Browse Source

Merge "Allow to search mandatory packages in all forest"

Jenkins 2 years ago
parent
commit
1508e35df2

+ 22
- 6
packetary/api/repositories.py View File

@@ -21,12 +21,14 @@ import logging
21 21
 
22 22
 import six
23 23
 
24
+from packetary import objects
25
+from packetary import schemas
26
+
24 27
 from packetary.api.context import Context
25 28
 from packetary.api.options import RepositoryCopyOptions
26 29
 from packetary.controllers import RepositoryController
27 30
 from packetary.library.functions import compose
28
-from packetary import objects
29
-from packetary import schemas
31
+from packetary.objects.package_relation import PackageRelation
30 32
 
31 33
 from packetary.api.loaders import get_packages_traverse
32 34
 from packetary.api.loaders import load_package_relations
@@ -37,6 +39,12 @@ from packetary.api.validators import declare_schema
37 39
 logger = logging.getLogger(__package__)
38 40
 
39 41
 
42
+_MANDATORY = {
43
+    "exact": "=",
44
+    "newest": ">=",
45
+}
46
+
47
+
40 48
 class RepositoryApi(object):
41 49
     """Provides high-level API to operate with repositories."""
42 50
 
@@ -149,16 +157,24 @@ class RepositoryApi(object):
149 157
                 requirements.get('repositories'), package_relations.append
150 158
             )
151 159
             for repo in repositories:
160
+                tree = forest.add_tree(repo.priority)
152 161
                 self.controller.load_packages(
153 162
                     repo,
154 163
                     compose(
155
-                        forest.add_tree(repo.priority).add,
164
+                        tree.add,
156 165
                         packages_traverse
157 166
                     )
158 167
                 )
159
-            return forest.get_packages(
160
-                package_relations, requirements.get('mandatory', True)
161
-            )
168
+                mandatory = requirements.get('mandatory')
169
+                if mandatory:
170
+                    for package in tree.mandatory_packages:
171
+                        package_relations.append(
172
+                            PackageRelation.from_args(
173
+                                (package.name,
174
+                                 _MANDATORY[requirements['mandatory']],
175
+                                 package.version)))
176
+
177
+            return forest.get_packages(package_relations)
162 178
 
163 179
         packages = set()
164 180
         self._load_packages(repositories, packages.add)

+ 1
- 9
packetary/objects/packages_forest.py View File

@@ -44,12 +44,10 @@ class PackagesForest(object):
44 44
             tree = self.trees[priority] = PackagesTree()
45 45
             return tree
46 46
 
47
-    def get_packages(self, requirements, include_mandatory=False):
47
+    def get_packages(self, requirements):
48 48
         """Get the packages according requirements.
49 49
 
50 50
         :param requirements: the list of requirements
51
-        :param include_mandatory: if true, the mandatory packages will be
52
-                                  included to result
53 51
         :return list of packages to copy
54 52
         """
55 53
 
@@ -61,12 +59,6 @@ class PackagesForest(object):
61 59
         unresolved = set()
62 60
         stack = [(None, requirements)]
63 61
 
64
-        if include_mandatory:
65
-            for tree in six.itervalues(self.trees):
66
-                for mandatory in tree.mandatory_packages:
67
-                    resolved.add(mandatory)
68
-                    stack.append((mandatory, mandatory.requires))
69
-
70 62
         while stack:
71 63
             pkg, requirements = stack.pop()
72 64
             for required in requirements:

+ 2
- 2
packetary/schemas/requirements_schema.py View File

@@ -68,7 +68,7 @@ REQUIREMENTS_SCHEMA = {
68 68
             }
69 69
         },
70 70
         "mandatory": {
71
-            "type": "boolean"
72
-        },
71
+            "enum": ["exact", "newest"]
72
+        }
73 73
     }
74 74
 }

+ 4
- 2
packetary/tests/stubs/generator.py View File

@@ -20,10 +20,12 @@ from packetary import objects
20 20
 
21 21
 
22 22
 def gen_repository(name="test", url="file:///test",
23
-                   architecture="x86_64", origin="Test", **kwargs):
23
+                   architecture="x86_64", priority=99,
24
+                   origin="Test", **kwargs):
24 25
     """Helper to create Repository object with default attributes."""
25 26
     url = kwargs.pop("uri", url)
26
-    return objects.Repository(name, url, architecture, origin, **kwargs)
27
+    return objects.Repository(name, url, architecture, priority, origin,
28
+                              **kwargs)
27 29
 
28 30
 
29 31
 def gen_relation(name="test", version=None, alternative=None):

+ 2
- 13
packetary/tests/test_packages_forest.py View File

@@ -96,22 +96,11 @@ class TestPackagesForest(base.TestCase):
96 96
             p22, forest.find(generator.gen_relation("package2", [">=", 2]))
97 97
         )
98 98
 
99
-    def test_get_packages_with_mandatory(self):
99
+    def test_get_packages(self):
100 100
         forest = PackagesForest()
101 101
         self._generate_packages(forest)
102 102
         packages = forest.get_packages(
103
-            [generator.gen_relation("package3")], True
104
-        )
105
-        self.assertItemsEqual(
106
-            ["package1", "package2", "package3", "package4", "package5"],
107
-            (x.name for x in packages)
108
-        )
109
-
110
-    def test_get_packages_without_mandatory(self):
111
-        forest = PackagesForest()
112
-        self._generate_packages(forest)
113
-        packages = forest.get_packages(
114
-            [generator.gen_relation("package3")], False
103
+            [generator.gen_relation("package3")]
115 104
         )
116 105
         self.assertItemsEqual(
117 106
             ["package2", "package3", "package5"],

+ 50
- 4
packetary/tests/test_repository_api.py View File

@@ -79,8 +79,12 @@ class TestRepositoryApi(base.TestCase):
79 79
                     name='{0}_5'.format(r.name), repository=r,
80 80
                     requires=[generator.gen_relation("unresolved")]
81 81
                 ),
82
+                generator.gen_package(
83
+                    name='package10', repository=r, mandatory=True,
84
+                    requires=None, version=counter + 10
85
+                )
82 86
             ]
83
-            for r in self.repos
87
+            for counter, r in enumerate(self.repos)
84 88
         ]
85 89
         self.controller.load_packages.side_effect = self.packages
86 90
 
@@ -139,7 +143,7 @@ class TestRepositoryApi(base.TestCase):
139 143
         self._generate_repositories(1)
140 144
         self._generate_packages()
141 145
         packages = self.api.get_packages(self.repos_data)
142
-        self.assertEqual(5, len(self.packages[0]))
146
+        self.assertEqual(6, len(self.packages[0]))
143 147
         self.assertItemsEqual(self.packages[0], packages)
144 148
         jsonschema_mock.validate.assert_called_once_with(
145 149
             self.repos_data, self.api._get_repositories_data_schema()
@@ -148,10 +152,30 @@ class TestRepositoryApi(base.TestCase):
148 152
     def test_get_packages_by_requirements(self, jsonschema_mock):
149 153
         self._generate_repositories(2)
150 154
         self._generate_packages()
155
+        requirements = {
156
+            'packages': [{"name": "repo0_1"}],
157
+            'repositories': [{"name": "repo1"}]
158
+        }
159
+        packages = self.api.get_packages(self.repos_data, requirements)
160
+        expected_packages = [self.packages[0][0]] + self.packages[1]
161
+        self.assertItemsEqual(
162
+            [x.name for x in expected_packages],
163
+            [x.name for x in packages]
164
+        )
165
+        repos_schema = self.api._get_repositories_data_schema()
166
+        jsonschema_mock.validate.assert_has_calls([
167
+            mock.call(self.repos_data, repos_schema),
168
+            mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
169
+        ], any_order=True)
170
+
171
+    def test_get_packages_by_requirements_newest_mandatory(self,
172
+                                                           jsonschema_mock):
173
+        self._generate_repositories(2)
174
+        self._generate_packages()
151 175
         requirements = {
152 176
             'packages': [{"name": "repo0_1"}],
153 177
             'repositories': [{"name": "repo1"}],
154
-            'mandatory': True
178
+            'mandatory': "newest"
155 179
         }
156 180
         packages = self.api.get_packages(self.repos_data, requirements)
157 181
         expected_packages = self.packages[0][:3] + self.packages[1]
@@ -165,6 +189,29 @@ class TestRepositoryApi(base.TestCase):
165 189
             mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
166 190
         ], any_order=True)
167 191
 
192
+    def test_get_packages_by_requirements_exact_mandatory(self,
193
+                                                          jsonschema_mock):
194
+        self._generate_repositories(2)
195
+        self._generate_packages()
196
+        requirements = {
197
+            'packages': [{"name": "repo0_1"}],
198
+            'repositories': [{"name": "repo1"}],
199
+            'mandatory': "exact"
200
+        }
201
+        packages = self.api.get_packages(self.repos_data, requirements)
202
+        expected_packages = self.packages[0][:3] + \
203
+            [self.packages[0][-1]] + \
204
+            self.packages[1]
205
+        self.assertItemsEqual(
206
+            [x.name for x in expected_packages],
207
+            [x.name for x in packages]
208
+        )
209
+        repos_schema = self.api._get_repositories_data_schema()
210
+        jsonschema_mock.validate.assert_has_calls([
211
+            mock.call(self.repos_data, repos_schema),
212
+            mock.call(requirements, schemas.REQUIREMENTS_SCHEMA)
213
+        ], any_order=True)
214
+
168 215
     def test_clone_repositories_as_is(self, jsonschema_mock):
169 216
         self._generate_repositories(1)
170 217
         self._generate_packages()
@@ -193,7 +240,6 @@ class TestRepositoryApi(base.TestCase):
193 240
         requirements = {
194 241
             'packages': [{"name": "repo0_1"}],
195 242
             'repositories': [{"name": "repo1"}],
196
-            'mandatory': False
197 243
         }
198 244
         self.controller.assign_packages.return_value = [0, 1, 1] * 3
199 245
         stats = self.api.clone_repositories(

Loading…
Cancel
Save