Merge "Allow to search mandatory packages in all forest"
This commit is contained in:
commit
1508e35df2
@ -21,12 +21,14 @@ import logging
|
|||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from packetary import objects
|
||||||
|
from packetary import schemas
|
||||||
|
|
||||||
from packetary.api.context import Context
|
from packetary.api.context import Context
|
||||||
from packetary.api.options import RepositoryCopyOptions
|
from packetary.api.options import RepositoryCopyOptions
|
||||||
from packetary.controllers import RepositoryController
|
from packetary.controllers import RepositoryController
|
||||||
from packetary.library.functions import compose
|
from packetary.library.functions import compose
|
||||||
from packetary import objects
|
from packetary.objects.package_relation import PackageRelation
|
||||||
from packetary import schemas
|
|
||||||
|
|
||||||
from packetary.api.loaders import get_packages_traverse
|
from packetary.api.loaders import get_packages_traverse
|
||||||
from packetary.api.loaders import load_package_relations
|
from packetary.api.loaders import load_package_relations
|
||||||
@ -37,6 +39,12 @@ from packetary.api.validators import declare_schema
|
|||||||
logger = logging.getLogger(__package__)
|
logger = logging.getLogger(__package__)
|
||||||
|
|
||||||
|
|
||||||
|
_MANDATORY = {
|
||||||
|
"exact": "=",
|
||||||
|
"newest": ">=",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class RepositoryApi(object):
|
class RepositoryApi(object):
|
||||||
"""Provides high-level API to operate with repositories."""
|
"""Provides high-level API to operate with repositories."""
|
||||||
|
|
||||||
@ -149,16 +157,24 @@ class RepositoryApi(object):
|
|||||||
requirements.get('repositories'), package_relations.append
|
requirements.get('repositories'), package_relations.append
|
||||||
)
|
)
|
||||||
for repo in repositories:
|
for repo in repositories:
|
||||||
|
tree = forest.add_tree(repo.priority)
|
||||||
self.controller.load_packages(
|
self.controller.load_packages(
|
||||||
repo,
|
repo,
|
||||||
compose(
|
compose(
|
||||||
forest.add_tree(repo.priority).add,
|
tree.add,
|
||||||
packages_traverse
|
packages_traverse
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return forest.get_packages(
|
mandatory = requirements.get('mandatory')
|
||||||
package_relations, requirements.get('mandatory', True)
|
if mandatory:
|
||||||
)
|
for package in tree.mandatory_packages:
|
||||||
|
package_relations.append(
|
||||||
|
PackageRelation.from_args(
|
||||||
|
(package.name,
|
||||||
|
_MANDATORY[requirements['mandatory']],
|
||||||
|
package.version)))
|
||||||
|
|
||||||
|
return forest.get_packages(package_relations)
|
||||||
|
|
||||||
packages = set()
|
packages = set()
|
||||||
self._load_packages(repositories, packages.add)
|
self._load_packages(repositories, packages.add)
|
||||||
|
@ -44,12 +44,10 @@ class PackagesForest(object):
|
|||||||
tree = self.trees[priority] = PackagesTree()
|
tree = self.trees[priority] = PackagesTree()
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
def get_packages(self, requirements, include_mandatory=False):
|
def get_packages(self, requirements):
|
||||||
"""Get the packages according requirements.
|
"""Get the packages according requirements.
|
||||||
|
|
||||||
:param requirements: the list of requirements
|
:param requirements: the list of requirements
|
||||||
:param include_mandatory: if true, the mandatory packages will be
|
|
||||||
included to result
|
|
||||||
:return list of packages to copy
|
:return list of packages to copy
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -61,12 +59,6 @@ class PackagesForest(object):
|
|||||||
unresolved = set()
|
unresolved = set()
|
||||||
stack = [(None, requirements)]
|
stack = [(None, requirements)]
|
||||||
|
|
||||||
if include_mandatory:
|
|
||||||
for tree in six.itervalues(self.trees):
|
|
||||||
for mandatory in tree.mandatory_packages:
|
|
||||||
resolved.add(mandatory)
|
|
||||||
stack.append((mandatory, mandatory.requires))
|
|
||||||
|
|
||||||
while stack:
|
while stack:
|
||||||
pkg, requirements = stack.pop()
|
pkg, requirements = stack.pop()
|
||||||
for required in requirements:
|
for required in requirements:
|
||||||
|
@ -68,7 +68,7 @@ REQUIREMENTS_SCHEMA = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mandatory": {
|
"mandatory": {
|
||||||
"type": "boolean"
|
"enum": ["exact", "newest"]
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,12 @@ from packetary import objects
|
|||||||
|
|
||||||
|
|
||||||
def gen_repository(name="test", url="file:///test",
|
def gen_repository(name="test", url="file:///test",
|
||||||
architecture="x86_64", origin="Test", **kwargs):
|
architecture="x86_64", priority=99,
|
||||||
|
origin="Test", **kwargs):
|
||||||
"""Helper to create Repository object with default attributes."""
|
"""Helper to create Repository object with default attributes."""
|
||||||
url = kwargs.pop("uri", url)
|
url = kwargs.pop("uri", url)
|
||||||
return objects.Repository(name, url, architecture, origin, **kwargs)
|
return objects.Repository(name, url, architecture, priority, origin,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
def gen_relation(name="test", version=None, alternative=None):
|
def gen_relation(name="test", version=None, alternative=None):
|
||||||
|
@ -96,22 +96,11 @@ class TestPackagesForest(base.TestCase):
|
|||||||
p22, forest.find(generator.gen_relation("package2", [">=", 2]))
|
p22, forest.find(generator.gen_relation("package2", [">=", 2]))
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_packages_with_mandatory(self):
|
def test_get_packages(self):
|
||||||
forest = PackagesForest()
|
forest = PackagesForest()
|
||||||
self._generate_packages(forest)
|
self._generate_packages(forest)
|
||||||
packages = forest.get_packages(
|
packages = forest.get_packages(
|
||||||
[generator.gen_relation("package3")], True
|
[generator.gen_relation("package3")]
|
||||||
)
|
|
||||||
self.assertItemsEqual(
|
|
||||||
["package1", "package2", "package3", "package4", "package5"],
|
|
||||||
(x.name for x in packages)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_get_packages_without_mandatory(self):
|
|
||||||
forest = PackagesForest()
|
|
||||||
self._generate_packages(forest)
|
|
||||||
packages = forest.get_packages(
|
|
||||||
[generator.gen_relation("package3")], False
|
|
||||||
)
|
)
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
["package2", "package3", "package5"],
|
["package2", "package3", "package5"],
|
||||||
|
@ -79,8 +79,12 @@ class TestRepositoryApi(base.TestCase):
|
|||||||
name='{0}_5'.format(r.name), repository=r,
|
name='{0}_5'.format(r.name), repository=r,
|
||||||
requires=[generator.gen_relation("unresolved")]
|
requires=[generator.gen_relation("unresolved")]
|
||||||
),
|
),
|
||||||
|
generator.gen_package(
|
||||||
|
name='package10', repository=r, mandatory=True,
|
||||||
|
requires=None, version=counter + 10
|
||||||
|
)
|
||||||
]
|
]
|
||||||
for r in self.repos
|
for counter, r in enumerate(self.repos)
|
||||||
]
|
]
|
||||||
self.controller.load_packages.side_effect = self.packages
|
self.controller.load_packages.side_effect = self.packages
|
||||||
|
|
||||||
@ -139,7 +143,7 @@ class TestRepositoryApi(base.TestCase):
|
|||||||
self._generate_repositories(1)
|
self._generate_repositories(1)
|
||||||
self._generate_packages()
|
self._generate_packages()
|
||||||
packages = self.api.get_packages(self.repos_data)
|
packages = self.api.get_packages(self.repos_data)
|
||||||
self.assertEqual(5, len(self.packages[0]))
|
self.assertEqual(6, len(self.packages[0]))
|
||||||
self.assertItemsEqual(self.packages[0], packages)
|
self.assertItemsEqual(self.packages[0], packages)
|
||||||
jsonschema_mock.validate.assert_called_once_with(
|
jsonschema_mock.validate.assert_called_once_with(
|
||||||
self.repos_data, self.api._get_repositories_data_schema()
|
self.repos_data, self.api._get_repositories_data_schema()
|
||||||
@ -148,10 +152,30 @@ class TestRepositoryApi(base.TestCase):
|
|||||||
def test_get_packages_by_requirements(self, jsonschema_mock):
|
def test_get_packages_by_requirements(self, jsonschema_mock):
|
||||||
self._generate_repositories(2)
|
self._generate_repositories(2)
|
||||||
self._generate_packages()
|
self._generate_packages()
|
||||||
|
requirements = {
|
||||||
|
'packages': [{"name": "repo0_1"}],
|
||||||
|
'repositories': [{"name": "repo1"}]
|
||||||
|
}
|
||||||
|
packages = self.api.get_packages(self.repos_data, requirements)
|
||||||
|
expected_packages = [self.packages[0][0]] + self.packages[1]
|
||||||
|
self.assertItemsEqual(
|
||||||
|
[x.name for x in expected_packages],
|
||||||
|
[x.name for x in packages]
|
||||||
|
)
|
||||||
|
repos_schema = self.api._get_repositories_data_schema()
|
||||||
|
jsonschema_mock.validate.assert_has_calls([
|
||||||
|
mock.call(self.repos_data, repos_schema),
|
||||||
|
mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
|
||||||
|
], any_order=True)
|
||||||
|
|
||||||
|
def test_get_packages_by_requirements_newest_mandatory(self,
|
||||||
|
jsonschema_mock):
|
||||||
|
self._generate_repositories(2)
|
||||||
|
self._generate_packages()
|
||||||
requirements = {
|
requirements = {
|
||||||
'packages': [{"name": "repo0_1"}],
|
'packages': [{"name": "repo0_1"}],
|
||||||
'repositories': [{"name": "repo1"}],
|
'repositories': [{"name": "repo1"}],
|
||||||
'mandatory': True
|
'mandatory': "newest"
|
||||||
}
|
}
|
||||||
packages = self.api.get_packages(self.repos_data, requirements)
|
packages = self.api.get_packages(self.repos_data, requirements)
|
||||||
expected_packages = self.packages[0][:3] + self.packages[1]
|
expected_packages = self.packages[0][:3] + self.packages[1]
|
||||||
@ -165,6 +189,29 @@ class TestRepositoryApi(base.TestCase):
|
|||||||
mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
|
mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
|
||||||
], any_order=True)
|
], any_order=True)
|
||||||
|
|
||||||
|
def test_get_packages_by_requirements_exact_mandatory(self,
|
||||||
|
jsonschema_mock):
|
||||||
|
self._generate_repositories(2)
|
||||||
|
self._generate_packages()
|
||||||
|
requirements = {
|
||||||
|
'packages': [{"name": "repo0_1"}],
|
||||||
|
'repositories': [{"name": "repo1"}],
|
||||||
|
'mandatory': "exact"
|
||||||
|
}
|
||||||
|
packages = self.api.get_packages(self.repos_data, requirements)
|
||||||
|
expected_packages = self.packages[0][:3] + \
|
||||||
|
[self.packages[0][-1]] + \
|
||||||
|
self.packages[1]
|
||||||
|
self.assertItemsEqual(
|
||||||
|
[x.name for x in expected_packages],
|
||||||
|
[x.name for x in packages]
|
||||||
|
)
|
||||||
|
repos_schema = self.api._get_repositories_data_schema()
|
||||||
|
jsonschema_mock.validate.assert_has_calls([
|
||||||
|
mock.call(self.repos_data, repos_schema),
|
||||||
|
mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
|
||||||
|
], any_order=True)
|
||||||
|
|
||||||
def test_clone_repositories_as_is(self, jsonschema_mock):
|
def test_clone_repositories_as_is(self, jsonschema_mock):
|
||||||
self._generate_repositories(1)
|
self._generate_repositories(1)
|
||||||
self._generate_packages()
|
self._generate_packages()
|
||||||
@ -193,7 +240,6 @@ class TestRepositoryApi(base.TestCase):
|
|||||||
requirements = {
|
requirements = {
|
||||||
'packages': [{"name": "repo0_1"}],
|
'packages': [{"name": "repo0_1"}],
|
||||||
'repositories': [{"name": "repo1"}],
|
'repositories': [{"name": "repo1"}],
|
||||||
'mandatory': False
|
|
||||||
}
|
}
|
||||||
self.controller.assign_packages.return_value = [0, 1, 1] * 3
|
self.controller.assign_packages.return_value = [0, 1, 1] * 3
|
||||||
stats = self.api.clone_repositories(
|
stats = self.api.clone_repositories(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user