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