Gentoo Archives: gentoo-commits

From: Zac Medico <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: pym/portage/util/, pym/_emerge/, pym/portage/dep/, pym/portage/_sets/, ...
Date: Wed, 04 Mar 2015 21:37:58
Message-Id: 1425504727.c6e3af2b1e419d70443a74575e9b762a101a3912.zmedico@gentoo
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)