1 # Copyright 2010-2012 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
8 from _emerge.Package import Package
10 from portage.dep import Atom, dep_getrepo, dep_getslot, ExtendedAtomDict, remove_slot, _get_useflag_re, _repo_separator
11 from portage.eapi import eapi_has_use_aliases, eapi_supports_stable_use_forcing_and_masking
12 from portage.exception import InvalidAtom
13 from portage.localization import _
14 from portage.util import grabfile, grabdict, grabdict_package, read_corresponding_eapi_file, stack_lists, writemsg
15 from portage.versions import _pkg_str
17 from portage.package.ebuild._config.helper import ordered_by_atom_specificity
19 class UseManager(object):
21 def __init__(self, repositories, profiles, abs_user_config, is_stable,
24 #--------------------------------
26 #--------------------------------
27 # use.mask _repo_usemask_dict
28 # use.stable.mask _repo_usestablemask_dict
29 # use.force _repo_useforce_dict
30 # use.stable.force _repo_usestableforce_dict
31 # use.aliases _repo_usealiases_dict
32 # package.use.mask _repo_pusemask_dict
33 # package.use.stable.mask _repo_pusestablemask_dict
34 # package.use.force _repo_puseforce_dict
35 # package.use.stable.force _repo_pusestableforce_dict
36 # package.use.aliases _repo_pusealiases_dict
37 #--------------------------------
39 #--------------------------------
40 # use.mask _usemask_list
41 # use.stable.mask _usestablemask_list
42 # use.force _useforce_list
43 # use.stable.force _usestableforce_list
44 # package.use.mask _pusemask_list
45 # package.use.stable.mask _pusestablemask_list
46 # package.use _pkgprofileuse
47 # package.use.force _puseforce_list
48 # package.use.stable.force _pusestableforce_list
49 #--------------------------------
51 #--------------------------------
52 # package.use _pusedict
54 # Dynamic variables tracked by the config class
55 #--------------------------------
57 #--------------------------------
60 #--------------------------------
62 #--------------------------------
65 self._user_config = user_config
66 self._is_stable = is_stable
67 self._repo_usemask_dict = self._parse_repository_files_to_dict_of_tuples("use.mask", repositories)
68 self._repo_usestablemask_dict = \
69 self._parse_repository_files_to_dict_of_tuples("use.stable.mask",
70 repositories, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
71 self._repo_useforce_dict = self._parse_repository_files_to_dict_of_tuples("use.force", repositories)
72 self._repo_usestableforce_dict = \
73 self._parse_repository_files_to_dict_of_tuples("use.stable.force",
74 repositories, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
75 self._repo_pusemask_dict = self._parse_repository_files_to_dict_of_dicts("package.use.mask", repositories)
76 self._repo_pusestablemask_dict = \
77 self._parse_repository_files_to_dict_of_dicts("package.use.stable.mask",
78 repositories, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
79 self._repo_puseforce_dict = self._parse_repository_files_to_dict_of_dicts("package.use.force", repositories)
80 self._repo_pusestableforce_dict = \
81 self._parse_repository_files_to_dict_of_dicts("package.use.stable.force",
82 repositories, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
83 self._repo_puse_dict = self._parse_repository_files_to_dict_of_dicts("package.use", repositories)
85 self._usemask_list = self._parse_profile_files_to_tuple_of_tuples("use.mask", profiles)
86 self._usestablemask_list = \
87 self._parse_profile_files_to_tuple_of_tuples("use.stable.mask",
88 profiles, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
89 self._useforce_list = self._parse_profile_files_to_tuple_of_tuples("use.force", profiles)
90 self._usestableforce_list = \
91 self._parse_profile_files_to_tuple_of_tuples("use.stable.force",
92 profiles, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
93 self._pusemask_list = self._parse_profile_files_to_tuple_of_dicts("package.use.mask", profiles)
94 self._pusestablemask_list = \
95 self._parse_profile_files_to_tuple_of_dicts("package.use.stable.mask",
96 profiles, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
97 self._pkgprofileuse = self._parse_profile_files_to_tuple_of_dicts("package.use", profiles, juststrings=True)
98 self._puseforce_list = self._parse_profile_files_to_tuple_of_dicts("package.use.force", profiles)
99 self._pusestableforce_list = \
100 self._parse_profile_files_to_tuple_of_dicts("package.use.stable.force",
101 profiles, eapi_filter=eapi_supports_stable_use_forcing_and_masking)
103 self._pusedict = self._parse_user_files_to_extatomdict("package.use", abs_user_config, user_config)
105 self._repo_usealiases_dict = self._parse_repository_usealiases(repositories)
106 self._repo_pusealiases_dict = self._parse_repository_packageusealiases(repositories)
108 self.repositories = repositories
110 def _parse_file_to_tuple(self, file_name, recursive=True, eapi_filter=None):
112 lines = grabfile(file_name, recursive=recursive)
113 eapi = read_corresponding_eapi_file(file_name)
114 if eapi_filter is not None and not eapi_filter(eapi):
116 writemsg(_("--- EAPI '%s' does not support '%s': '%s'\n") %
117 (eapi, os.path.basename(file_name), file_name),
120 useflag_re = _get_useflag_re(eapi)
121 for prefixed_useflag in lines:
122 if prefixed_useflag[:1] == "-":
123 useflag = prefixed_useflag[1:]
125 useflag = prefixed_useflag
126 if useflag_re.match(useflag) is None:
127 writemsg(_("--- Invalid USE flag in '%s': '%s'\n") %
128 (file_name, prefixed_useflag), noiselevel=-1)
130 ret.append(prefixed_useflag)
133 def _parse_file_to_dict(self, file_name, juststrings=False, recursive=True,
134 eapi_filter=None, user_config=False):
137 eapi = read_corresponding_eapi_file(file_name, default=None)
138 if eapi is None and not user_config:
141 ret = ExtendedAtomDict(dict)
144 file_dict = grabdict_package(file_name, recursive=recursive,
145 allow_wildcard=(eapi is None), allow_repo=(eapi is None),
146 verify_eapi=(eapi is not None))
147 if eapi is not None and eapi_filter is not None and not eapi_filter(eapi):
149 writemsg(_("--- EAPI '%s' does not support '%s': '%s'\n") %
150 (eapi, os.path.basename(file_name), file_name),
153 useflag_re = _get_useflag_re(eapi)
154 for k, v in file_dict.items():
156 for prefixed_useflag in v:
157 if prefixed_useflag[:1] == "-":
158 useflag = prefixed_useflag[1:]
160 useflag = prefixed_useflag
161 if useflag_re.match(useflag) is None:
162 writemsg(_("--- Invalid USE flag for '%s' in '%s': '%s'\n") %
163 (k, file_name, prefixed_useflag), noiselevel=-1)
165 useflags.append(prefixed_useflag)
166 location_dict.setdefault(k, []).extend(useflags)
167 for k, v in location_dict.items():
172 ret.setdefault(k.cp, {})[k] = v
175 def _parse_user_files_to_extatomdict(self, file_name, location, user_config):
176 ret = ExtendedAtomDict(dict)
178 pusedict = grabdict_package(
179 os.path.join(location, file_name), recursive=1, allow_wildcard=True, allow_repo=True, verify_eapi=False)
180 for k, v in pusedict.items():
181 ret.setdefault(k.cp, {})[k] = tuple(v)
185 def _parse_repository_files_to_dict_of_tuples(self, file_name, repositories, eapi_filter=None):
187 for repo in repositories.repos_with_profiles():
188 ret[repo.name] = self._parse_file_to_tuple(os.path.join(repo.location, "profiles", file_name), eapi_filter=eapi_filter)
191 def _parse_repository_files_to_dict_of_dicts(self, file_name, repositories, eapi_filter=None):
193 for repo in repositories.repos_with_profiles():
194 ret[repo.name] = self._parse_file_to_dict(os.path.join(repo.location, "profiles", file_name), eapi_filter=eapi_filter)
197 def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations,
199 return tuple(self._parse_file_to_tuple(
200 os.path.join(profile.location, file_name),
201 recursive=profile.portage1_directories, eapi_filter=eapi_filter)
202 for profile in locations)
204 def _parse_profile_files_to_tuple_of_dicts(self, file_name, locations,
205 juststrings=False, eapi_filter=None):
206 return tuple(self._parse_file_to_dict(
207 os.path.join(profile.location, file_name), juststrings,
208 recursive=profile.portage1_directories, eapi_filter=eapi_filter,
209 user_config=profile.user_config)
210 for profile in locations)
212 def _parse_repository_usealiases(self, repositories):
214 for repo in repositories.repos_with_profiles():
215 file_name = os.path.join(repo.location, "profiles", "use.aliases")
216 eapi = read_corresponding_eapi_file(file_name)
217 useflag_re = _get_useflag_re(eapi)
218 raw_file_dict = grabdict(file_name, recursive=True)
220 for real_flag, aliases in raw_file_dict.items():
221 if useflag_re.match(real_flag) is None:
222 writemsg(_("--- Invalid real USE flag in '%s': '%s'\n") % (file_name, real_flag), noiselevel=-1)
224 for alias in aliases:
225 if useflag_re.match(alias) is None:
226 writemsg(_("--- Invalid USE flag alias for '%s' real USE flag in '%s': '%s'\n") %
227 (real_flag, file_name, alias), noiselevel=-1)
229 if any(alias in v for k, v in file_dict.items() if k != real_flag):
230 writemsg(_("--- Duplicated USE flag alias in '%s': '%s'\n") %
231 (file_name, alias), noiselevel=-1)
233 file_dict.setdefault(real_flag, []).append(alias)
234 ret[repo.name] = file_dict
237 def _parse_repository_packageusealiases(self, repositories):
239 for repo in repositories.repos_with_profiles():
240 file_name = os.path.join(repo.location, "profiles", "package.use.aliases")
241 eapi = read_corresponding_eapi_file(file_name)
242 useflag_re = _get_useflag_re(eapi)
243 lines = grabfile(file_name, recursive=True)
246 elements = line.split()
249 atom = Atom(atom, eapi=eapi)
251 writemsg(_("--- Invalid atom in '%s': '%s'\n") % (file_name, atom))
253 if len(elements) == 1:
254 writemsg(_("--- Missing real USE flag for '%s' in '%s'\n") % (atom, file_name), noiselevel=-1)
256 real_flag = elements[1]
257 if useflag_re.match(real_flag) is None:
258 writemsg(_("--- Invalid real USE flag for '%s' in '%s': '%s'\n") % (atom, file_name, real_flag), noiselevel=-1)
260 for alias in elements[2:]:
261 if useflag_re.match(alias) is None:
262 writemsg(_("--- Invalid USE flag alias for '%s' real USE flag for '%s' in '%s': '%s'\n") %
263 (real_flag, atom, file_name, alias), noiselevel=-1)
265 # Duplicated USE flag aliases in entries for different atoms
266 # matching the same package version are detected in getUseAliases().
267 if any(alias in v for k, v in file_dict.get(atom.cp, {}).get(atom, {}).items() if k != real_flag):
268 writemsg(_("--- Duplicated USE flag alias for '%s' in '%s': '%s'\n") %
269 (atom, file_name, alias), noiselevel=-1)
271 file_dict.setdefault(atom.cp, {}).setdefault(atom, {}).setdefault(real_flag, []).append(alias)
272 ret[repo.name] = file_dict
275 def _isStable(self, pkg):
276 if self._user_config:
279 except AttributeError:
280 # KEYWORDS is unavailable (prior to "depend" phase)
285 except AttributeError:
286 # KEYWORDS is unavailable (prior to "depend" phase)
289 # Since repoman uses different config instances for
290 # different profiles, we have to be careful to do the
291 # stable check against the correct profile here.
292 return self._is_stable(pkg)
294 def getUseMask(self, pkg=None):
296 return frozenset(stack_lists(
297 self._usemask_list, incremental=True))
300 cp = getattr(pkg, "cp", None)
302 slot = dep_getslot(pkg)
303 repo = dep_getrepo(pkg)
304 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo)
307 stable = self._isStable(pkg)
311 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
314 repos.extend(repo.name for repo in
315 self.repositories[pkg.repo].masters)
318 repos.append(pkg.repo)
320 usemask.append(self._repo_usemask_dict.get(repo, {}))
322 usemask.append(self._repo_usestablemask_dict.get(repo, {}))
323 cpdict = self._repo_pusemask_dict.get(repo, {}).get(cp)
325 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
327 usemask.extend(pkg_usemask)
329 cpdict = self._repo_pusestablemask_dict.get(repo, {}).get(cp)
331 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
333 usemask.extend(pkg_usemask)
335 for i, pusemask_dict in enumerate(self._pusemask_list):
336 if self._usemask_list[i]:
337 usemask.append(self._usemask_list[i])
338 if stable and self._usestablemask_list[i]:
339 usemask.append(self._usestablemask_list[i])
340 cpdict = pusemask_dict.get(cp)
342 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
344 usemask.extend(pkg_usemask)
346 cpdict = self._pusestablemask_list[i].get(cp)
348 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
350 usemask.extend(pkg_usemask)
352 return frozenset(stack_lists(usemask, incremental=True))
354 def getUseForce(self, pkg=None):
356 return frozenset(stack_lists(
357 self._useforce_list, incremental=True))
359 cp = getattr(pkg, "cp", None)
361 slot = dep_getslot(pkg)
362 repo = dep_getrepo(pkg)
363 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo)
366 stable = self._isStable(pkg)
370 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
373 repos.extend(repo.name for repo in
374 self.repositories[pkg.repo].masters)
377 repos.append(pkg.repo)
379 useforce.append(self._repo_useforce_dict.get(repo, {}))
381 useforce.append(self._repo_usestableforce_dict.get(repo, {}))
382 cpdict = self._repo_puseforce_dict.get(repo, {}).get(cp)
384 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
386 useforce.extend(pkg_useforce)
388 cpdict = self._repo_pusestableforce_dict.get(repo, {}).get(cp)
390 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
392 useforce.extend(pkg_useforce)
394 for i, puseforce_dict in enumerate(self._puseforce_list):
395 if self._useforce_list[i]:
396 useforce.append(self._useforce_list[i])
397 if stable and self._usestableforce_list[i]:
398 useforce.append(self._usestableforce_list[i])
399 cpdict = puseforce_dict.get(cp)
401 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
403 useforce.extend(pkg_useforce)
405 cpdict = self._pusestableforce_list[i].get(cp)
407 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
409 useforce.extend(pkg_useforce)
411 return frozenset(stack_lists(useforce, incremental=True))
413 def getUseAliases(self, pkg):
414 if not eapi_has_use_aliases(pkg.eapi):
417 cp = getattr(pkg, "cp", None)
419 slot = dep_getslot(pkg)
420 repo = dep_getrepo(pkg)
421 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo)
426 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
429 repos.extend(repo.name for repo in
430 self.repositories[pkg.repo].masters)
433 repos.append(pkg.repo)
435 usealiases_dict = self._repo_usealiases_dict.get(repo, {})
436 for real_flag, aliases in usealiases_dict.items():
437 for alias in aliases:
438 if any(alias in v for k, v in usealiases.items() if k != real_flag):
439 writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") %
440 (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1)
442 usealiases.setdefault(real_flag, []).append(alias)
443 cp_usealiases_dict = self._repo_pusealiases_dict.get(repo, {}).get(cp)
444 if cp_usealiases_dict:
445 usealiases_dict_list = ordered_by_atom_specificity(cp_usealiases_dict, pkg)
446 for usealiases_dict in usealiases_dict_list:
447 for real_flag, aliases in usealiases_dict.items():
448 for alias in aliases:
449 if any(alias in v for k, v in usealiases.items() if k != real_flag):
450 writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") %
451 (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1)
453 usealiases.setdefault(real_flag, []).append(alias)
457 def getPUSE(self, pkg):
458 cp = getattr(pkg, "cp", None)
460 slot = dep_getslot(pkg)
461 repo = dep_getrepo(pkg)
462 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo)
465 cpdict = self._pusedict.get(cp)
467 puse_matches = ordered_by_atom_specificity(cpdict, pkg)
470 for x in puse_matches:
472 ret = " ".join(puse_list)
475 def extract_global_USE_changes(self, old=""):
477 cpdict = self._pusedict.get("*/*")
478 if cpdict is not None:
479 v = cpdict.pop("*/*", None)
483 ret = old + " " + ret
485 #No tokens left in atom_license_map, remove it.
486 del self._pusedict["*/*"]