Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH 2/2] Add profile-formats=build-id (bug 150031)
Date: Tue, 17 Feb 2015 08:37:51
Message-Id: 1424162233-25071-2-git-send-email-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH 1/2] Add FEATURES=binpkg-multi-instance (bug 150031) by Zac Medico
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

Replies