1 |
Support "profile-formats = build-id" setting for layout.conf. When |
2 |
this is enabled in layout.conf of the containing repository, a |
3 |
dependency atom in the profile can refer to a specific build, using the |
4 |
build-id that is assigned when FEATURES=binpkg-multi-instance is |
5 |
enabled. A build-id atom is identical to a version-specific atom, |
6 |
except that the version is followed by a hyphen and an integer build-id. |
7 |
|
8 |
With the build-id profile format, it is possible to assemble a system |
9 |
using specific builds of binary packages, as users of "binary" |
10 |
distros might be accustomed to. For example, an atom in the "packages" |
11 |
file can pull a specific build of a package into the @system set, and |
12 |
an atom in the "package.keywords" file can be used to modify the |
13 |
effective KEYWORDS of a specific build of a package. |
14 |
|
15 |
Refering to specific builds can be useful for a number of reasons. For |
16 |
example, if a particular build needs to undergo a large amount of |
17 |
testing in a complex environment in order to verify reliability, then |
18 |
it can be useful to lock a profile to a specific build that has been |
19 |
thoroughly tested. |
20 |
--- |
21 |
This patch is identical to "[PATCH 2/2] Add profile-formats=build-id |
22 |
(bug 150031)" which was sent to the list earlier, except that it adds |
23 |
a comment about "smart" defaults in the Atom class. |
24 |
|
25 |
man/portage.5 | 8 +- |
26 |
pym/_emerge/is_valid_package_atom.py | 5 +- |
27 |
pym/portage/_sets/ProfilePackageSet.py | 3 +- |
28 |
pym/portage/_sets/profiles.py | 3 +- |
29 |
pym/portage/dep/__init__.py | 38 +++++- |
30 |
.../package/ebuild/_config/KeywordsManager.py | 3 +- |
31 |
.../package/ebuild/_config/LocationsManager.py | 8 +- |
32 |
pym/portage/package/ebuild/_config/MaskManager.py | 21 +++- |
33 |
pym/portage/package/ebuild/_config/UseManager.py | 14 ++- |
34 |
pym/portage/package/ebuild/config.py | 15 ++- |
35 |
pym/portage/repository/config.py | 2 +- |
36 |
pym/portage/tests/dep/test_isvalidatom.py | 8 +- |
37 |
.../test_build_id_profile_format.py | 134 +++++++++++++++++++++ |
38 |
pym/portage/util/__init__.py | 13 +- |
39 |
14 files changed, 237 insertions(+), 38 deletions(-) |
40 |
create mode 100644 pym/portage/tests/resolver/binpkg_multi_instance/test_build_id_profile_format.py |
41 |
|
42 |
diff --git a/man/portage.5 b/man/portage.5 |
43 |
index ed5140d..e062f9f 100644 |
44 |
--- a/man/portage.5 |
45 |
+++ b/man/portage.5 |
46 |
@@ -1180,7 +1180,7 @@ and the newer/faster "md5-dict" format. Default is to detect dirs. |
47 |
The EAPI to use for profiles when unspecified. This attribute is |
48 |
supported only if profile-default-eapi is included in profile-formats. |
49 |
.TP |
50 |
-.BR profile\-formats " = [pms] [portage-1] [portage-2] [profile-bashrcs] [profile-set] [profile-default-eapi]" |
51 |
+.BR profile\-formats " = [pms] [portage-1] [portage-2] [profile-bashrcs] [profile-set] [profile-default-eapi] [build-id]" |
52 |
Control functionality available to profiles in this repo such as which files |
53 |
may be dirs, or the syntax available in parent files. Use "portage-2" if you're |
54 |
unsure. The default is "portage-1-compat" mode which is meant to be compatible |
55 |
@@ -1190,7 +1190,11 @@ Setting profile-bashrcs will enable the per-profile bashrc mechanism |
56 |
profile \fBpackages\fR file to add atoms to the @profile package set. |
57 |
See the profile \fBpackages\fR section for more information. |
58 |
Setting profile-default-eapi enables support for the |
59 |
-profile_eapi_when_unspecified attribute. |
60 |
+profile_eapi_when_unspecified attribute. Setting build\-id allows |
61 |
+dependency atoms in the profile to refer to specific builds (see the |
62 |
+binpkg\-multi\-instance FEATURES setting in \fBmake.conf\fR(5)). A |
63 |
+build\-id atom is identical to a version-specific atom, except that the |
64 |
+version is followed by a hyphen and an integer build\-id. |
65 |
.RE |
66 |
.RE |
67 |
|
68 |
diff --git a/pym/_emerge/is_valid_package_atom.py b/pym/_emerge/is_valid_package_atom.py |
69 |
index 112afc1..17f7642 100644 |
70 |
--- a/pym/_emerge/is_valid_package_atom.py |
71 |
+++ b/pym/_emerge/is_valid_package_atom.py |
72 |
@@ -14,9 +14,10 @@ def insert_category_into_atom(atom, category): |
73 |
ret = None |
74 |
return ret |
75 |
|
76 |
-def is_valid_package_atom(x, allow_repo=False): |
77 |
+def is_valid_package_atom(x, allow_repo=False, allow_build_id=True): |
78 |
if "/" not in x.split(":")[0]: |
79 |
x2 = insert_category_into_atom(x, 'cat') |
80 |
if x2 != None: |
81 |
x = x2 |
82 |
- return isvalidatom(x, allow_blockers=False, allow_repo=allow_repo) |
83 |
+ return isvalidatom(x, allow_blockers=False, allow_repo=allow_repo, |
84 |
+ allow_build_id=allow_build_id) |
85 |
diff --git a/pym/portage/_sets/ProfilePackageSet.py b/pym/portage/_sets/ProfilePackageSet.py |
86 |
index 2fcafb6..fec9373 100644 |
87 |
--- a/pym/portage/_sets/ProfilePackageSet.py |
88 |
+++ b/pym/portage/_sets/ProfilePackageSet.py |
89 |
@@ -23,7 +23,8 @@ class ProfilePackageSet(PackageSet): |
90 |
def load(self): |
91 |
self._setAtoms(x for x in stack_lists( |
92 |
[grabfile_package(os.path.join(y.location, "packages"), |
93 |
- verify_eapi=True, eapi=y.eapi, eapi_default=None) |
94 |
+ verify_eapi=True, eapi=y.eapi, eapi_default=None, |
95 |
+ allow_build_id=y.allow_build_id) |
96 |
for y in self._profiles |
97 |
if "profile-set" in y.profile_formats], |
98 |
incremental=1) if x[:1] != "*") |
99 |
diff --git a/pym/portage/_sets/profiles.py b/pym/portage/_sets/profiles.py |
100 |
index ccb3432..bccc02e 100644 |
101 |
--- a/pym/portage/_sets/profiles.py |
102 |
+++ b/pym/portage/_sets/profiles.py |
103 |
@@ -34,7 +34,8 @@ class PackagesSystemSet(PackageSet): |
104 |
(self._profiles,), level=logging.DEBUG, noiselevel=-1) |
105 |
|
106 |
mylist = [grabfile_package(os.path.join(x.location, "packages"), |
107 |
- verify_eapi=True, eapi=x.eapi, eapi_default=None) |
108 |
+ verify_eapi=True, eapi=x.eapi, eapi_default=None, |
109 |
+ allow_build_id=x.allow_build_id) |
110 |
for x in self._profiles] |
111 |
|
112 |
if debug: |
113 |
diff --git a/pym/portage/dep/__init__.py b/pym/portage/dep/__init__.py |
114 |
index e2e416c..1f2c8cd 100644 |
115 |
--- a/pym/portage/dep/__init__.py |
116 |
+++ b/pym/portage/dep/__init__.py |
117 |
@@ -1191,11 +1191,11 @@ class Atom(_unicode): |
118 |
self.overlap = self._overlap(forbid=forbid_overlap) |
119 |
|
120 |
def __new__(cls, s, unevaluated_atom=None, allow_wildcard=False, allow_repo=None, |
121 |
- _use=None, eapi=None, is_valid_flag=None): |
122 |
+ _use=None, eapi=None, is_valid_flag=None, allow_build_id=None): |
123 |
return _unicode.__new__(cls, s) |
124 |
|
125 |
def __init__(self, s, unevaluated_atom=None, allow_wildcard=False, allow_repo=None, |
126 |
- _use=None, eapi=None, is_valid_flag=None): |
127 |
+ _use=None, eapi=None, is_valid_flag=None, allow_build_id=None): |
128 |
if isinstance(s, Atom): |
129 |
# This is an efficiency assertion, to ensure that the Atom |
130 |
# constructor is not called redundantly. |
131 |
@@ -1216,8 +1216,13 @@ class Atom(_unicode): |
132 |
# Ignore allow_repo when eapi is specified. |
133 |
allow_repo = eapi_attrs.repo_deps |
134 |
else: |
135 |
+ # These parameters have "smart" defaults that are only |
136 |
+ # applied when the caller does not explicitly pass in a |
137 |
+ # True or False value. |
138 |
if allow_repo is None: |
139 |
allow_repo = True |
140 |
+ if allow_build_id is None: |
141 |
+ allow_build_id = True |
142 |
|
143 |
blocker_prefix = "" |
144 |
if "!" == s[:1]: |
145 |
@@ -1232,6 +1237,7 @@ class Atom(_unicode): |
146 |
blocker = False |
147 |
self.__dict__['blocker'] = blocker |
148 |
m = atom_re.match(s) |
149 |
+ build_id = None |
150 |
extended_syntax = False |
151 |
extended_version = None |
152 |
if m is None: |
153 |
@@ -1268,8 +1274,22 @@ class Atom(_unicode): |
154 |
slot = m.group(atom_re.groups - 2) |
155 |
repo = m.group(atom_re.groups - 1) |
156 |
use_str = m.group(atom_re.groups) |
157 |
- if m.group(base + 4) is not None: |
158 |
- raise InvalidAtom(self) |
159 |
+ version = m.group(base + 4) |
160 |
+ if version is not None: |
161 |
+ if allow_build_id: |
162 |
+ cpv_build_id = cpv |
163 |
+ cpv = cp |
164 |
+ cp = cp[:-len(version)] |
165 |
+ build_id = cpv_build_id[len(cpv)+1:] |
166 |
+ if len(build_id) > 1 and build_id[:1] == "0": |
167 |
+ # Leading zeros are not allowed. |
168 |
+ raise InvalidAtom(self) |
169 |
+ try: |
170 |
+ build_id = int(build_id) |
171 |
+ except ValueError: |
172 |
+ raise InvalidAtom(self) |
173 |
+ else: |
174 |
+ raise InvalidAtom(self) |
175 |
elif m.group('star') is not None: |
176 |
base = atom_re.groupindex['star'] |
177 |
op = '=*' |
178 |
@@ -1332,6 +1352,7 @@ class Atom(_unicode): |
179 |
self.__dict__['slot_operator'] = None |
180 |
self.__dict__['operator'] = op |
181 |
self.__dict__['extended_syntax'] = extended_syntax |
182 |
+ self.__dict__['build_id'] = build_id |
183 |
|
184 |
if not (repo is None or allow_repo): |
185 |
raise InvalidAtom(self) |
186 |
@@ -1877,7 +1898,7 @@ def dep_getusedeps( depend ): |
187 |
return tuple(use_list) |
188 |
|
189 |
def isvalidatom(atom, allow_blockers=False, allow_wildcard=False, |
190 |
- allow_repo=False, eapi=None): |
191 |
+ allow_repo=False, eapi=None, allow_build_id=False): |
192 |
""" |
193 |
Check to see if a depend atom is valid |
194 |
|
195 |
@@ -1902,7 +1923,8 @@ def isvalidatom(atom, allow_blockers=False, allow_wildcard=False, |
196 |
try: |
197 |
if not isinstance(atom, Atom): |
198 |
atom = Atom(atom, allow_wildcard=allow_wildcard, |
199 |
- allow_repo=allow_repo, eapi=eapi) |
200 |
+ allow_repo=allow_repo, eapi=eapi, |
201 |
+ allow_build_id=allow_build_id) |
202 |
if not allow_blockers and atom.blocker: |
203 |
return False |
204 |
return True |
205 |
@@ -2107,6 +2129,7 @@ def match_from_list(mydep, candidate_list): |
206 |
mycpv = mydep.cpv |
207 |
mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific |
208 |
slot = mydep.slot |
209 |
+ build_id = mydep.build_id |
210 |
|
211 |
if not mycpv_cps: |
212 |
cat, pkg = catsplit(mycpv) |
213 |
@@ -2181,6 +2204,9 @@ def match_from_list(mydep, candidate_list): |
214 |
xcpv = remove_slot(x) |
215 |
if not cpvequal(xcpv, mycpv): |
216 |
continue |
217 |
+ if (build_id is not None and |
218 |
+ getattr(xcpv, "build_id", None) != build_id): |
219 |
+ continue |
220 |
mylist.append(x) |
221 |
|
222 |
elif operator == "=*": # glob match |
223 |
diff --git a/pym/portage/package/ebuild/_config/KeywordsManager.py b/pym/portage/package/ebuild/_config/KeywordsManager.py |
224 |
index e1a8e2b..72e24b9 100644 |
225 |
--- a/pym/portage/package/ebuild/_config/KeywordsManager.py |
226 |
+++ b/pym/portage/package/ebuild/_config/KeywordsManager.py |
227 |
@@ -22,7 +22,8 @@ class KeywordsManager(object): |
228 |
rawpkeywords = [grabdict_package( |
229 |
os.path.join(x.location, "package.keywords"), |
230 |
recursive=x.portage1_directories, |
231 |
- verify_eapi=True, eapi=x.eapi, eapi_default=None) |
232 |
+ verify_eapi=True, eapi=x.eapi, eapi_default=None, |
233 |
+ allow_build_id=x.allow_build_id) |
234 |
for x in profiles] |
235 |
for pkeyworddict in rawpkeywords: |
236 |
if not pkeyworddict: |
237 |
diff --git a/pym/portage/package/ebuild/_config/LocationsManager.py b/pym/portage/package/ebuild/_config/LocationsManager.py |
238 |
index 34b33e9..55b8c08 100644 |
239 |
--- a/pym/portage/package/ebuild/_config/LocationsManager.py |
240 |
+++ b/pym/portage/package/ebuild/_config/LocationsManager.py |
241 |
@@ -31,7 +31,8 @@ _PORTAGE1_DIRECTORIES = frozenset([ |
242 |
'use.mask', 'use.force']) |
243 |
|
244 |
_profile_node = collections.namedtuple('_profile_node', |
245 |
- 'location portage1_directories user_config profile_formats eapi') |
246 |
+ ('location', 'portage1_directories', 'user_config', |
247 |
+ 'profile_formats', 'eapi', 'allow_build_id')) |
248 |
|
249 |
_allow_parent_colon = frozenset( |
250 |
["portage-2"]) |
251 |
@@ -142,7 +143,8 @@ class LocationsManager(object): |
252 |
_profile_node(custom_prof, True, True, |
253 |
('profile-bashrcs', 'profile-set'), |
254 |
read_corresponding_eapi_file( |
255 |
- custom_prof + os.sep, default=None))) |
256 |
+ custom_prof + os.sep, default=None), |
257 |
+ True)) |
258 |
del custom_prof |
259 |
|
260 |
self.profiles = tuple(self.profiles) |
261 |
@@ -253,7 +255,7 @@ class LocationsManager(object): |
262 |
self.profiles.append(currentPath) |
263 |
self.profiles_complex.append( |
264 |
_profile_node(currentPath, allow_directories, False, |
265 |
- current_formats, eapi)) |
266 |
+ current_formats, eapi, 'build-id' in current_formats)) |
267 |
|
268 |
def _expand_parent_colon(self, parentsFile, parentPath, |
269 |
repo_loc, repositories): |
270 |
diff --git a/pym/portage/package/ebuild/_config/MaskManager.py b/pym/portage/package/ebuild/_config/MaskManager.py |
271 |
index 55c8c7a..44aba23 100644 |
272 |
--- a/pym/portage/package/ebuild/_config/MaskManager.py |
273 |
+++ b/pym/portage/package/ebuild/_config/MaskManager.py |
274 |
@@ -40,7 +40,9 @@ class MaskManager(object): |
275 |
pmask_cache[loc] = grabfile_package(path, |
276 |
recursive=repo_config.portage1_profiles, |
277 |
remember_source_file=True, verify_eapi=True, |
278 |
- eapi_default=repo_config.eapi) |
279 |
+ eapi_default=repo_config.eapi, |
280 |
+ allow_build_id=("build-id" |
281 |
+ in repo_config.profile_formats)) |
282 |
if repo_config.portage1_profiles_compat and os.path.isdir(path): |
283 |
warnings.warn(_("Repository '%(repo_name)s' is implicitly using " |
284 |
"'portage-1' profile format in its profiles/package.mask, but " |
285 |
@@ -107,7 +109,8 @@ class MaskManager(object): |
286 |
continue |
287 |
repo_lines = grabfile_package(os.path.join(repo.location, "profiles", "package.unmask"), \ |
288 |
recursive=1, remember_source_file=True, |
289 |
- verify_eapi=True, eapi_default=repo.eapi) |
290 |
+ verify_eapi=True, eapi_default=repo.eapi, |
291 |
+ allow_build_id=("build-id" in repo.profile_formats)) |
292 |
lines = stack_lists([repo_lines], incremental=1, \ |
293 |
remember_source_file=True, warn_for_unmatched_removal=True, |
294 |
strict_warn_for_unmatched_removal=strict_umatched_removal) |
295 |
@@ -122,13 +125,15 @@ class MaskManager(object): |
296 |
os.path.join(x.location, "package.mask"), |
297 |
recursive=x.portage1_directories, |
298 |
remember_source_file=True, verify_eapi=True, |
299 |
- eapi=x.eapi, eapi_default=None)) |
300 |
+ eapi=x.eapi, eapi_default=None, |
301 |
+ allow_build_id=x.allow_build_id)) |
302 |
if x.portage1_directories: |
303 |
profile_pkgunmasklines.append(grabfile_package( |
304 |
os.path.join(x.location, "package.unmask"), |
305 |
recursive=x.portage1_directories, |
306 |
remember_source_file=True, verify_eapi=True, |
307 |
- eapi=x.eapi, eapi_default=None)) |
308 |
+ eapi=x.eapi, eapi_default=None, |
309 |
+ allow_build_id=x.allow_build_id)) |
310 |
profile_pkgmasklines = stack_lists(profile_pkgmasklines, incremental=1, \ |
311 |
remember_source_file=True, warn_for_unmatched_removal=True, |
312 |
strict_warn_for_unmatched_removal=strict_umatched_removal) |
313 |
@@ -143,10 +148,14 @@ class MaskManager(object): |
314 |
if user_config: |
315 |
user_pkgmasklines = grabfile_package( |
316 |
os.path.join(abs_user_config, "package.mask"), recursive=1, \ |
317 |
- allow_wildcard=True, allow_repo=True, remember_source_file=True, verify_eapi=False) |
318 |
+ allow_wildcard=True, allow_repo=True, |
319 |
+ remember_source_file=True, verify_eapi=False, |
320 |
+ allow_build_id=True) |
321 |
user_pkgunmasklines = grabfile_package( |
322 |
os.path.join(abs_user_config, "package.unmask"), recursive=1, \ |
323 |
- allow_wildcard=True, allow_repo=True, remember_source_file=True, verify_eapi=False) |
324 |
+ allow_wildcard=True, allow_repo=True, |
325 |
+ remember_source_file=True, verify_eapi=False, |
326 |
+ allow_build_id=True) |
327 |
|
328 |
#Stack everything together. At this point, only user_pkgmasklines may contain -atoms. |
329 |
#Don't warn for unmatched -atoms here, since we don't do it for any other user config file. |
330 |
diff --git a/pym/portage/package/ebuild/_config/UseManager.py b/pym/portage/package/ebuild/_config/UseManager.py |
331 |
index 60d5f92..a93ea5c 100644 |
332 |
--- a/pym/portage/package/ebuild/_config/UseManager.py |
333 |
+++ b/pym/portage/package/ebuild/_config/UseManager.py |
334 |
@@ -153,7 +153,8 @@ class UseManager(object): |
335 |
return tuple(ret) |
336 |
|
337 |
def _parse_file_to_dict(self, file_name, juststrings=False, recursive=True, |
338 |
- eapi_filter=None, user_config=False, eapi=None, eapi_default="0"): |
339 |
+ eapi_filter=None, user_config=False, eapi=None, eapi_default="0", |
340 |
+ allow_build_id=False): |
341 |
""" |
342 |
@param file_name: input file name |
343 |
@type file_name: str |
344 |
@@ -176,6 +177,9 @@ class UseManager(object): |
345 |
@param eapi_default: the default EAPI which applies if the |
346 |
current profile node does not define a local EAPI |
347 |
@type eapi_default: str |
348 |
+ @param allow_build_id: allow atoms to specify a particular |
349 |
+ build-id |
350 |
+ @type allow_build_id: bool |
351 |
@rtype: tuple |
352 |
@return: collection of USE flags |
353 |
""" |
354 |
@@ -192,7 +196,7 @@ class UseManager(object): |
355 |
file_dict = grabdict_package(file_name, recursive=recursive, |
356 |
allow_wildcard=extended_syntax, allow_repo=extended_syntax, |
357 |
verify_eapi=(not extended_syntax), eapi=eapi, |
358 |
- eapi_default=eapi_default) |
359 |
+ eapi_default=eapi_default, allow_build_id=allow_build_id) |
360 |
if eapi is not None and eapi_filter is not None and not eapi_filter(eapi): |
361 |
if file_dict: |
362 |
writemsg(_("--- EAPI '%s' does not support '%s': '%s'\n") % |
363 |
@@ -262,7 +266,8 @@ class UseManager(object): |
364 |
for repo in repositories.repos_with_profiles(): |
365 |
ret[repo.name] = self._parse_file_to_dict( |
366 |
os.path.join(repo.location, "profiles", file_name), |
367 |
- eapi_filter=eapi_filter, eapi_default=repo.eapi) |
368 |
+ eapi_filter=eapi_filter, eapi_default=repo.eapi, |
369 |
+ allow_build_id=("build-id" in repo.profile_formats)) |
370 |
return ret |
371 |
|
372 |
def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations, |
373 |
@@ -279,7 +284,8 @@ class UseManager(object): |
374 |
os.path.join(profile.location, file_name), juststrings, |
375 |
recursive=profile.portage1_directories, eapi_filter=eapi_filter, |
376 |
user_config=profile.user_config, eapi=profile.eapi, |
377 |
- eapi_default=None) for profile in locations) |
378 |
+ eapi_default=None, allow_build_id=profile.allow_build_id) |
379 |
+ for profile in locations) |
380 |
|
381 |
def _parse_repository_usealiases(self, repositories): |
382 |
ret = {} |
383 |
diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py |
384 |
index 71fe4df..f16d16e 100644 |
385 |
--- a/pym/portage/package/ebuild/config.py |
386 |
+++ b/pym/portage/package/ebuild/config.py |
387 |
@@ -569,7 +569,8 @@ class config(object): |
388 |
try: |
389 |
packages_list = [grabfile_package( |
390 |
os.path.join(x.location, "packages"), |
391 |
- verify_eapi=True, eapi=x.eapi, eapi_default=None) |
392 |
+ verify_eapi=True, eapi=x.eapi, eapi_default=None, |
393 |
+ allow_build_id=x.allow_build_id) |
394 |
for x in profiles_complex] |
395 |
except IOError as e: |
396 |
if e.errno == IsADirectory.errno: |
397 |
@@ -707,7 +708,8 @@ class config(object): |
398 |
#package.properties |
399 |
propdict = grabdict_package(os.path.join( |
400 |
abs_user_config, "package.properties"), recursive=1, allow_wildcard=True, \ |
401 |
- allow_repo=True, verify_eapi=False) |
402 |
+ allow_repo=True, verify_eapi=False, |
403 |
+ allow_build_id=True) |
404 |
v = propdict.pop("*/*", None) |
405 |
if v is not None: |
406 |
if "ACCEPT_PROPERTIES" in self.configdict["conf"]: |
407 |
@@ -721,7 +723,8 @@ class config(object): |
408 |
d = grabdict_package(os.path.join( |
409 |
abs_user_config, "package.accept_restrict"), |
410 |
recursive=True, allow_wildcard=True, |
411 |
- allow_repo=True, verify_eapi=False) |
412 |
+ allow_repo=True, verify_eapi=False, |
413 |
+ allow_build_id=True) |
414 |
v = d.pop("*/*", None) |
415 |
if v is not None: |
416 |
if "ACCEPT_RESTRICT" in self.configdict["conf"]: |
417 |
@@ -734,7 +737,8 @@ class config(object): |
418 |
#package.env |
419 |
penvdict = grabdict_package(os.path.join( |
420 |
abs_user_config, "package.env"), recursive=1, allow_wildcard=True, \ |
421 |
- allow_repo=True, verify_eapi=False) |
422 |
+ allow_repo=True, verify_eapi=False, |
423 |
+ allow_build_id=True) |
424 |
v = penvdict.pop("*/*", None) |
425 |
if v is not None: |
426 |
global_wildcard_conf = {} |
427 |
@@ -764,7 +768,8 @@ class config(object): |
428 |
bashrc = grabdict_package(os.path.join(profile.location, |
429 |
"package.bashrc"), recursive=1, allow_wildcard=True, |
430 |
allow_repo=True, verify_eapi=True, |
431 |
- eapi=profile.eapi, eapi_default=None) |
432 |
+ eapi=profile.eapi, eapi_default=None, |
433 |
+ allow_build_id=profile.allow_build_id) |
434 |
if not bashrc: |
435 |
continue |
436 |
|
437 |
diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py |
438 |
index a884156..5da1810 100644 |
439 |
--- a/pym/portage/repository/config.py |
440 |
+++ b/pym/portage/repository/config.py |
441 |
@@ -42,7 +42,7 @@ _invalid_path_char_re = re.compile(r'[^a-zA-Z0-9._\-+:/]') |
442 |
|
443 |
_valid_profile_formats = frozenset( |
444 |
['pms', 'portage-1', 'portage-2', 'profile-bashrcs', 'profile-set', |
445 |
- 'profile-default-eapi']) |
446 |
+ 'profile-default-eapi', 'build-id']) |
447 |
|
448 |
_portage1_profiles_allow_directories = frozenset( |
449 |
["portage-1-compat", "portage-1", 'portage-2']) |
450 |
diff --git a/pym/portage/tests/dep/test_isvalidatom.py b/pym/portage/tests/dep/test_isvalidatom.py |
451 |
index 67ba603..9d3367a 100644 |
452 |
--- a/pym/portage/tests/dep/test_isvalidatom.py |
453 |
+++ b/pym/portage/tests/dep/test_isvalidatom.py |
454 |
@@ -5,11 +5,13 @@ from portage.tests import TestCase |
455 |
from portage.dep import isvalidatom |
456 |
|
457 |
class IsValidAtomTestCase(object): |
458 |
- def __init__(self, atom, expected, allow_wildcard=False, allow_repo=False): |
459 |
+ def __init__(self, atom, expected, allow_wildcard=False, |
460 |
+ allow_repo=False, allow_build_id=False): |
461 |
self.atom = atom |
462 |
self.expected = expected |
463 |
self.allow_wildcard = allow_wildcard |
464 |
self.allow_repo = allow_repo |
465 |
+ self.allow_build_id = allow_build_id |
466 |
|
467 |
class IsValidAtom(TestCase): |
468 |
|
469 |
@@ -154,5 +156,7 @@ class IsValidAtom(TestCase): |
470 |
else: |
471 |
atom_type = "invalid" |
472 |
self.assertEqual(bool(isvalidatom(test_case.atom, allow_wildcard=test_case.allow_wildcard, |
473 |
- allow_repo=test_case.allow_repo)), test_case.expected, |
474 |
+ allow_repo=test_case.allow_repo, |
475 |
+ allow_build_id=test_case.allow_build_id)), |
476 |
+ test_case.expected, |
477 |
msg="isvalidatom(%s) != %s" % (test_case.atom, test_case.expected)) |
478 |
diff --git a/pym/portage/tests/resolver/binpkg_multi_instance/test_build_id_profile_format.py b/pym/portage/tests/resolver/binpkg_multi_instance/test_build_id_profile_format.py |
479 |
new file mode 100644 |
480 |
index 0000000..0397509 |
481 |
--- /dev/null |
482 |
+++ b/pym/portage/tests/resolver/binpkg_multi_instance/test_build_id_profile_format.py |
483 |
@@ -0,0 +1,134 @@ |
484 |
+# Copyright 2015 Gentoo Foundation |
485 |
+# Distributed under the terms of the GNU General Public License v2 |
486 |
+ |
487 |
+from portage.tests import TestCase |
488 |
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground, |
489 |
+ ResolverPlaygroundTestCase) |
490 |
+ |
491 |
+class BuildIdProfileFormatTestCase(TestCase): |
492 |
+ |
493 |
+ def testBuildIdProfileFormat(self): |
494 |
+ |
495 |
+ profile = { |
496 |
+ "packages": ("=app-misc/A-1-2",), |
497 |
+ "package.provided": ("sys-libs/zlib-1.2.8-r1",), |
498 |
+ } |
499 |
+ |
500 |
+ repo_configs = { |
501 |
+ "test_repo": { |
502 |
+ "layout.conf": ( |
503 |
+ "profile-formats = build-id profile-set", |
504 |
+ ), |
505 |
+ } |
506 |
+ } |
507 |
+ |
508 |
+ user_config = { |
509 |
+ "make.conf": |
510 |
+ ( |
511 |
+ "FEATURES=\"binpkg-multi-instance\"", |
512 |
+ ), |
513 |
+ } |
514 |
+ |
515 |
+ ebuilds = { |
516 |
+ "app-misc/A-1" : { |
517 |
+ "EAPI": "5", |
518 |
+ "RDEPEND": "sys-libs/zlib dev-libs/B[foo]", |
519 |
+ "DEPEND": "sys-libs/zlib dev-libs/B[foo]", |
520 |
+ }, |
521 |
+ "dev-libs/B-1" : { |
522 |
+ "EAPI": "5", |
523 |
+ "IUSE": "foo", |
524 |
+ }, |
525 |
+ } |
526 |
+ |
527 |
+ binpkgs = ( |
528 |
+ ("app-misc/A-1", { |
529 |
+ "EAPI": "5", |
530 |
+ "BUILD_ID": "1", |
531 |
+ "BUILD_TIME": "1", |
532 |
+ "RDEPEND": "sys-libs/zlib dev-libs/B[foo]", |
533 |
+ "DEPEND": "sys-libs/zlib dev-libs/B[foo]", |
534 |
+ }), |
535 |
+ ("app-misc/A-1", { |
536 |
+ "EAPI": "5", |
537 |
+ "BUILD_ID": "2", |
538 |
+ "BUILD_TIME": "2", |
539 |
+ "RDEPEND": "sys-libs/zlib dev-libs/B[foo]", |
540 |
+ "DEPEND": "sys-libs/zlib dev-libs/B[foo]", |
541 |
+ }), |
542 |
+ ("app-misc/A-1", { |
543 |
+ "EAPI": "5", |
544 |
+ "BUILD_ID": "3", |
545 |
+ "BUILD_TIME": "3", |
546 |
+ "RDEPEND": "sys-libs/zlib dev-libs/B[foo]", |
547 |
+ "DEPEND": "sys-libs/zlib dev-libs/B[foo]", |
548 |
+ }), |
549 |
+ ("dev-libs/B-1", { |
550 |
+ "EAPI": "5", |
551 |
+ "IUSE": "foo", |
552 |
+ "USE": "", |
553 |
+ "BUILD_ID": "1", |
554 |
+ "BUILD_TIME": "1", |
555 |
+ }), |
556 |
+ ("dev-libs/B-1", { |
557 |
+ "EAPI": "5", |
558 |
+ "IUSE": "foo", |
559 |
+ "USE": "foo", |
560 |
+ "BUILD_ID": "2", |
561 |
+ "BUILD_TIME": "2", |
562 |
+ }), |
563 |
+ ("dev-libs/B-1", { |
564 |
+ "EAPI": "5", |
565 |
+ "IUSE": "foo", |
566 |
+ "USE": "", |
567 |
+ "BUILD_ID": "3", |
568 |
+ "BUILD_TIME": "3", |
569 |
+ }), |
570 |
+ ) |
571 |
+ |
572 |
+ installed = { |
573 |
+ "app-misc/A-1" : { |
574 |
+ "EAPI": "5", |
575 |
+ "BUILD_ID": "1", |
576 |
+ "BUILD_TIME": "1", |
577 |
+ "RDEPEND": "sys-libs/zlib", |
578 |
+ "DEPEND": "sys-libs/zlib", |
579 |
+ }, |
580 |
+ "dev-libs/B-1" : { |
581 |
+ "EAPI": "5", |
582 |
+ "IUSE": "foo", |
583 |
+ "USE": "foo", |
584 |
+ "BUILD_ID": "2", |
585 |
+ "BUILD_TIME": "2", |
586 |
+ }, |
587 |
+ } |
588 |
+ |
589 |
+ world = () |
590 |
+ |
591 |
+ test_cases = ( |
592 |
+ |
593 |
+ ResolverPlaygroundTestCase( |
594 |
+ ["@world"], |
595 |
+ options = {"--emptytree": True, "--usepkgonly": True}, |
596 |
+ success = True, |
597 |
+ mergelist = [ |
598 |
+ "[binary]dev-libs/B-1-2", |
599 |
+ "[binary]app-misc/A-1-2" |
600 |
+ ] |
601 |
+ ), |
602 |
+ |
603 |
+ ) |
604 |
+ |
605 |
+ playground = ResolverPlayground(debug=False, |
606 |
+ binpkgs=binpkgs, ebuilds=ebuilds, installed=installed, |
607 |
+ repo_configs=repo_configs, profile=profile, |
608 |
+ user_config=user_config, world=world) |
609 |
+ try: |
610 |
+ for test_case in test_cases: |
611 |
+ playground.run_TestCase(test_case) |
612 |
+ self.assertEqual(test_case.test_success, True, |
613 |
+ test_case.fail_msg) |
614 |
+ finally: |
615 |
+ # Disable debug so that cleanup works. |
616 |
+ #playground.debug = False |
617 |
+ playground.cleanup() |
618 |
diff --git a/pym/portage/util/__init__.py b/pym/portage/util/__init__.py |
619 |
index b6f5787..aeb951e 100644 |
620 |
--- a/pym/portage/util/__init__.py |
621 |
+++ b/pym/portage/util/__init__.py |
622 |
@@ -424,7 +424,8 @@ def read_corresponding_eapi_file(filename, default="0"): |
623 |
return default |
624 |
return eapi |
625 |
|
626 |
-def grabdict_package(myfilename, juststrings=0, recursive=0, allow_wildcard=False, allow_repo=False, |
627 |
+def grabdict_package(myfilename, juststrings=0, recursive=0, |
628 |
+ allow_wildcard=False, allow_repo=False, allow_build_id=False, |
629 |
verify_eapi=False, eapi=None, eapi_default="0"): |
630 |
""" Does the same thing as grabdict except it validates keys |
631 |
with isvalidatom()""" |
632 |
@@ -447,7 +448,8 @@ def grabdict_package(myfilename, juststrings=0, recursive=0, allow_wildcard=Fals |
633 |
for k, v in d.items(): |
634 |
try: |
635 |
k = Atom(k, allow_wildcard=allow_wildcard, |
636 |
- allow_repo=allow_repo, eapi=eapi) |
637 |
+ allow_repo=allow_repo, |
638 |
+ allow_build_id=allow_build_id, eapi=eapi) |
639 |
except InvalidAtom as e: |
640 |
writemsg(_("--- Invalid atom in %s: %s\n") % (filename, e), |
641 |
noiselevel=-1) |
642 |
@@ -460,7 +462,8 @@ def grabdict_package(myfilename, juststrings=0, recursive=0, allow_wildcard=Fals |
643 |
|
644 |
return atoms |
645 |
|
646 |
-def grabfile_package(myfilename, compatlevel=0, recursive=0, allow_wildcard=False, allow_repo=False, |
647 |
+def grabfile_package(myfilename, compatlevel=0, recursive=0, |
648 |
+ allow_wildcard=False, allow_repo=False, allow_build_id=False, |
649 |
remember_source_file=False, verify_eapi=False, eapi=None, |
650 |
eapi_default="0"): |
651 |
|
652 |
@@ -480,7 +483,9 @@ def grabfile_package(myfilename, compatlevel=0, recursive=0, allow_wildcard=Fals |
653 |
if pkg[:1] == '*' and mybasename == 'packages': |
654 |
pkg = pkg[1:] |
655 |
try: |
656 |
- pkg = Atom(pkg, allow_wildcard=allow_wildcard, allow_repo=allow_repo, eapi=eapi) |
657 |
+ pkg = Atom(pkg, allow_wildcard=allow_wildcard, |
658 |
+ allow_repo=allow_repo, allow_build_id=allow_build_id, |
659 |
+ eapi=eapi) |
660 |
except InvalidAtom as e: |
661 |
writemsg(_("--- Invalid atom in %s: %s\n") % (source_file, e), |
662 |
noiselevel=-1) |
663 |
-- |
664 |
2.0.5 |