Merge "Allow to search mandatory packages in all forest"

This commit is contained in:
Jenkins 2016-07-05 21:23:39 +00:00 committed by Gerrit Code Review
commit 1508e35df2
6 changed files with 81 additions and 36 deletions

View File

@ -21,12 +21,14 @@ import logging
import six
from packetary import objects
from packetary import schemas
from packetary.api.context import Context
from packetary.api.options import RepositoryCopyOptions
from packetary.controllers import RepositoryController
from packetary.library.functions import compose
from packetary import objects
from packetary import schemas
from packetary.objects.package_relation import PackageRelation
from packetary.api.loaders import get_packages_traverse
from packetary.api.loaders import load_package_relations
@ -37,6 +39,12 @@ from packetary.api.validators import declare_schema
logger = logging.getLogger(__package__)
_MANDATORY = {
"exact": "=",
"newest": ">=",
}
class RepositoryApi(object):
"""Provides high-level API to operate with repositories."""
@ -149,16 +157,24 @@ class RepositoryApi(object):
requirements.get('repositories'), package_relations.append
)
for repo in repositories:
tree = forest.add_tree(repo.priority)
self.controller.load_packages(
repo,
compose(
forest.add_tree(repo.priority).add,
tree.add,
packages_traverse
)
)
return forest.get_packages(
package_relations, requirements.get('mandatory', True)
)
mandatory = requirements.get('mandatory')
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()
self._load_packages(repositories, packages.add)

View File

@ -44,12 +44,10 @@ class PackagesForest(object):
tree = self.trees[priority] = PackagesTree()
return tree
def get_packages(self, requirements, include_mandatory=False):
def get_packages(self, requirements):
"""Get the packages according 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
"""
@ -61,12 +59,6 @@ class PackagesForest(object):
unresolved = set()
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:
pkg, requirements = stack.pop()
for required in requirements:

View File

@ -68,7 +68,7 @@ REQUIREMENTS_SCHEMA = {
}
},
"mandatory": {
"type": "boolean"
},
"enum": ["exact", "newest"]
}
}
}

View File

@ -20,10 +20,12 @@ from packetary import objects
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."""
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):

View File

@ -96,22 +96,11 @@ class TestPackagesForest(base.TestCase):
p22, forest.find(generator.gen_relation("package2", [">=", 2]))
)
def test_get_packages_with_mandatory(self):
def test_get_packages(self):
forest = PackagesForest()
self._generate_packages(forest)
packages = forest.get_packages(
[generator.gen_relation("package3")], True
)
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
[generator.gen_relation("package3")]
)
self.assertItemsEqual(
["package2", "package3", "package5"],

View File

@ -79,8 +79,12 @@ class TestRepositoryApi(base.TestCase):
name='{0}_5'.format(r.name), repository=r,
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
@ -139,7 +143,7 @@ class TestRepositoryApi(base.TestCase):
self._generate_repositories(1)
self._generate_packages()
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)
jsonschema_mock.validate.assert_called_once_with(
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):
self._generate_repositories(2)
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 = {
'packages': [{"name": "repo0_1"}],
'repositories': [{"name": "repo1"}],
'mandatory': True
'mandatory': "newest"
}
packages = self.api.get_packages(self.repos_data, requirements)
expected_packages = self.packages[0][:3] + self.packages[1]
@ -165,6 +189,29 @@ class TestRepositoryApi(base.TestCase):
mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
], 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):
self._generate_repositories(1)
self._generate_packages()
@ -193,7 +240,6 @@ class TestRepositoryApi(base.TestCase):
requirements = {
'packages': [{"name": "repo0_1"}],
'repositories': [{"name": "repo1"}],
'mandatory': False
}
self.controller.assign_packages.return_value = [0, 1, 1] * 3
stats = self.api.clone_repositories(