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