Package portage :: Package package :: Package ebuild :: Package _config :: Module UseManager
[hide private]

Source Code for Module portage.package.ebuild._config.UseManager

  1  # Copyright 2010-2014 Gentoo Foundation 
  2  # Distributed under the terms of the GNU General Public License v2 
  3   
  4  __all__ = ( 
  5          'UseManager', 
  6  ) 
  7   
  8  from _emerge.Package import Package 
  9  from portage import os 
 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 
 16   
 17  from portage.package.ebuild._config.helper import ordered_by_atom_specificity 
 18   
19 -class UseManager(object):
20
21 - def __init__(self, repositories, profiles, abs_user_config, is_stable, 22 user_config=True):
23 # file variable 24 #-------------------------------- 25 # repositories 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 #-------------------------------- 38 # profiles 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 #-------------------------------- 50 # user config 51 #-------------------------------- 52 # package.use _pusedict 53 54 # Dynamic variables tracked by the config class 55 #-------------------------------- 56 # profiles 57 #-------------------------------- 58 # usemask 59 # useforce 60 #-------------------------------- 61 # user config 62 #-------------------------------- 63 # puse 64 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) 84 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) 102 103 self._pusedict = self._parse_user_files_to_extatomdict("package.use", abs_user_config, user_config) 104 105 self._repo_usealiases_dict = self._parse_repository_usealiases(repositories) 106 self._repo_pusealiases_dict = self._parse_repository_packageusealiases(repositories) 107 108 self.repositories = repositories
109
110 - def _parse_file_to_tuple(self, file_name, recursive=True, 111 eapi_filter=None, eapi=None, eapi_default="0"):
112 """ 113 @param file_name: input file name 114 @type file_name: str 115 @param recursive: triggers recursion if the input file is a 116 directory 117 @type recursive: bool 118 @param eapi_filter: a function that accepts a single eapi 119 argument, and returns true if the the current file type 120 is supported by the given EAPI 121 @type eapi_filter: callable 122 @param eapi: the EAPI of the current profile node, which allows 123 a call to read_corresponding_eapi_file to be skipped 124 @type eapi: str 125 @param eapi_default: the default EAPI which applies if the 126 current profile node does not define a local EAPI 127 @type eapi_default: str 128 @rtype: tuple 129 @return: collection of USE flags 130 """ 131 ret = [] 132 lines = grabfile(file_name, recursive=recursive) 133 if eapi is None: 134 eapi = read_corresponding_eapi_file( 135 file_name, default=eapi_default) 136 if eapi_filter is not None and not eapi_filter(eapi): 137 if lines: 138 writemsg(_("--- EAPI '%s' does not support '%s': '%s'\n") % 139 (eapi, os.path.basename(file_name), file_name), 140 noiselevel=-1) 141 return () 142 useflag_re = _get_useflag_re(eapi) 143 for prefixed_useflag in lines: 144 if prefixed_useflag[:1] == "-": 145 useflag = prefixed_useflag[1:] 146 else: 147 useflag = prefixed_useflag 148 if useflag_re.match(useflag) is None: 149 writemsg(_("--- Invalid USE flag in '%s': '%s'\n") % 150 (file_name, prefixed_useflag), noiselevel=-1) 151 else: 152 ret.append(prefixed_useflag) 153 return tuple(ret)
154
155 - def _parse_file_to_dict(self, file_name, juststrings=False, recursive=True, 156 eapi_filter=None, user_config=False, eapi=None, eapi_default="0", 157 allow_build_id=False):
158 """ 159 @param file_name: input file name 160 @type file_name: str 161 @param juststrings: store dict values as space-delimited strings 162 instead of tuples 163 @type juststrings: bool 164 @param recursive: triggers recursion if the input file is a 165 directory 166 @type recursive: bool 167 @param eapi_filter: a function that accepts a single eapi 168 argument, and returns true if the the current file type 169 is supported by the given EAPI 170 @type eapi_filter: callable 171 @param user_config: current file is part of the local 172 configuration (not repository content) 173 @type user_config: bool 174 @param eapi: the EAPI of the current profile node, which allows 175 a call to read_corresponding_eapi_file to be skipped 176 @type eapi: str 177 @param eapi_default: the default EAPI which applies if the 178 current profile node does not define a local EAPI 179 @type eapi_default: str 180 @param allow_build_id: allow atoms to specify a particular 181 build-id 182 @type allow_build_id: bool 183 @rtype: tuple 184 @return: collection of USE flags 185 """ 186 ret = {} 187 location_dict = {} 188 if eapi is None: 189 eapi = read_corresponding_eapi_file(file_name, 190 default=eapi_default) 191 extended_syntax = eapi is None and user_config 192 if extended_syntax: 193 ret = ExtendedAtomDict(dict) 194 else: 195 ret = {} 196 file_dict = grabdict_package(file_name, recursive=recursive, 197 allow_wildcard=extended_syntax, allow_repo=extended_syntax, 198 verify_eapi=(not extended_syntax), eapi=eapi, 199 eapi_default=eapi_default, allow_build_id=allow_build_id) 200 if eapi is not None and eapi_filter is not None and not eapi_filter(eapi): 201 if file_dict: 202 writemsg(_("--- EAPI '%s' does not support '%s': '%s'\n") % 203 (eapi, os.path.basename(file_name), file_name), 204 noiselevel=-1) 205 return ret 206 useflag_re = _get_useflag_re(eapi) 207 for k, v in file_dict.items(): 208 useflags = [] 209 use_expand_prefix = '' 210 for prefixed_useflag in v: 211 if extended_syntax and prefixed_useflag == "\n": 212 use_expand_prefix = "" 213 continue 214 if extended_syntax and prefixed_useflag[-1] == ":": 215 use_expand_prefix = prefixed_useflag[:-1].lower() + "_" 216 continue 217 218 if prefixed_useflag[:1] == "-": 219 useflag = use_expand_prefix + prefixed_useflag[1:] 220 prefixed_useflag = "-" + useflag 221 else: 222 useflag = use_expand_prefix + prefixed_useflag 223 prefixed_useflag = useflag 224 if useflag_re.match(useflag) is None: 225 writemsg(_("--- Invalid USE flag for '%s' in '%s': '%s'\n") % 226 (k, file_name, prefixed_useflag), noiselevel=-1) 227 else: 228 useflags.append(prefixed_useflag) 229 location_dict.setdefault(k, []).extend(useflags) 230 for k, v in location_dict.items(): 231 if juststrings: 232 v = " ".join(v) 233 else: 234 v = tuple(v) 235 ret.setdefault(k.cp, {})[k] = v 236 return ret
237
238 - def _parse_user_files_to_extatomdict(self, file_name, location, user_config):
239 ret = ExtendedAtomDict(dict) 240 if user_config: 241 pusedict = grabdict_package( 242 os.path.join(location, file_name), recursive=1, newlines=1, allow_wildcard=True, allow_repo=True, verify_eapi=False) 243 for k, v in pusedict.items(): 244 l = [] 245 use_expand_prefix = '' 246 for flag in v: 247 if flag == "\n": 248 use_expand_prefix = "" 249 continue 250 if flag[-1] == ":": 251 use_expand_prefix = flag[:-1].lower() + "_" 252 continue 253 if flag[0] == "-": 254 nv = "-" + use_expand_prefix + flag[1:] 255 else: 256 nv = use_expand_prefix + flag 257 l.append(nv) 258 ret.setdefault(k.cp, {})[k] = tuple(l) 259 260 return ret
261
262 - def _parse_repository_files_to_dict_of_tuples(self, file_name, repositories, eapi_filter=None):
263 ret = {} 264 for repo in repositories.repos_with_profiles(): 265 ret[repo.name] = self._parse_file_to_tuple( 266 os.path.join(repo.location, "profiles", file_name), 267 eapi_filter=eapi_filter, eapi_default=repo.eapi) 268 return ret
269
270 - def _parse_repository_files_to_dict_of_dicts(self, file_name, repositories, eapi_filter=None):
271 ret = {} 272 for repo in repositories.repos_with_profiles(): 273 ret[repo.name] = self._parse_file_to_dict( 274 os.path.join(repo.location, "profiles", file_name), 275 eapi_filter=eapi_filter, eapi_default=repo.eapi, 276 allow_build_id=("build-id" in repo.profile_formats)) 277 return ret
278
279 - def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations, 280 eapi_filter=None):
281 return tuple(self._parse_file_to_tuple( 282 os.path.join(profile.location, file_name), 283 recursive=profile.portage1_directories, 284 eapi_filter=eapi_filter, eapi=profile.eapi, 285 eapi_default=None) for profile in locations)
286
287 - def _parse_profile_files_to_tuple_of_dicts(self, file_name, locations, 288 juststrings=False, eapi_filter=None):
289 return tuple(self._parse_file_to_dict( 290 os.path.join(profile.location, file_name), juststrings, 291 recursive=profile.portage1_directories, eapi_filter=eapi_filter, 292 user_config=profile.user_config, eapi=profile.eapi, 293 eapi_default=None, allow_build_id=profile.allow_build_id) 294 for profile in locations)
295
296 - def _parse_repository_usealiases(self, repositories):
297 ret = {} 298 for repo in repositories.repos_with_profiles(): 299 file_name = os.path.join(repo.location, "profiles", "use.aliases") 300 eapi = read_corresponding_eapi_file( 301 file_name, default=repo.eapi) 302 useflag_re = _get_useflag_re(eapi) 303 raw_file_dict = grabdict(file_name, recursive=True) 304 file_dict = {} 305 for real_flag, aliases in raw_file_dict.items(): 306 if useflag_re.match(real_flag) is None: 307 writemsg(_("--- Invalid real USE flag in '%s': '%s'\n") % (file_name, real_flag), noiselevel=-1) 308 else: 309 for alias in aliases: 310 if useflag_re.match(alias) is None: 311 writemsg(_("--- Invalid USE flag alias for '%s' real USE flag in '%s': '%s'\n") % 312 (real_flag, file_name, alias), noiselevel=-1) 313 else: 314 if any(alias in v for k, v in file_dict.items() if k != real_flag): 315 writemsg(_("--- Duplicated USE flag alias in '%s': '%s'\n") % 316 (file_name, alias), noiselevel=-1) 317 else: 318 file_dict.setdefault(real_flag, []).append(alias) 319 ret[repo.name] = file_dict 320 return ret
321
322 - def _parse_repository_packageusealiases(self, repositories):
323 ret = {} 324 for repo in repositories.repos_with_profiles(): 325 file_name = os.path.join(repo.location, "profiles", "package.use.aliases") 326 eapi = read_corresponding_eapi_file( 327 file_name, default=repo.eapi) 328 useflag_re = _get_useflag_re(eapi) 329 lines = grabfile(file_name, recursive=True) 330 file_dict = {} 331 for line in lines: 332 elements = line.split() 333 atom = elements[0] 334 try: 335 atom = Atom(atom, eapi=eapi) 336 except InvalidAtom: 337 writemsg(_("--- Invalid atom in '%s': '%s'\n") % (file_name, atom)) 338 continue 339 if len(elements) == 1: 340 writemsg(_("--- Missing real USE flag for '%s' in '%s'\n") % (atom, file_name), noiselevel=-1) 341 continue 342 real_flag = elements[1] 343 if useflag_re.match(real_flag) is None: 344 writemsg(_("--- Invalid real USE flag for '%s' in '%s': '%s'\n") % (atom, file_name, real_flag), noiselevel=-1) 345 else: 346 for alias in elements[2:]: 347 if useflag_re.match(alias) is None: 348 writemsg(_("--- Invalid USE flag alias for '%s' real USE flag for '%s' in '%s': '%s'\n") % 349 (real_flag, atom, file_name, alias), noiselevel=-1) 350 else: 351 # Duplicated USE flag aliases in entries for different atoms 352 # matching the same package version are detected in getUseAliases(). 353 if any(alias in v for k, v in file_dict.get(atom.cp, {}).get(atom, {}).items() if k != real_flag): 354 writemsg(_("--- Duplicated USE flag alias for '%s' in '%s': '%s'\n") % 355 (atom, file_name, alias), noiselevel=-1) 356 else: 357 file_dict.setdefault(atom.cp, {}).setdefault(atom, {}).setdefault(real_flag, []).append(alias) 358 ret[repo.name] = file_dict 359 return ret
360
361 - def _isStable(self, pkg):
362 if self._user_config: 363 try: 364 return pkg.stable 365 except AttributeError: 366 # KEYWORDS is unavailable (prior to "depend" phase) 367 return False 368 369 try: 370 pkg._metadata 371 except AttributeError: 372 # KEYWORDS is unavailable (prior to "depend" phase) 373 return False 374 375 # Since repoman uses different config instances for 376 # different profiles, we have to be careful to do the 377 # stable check against the correct profile here. 378 return self._is_stable(pkg)
379
380 - def getUseMask(self, pkg=None, stable=None):
381 if pkg is None: 382 return frozenset(stack_lists( 383 self._usemask_list, incremental=True)) 384 385 slot = None 386 cp = getattr(pkg, "cp", None) 387 if cp is None: 388 slot = dep_getslot(pkg) 389 repo = dep_getrepo(pkg) 390 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 391 cp = pkg.cp 392 393 if stable is None: 394 stable = self._isStable(pkg) 395 396 usemask = [] 397 398 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: 399 repos = [] 400 try: 401 repos.extend(repo.name for repo in 402 self.repositories[pkg.repo].masters) 403 except KeyError: 404 pass 405 repos.append(pkg.repo) 406 for repo in repos: 407 usemask.append(self._repo_usemask_dict.get(repo, {})) 408 if stable: 409 usemask.append(self._repo_usestablemask_dict.get(repo, {})) 410 cpdict = self._repo_pusemask_dict.get(repo, {}).get(cp) 411 if cpdict: 412 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 413 if pkg_usemask: 414 usemask.extend(pkg_usemask) 415 if stable: 416 cpdict = self._repo_pusestablemask_dict.get(repo, {}).get(cp) 417 if cpdict: 418 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 419 if pkg_usemask: 420 usemask.extend(pkg_usemask) 421 422 for i, pusemask_dict in enumerate(self._pusemask_list): 423 if self._usemask_list[i]: 424 usemask.append(self._usemask_list[i]) 425 if stable and self._usestablemask_list[i]: 426 usemask.append(self._usestablemask_list[i]) 427 cpdict = pusemask_dict.get(cp) 428 if cpdict: 429 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 430 if pkg_usemask: 431 usemask.extend(pkg_usemask) 432 if stable: 433 cpdict = self._pusestablemask_list[i].get(cp) 434 if cpdict: 435 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 436 if pkg_usemask: 437 usemask.extend(pkg_usemask) 438 439 return frozenset(stack_lists(usemask, incremental=True))
440
441 - def getUseForce(self, pkg=None, stable=None):
442 if pkg is None: 443 return frozenset(stack_lists( 444 self._useforce_list, incremental=True)) 445 446 cp = getattr(pkg, "cp", None) 447 if cp is None: 448 slot = dep_getslot(pkg) 449 repo = dep_getrepo(pkg) 450 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 451 cp = pkg.cp 452 453 if stable is None: 454 stable = self._isStable(pkg) 455 456 useforce = [] 457 458 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: 459 repos = [] 460 try: 461 repos.extend(repo.name for repo in 462 self.repositories[pkg.repo].masters) 463 except KeyError: 464 pass 465 repos.append(pkg.repo) 466 for repo in repos: 467 useforce.append(self._repo_useforce_dict.get(repo, {})) 468 if stable: 469 useforce.append(self._repo_usestableforce_dict.get(repo, {})) 470 cpdict = self._repo_puseforce_dict.get(repo, {}).get(cp) 471 if cpdict: 472 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 473 if pkg_useforce: 474 useforce.extend(pkg_useforce) 475 if stable: 476 cpdict = self._repo_pusestableforce_dict.get(repo, {}).get(cp) 477 if cpdict: 478 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 479 if pkg_useforce: 480 useforce.extend(pkg_useforce) 481 482 for i, puseforce_dict in enumerate(self._puseforce_list): 483 if self._useforce_list[i]: 484 useforce.append(self._useforce_list[i]) 485 if stable and self._usestableforce_list[i]: 486 useforce.append(self._usestableforce_list[i]) 487 cpdict = puseforce_dict.get(cp) 488 if cpdict: 489 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 490 if pkg_useforce: 491 useforce.extend(pkg_useforce) 492 if stable: 493 cpdict = self._pusestableforce_list[i].get(cp) 494 if cpdict: 495 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 496 if pkg_useforce: 497 useforce.extend(pkg_useforce) 498 499 return frozenset(stack_lists(useforce, incremental=True))
500
501 - def getUseAliases(self, pkg):
502 if hasattr(pkg, "eapi") and not eapi_has_use_aliases(pkg.eapi): 503 return {} 504 505 cp = getattr(pkg, "cp", None) 506 if cp is None: 507 slot = dep_getslot(pkg) 508 repo = dep_getrepo(pkg) 509 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 510 cp = pkg.cp 511 512 usealiases = {} 513 514 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: 515 repos = [] 516 try: 517 repos.extend(repo.name for repo in 518 self.repositories[pkg.repo].masters) 519 except KeyError: 520 pass 521 repos.append(pkg.repo) 522 for repo in repos: 523 usealiases_dict = self._repo_usealiases_dict.get(repo, {}) 524 for real_flag, aliases in usealiases_dict.items(): 525 for alias in aliases: 526 if any(alias in v for k, v in usealiases.items() if k != real_flag): 527 writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") % 528 (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1) 529 else: 530 usealiases.setdefault(real_flag, []).append(alias) 531 cp_usealiases_dict = self._repo_pusealiases_dict.get(repo, {}).get(cp) 532 if cp_usealiases_dict: 533 usealiases_dict_list = ordered_by_atom_specificity(cp_usealiases_dict, pkg) 534 for usealiases_dict in usealiases_dict_list: 535 for real_flag, aliases in usealiases_dict.items(): 536 for alias in aliases: 537 if any(alias in v for k, v in usealiases.items() if k != real_flag): 538 writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") % 539 (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1) 540 else: 541 usealiases.setdefault(real_flag, []).append(alias) 542 543 return usealiases
544
545 - def getPUSE(self, pkg):
546 cp = getattr(pkg, "cp", None) 547 if cp is None: 548 slot = dep_getslot(pkg) 549 repo = dep_getrepo(pkg) 550 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 551 cp = pkg.cp 552 ret = "" 553 cpdict = self._pusedict.get(cp) 554 if cpdict: 555 puse_matches = ordered_by_atom_specificity(cpdict, pkg) 556 if puse_matches: 557 puse_list = [] 558 for x in puse_matches: 559 puse_list.extend(x) 560 ret = " ".join(puse_list) 561 return ret
562
563 - def extract_global_USE_changes(self, old=""):
564 ret = old 565 cpdict = self._pusedict.get("*/*") 566 if cpdict is not None: 567 v = cpdict.pop("*/*", None) 568 if v is not None: 569 ret = " ".join(v) 570 if old: 571 ret = old + " " + ret 572 if not cpdict: 573 #No tokens left in atom_license_map, remove it. 574 del self._pusedict["*/*"] 575 return ret
576