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), 243 recursive=1, newlines=1, allow_wildcard=True, 244 allow_repo=True, verify_eapi=False, 245 allow_build_id=True) 246 for k, v in pusedict.items(): 247 l = [] 248 use_expand_prefix = '' 249 for flag in v: 250 if flag == "\n": 251 use_expand_prefix = "" 252 continue 253 if flag[-1] == ":": 254 use_expand_prefix = flag[:-1].lower() + "_" 255 continue 256 if flag[0] == "-": 257 nv = "-" + use_expand_prefix + flag[1:] 258 else: 259 nv = use_expand_prefix + flag 260 l.append(nv) 261 ret.setdefault(k.cp, {})[k] = tuple(l) 262 263 return ret
264
265 - def _parse_repository_files_to_dict_of_tuples(self, file_name, repositories, eapi_filter=None):
266 ret = {} 267 for repo in repositories.repos_with_profiles(): 268 ret[repo.name] = self._parse_file_to_tuple( 269 os.path.join(repo.location, "profiles", file_name), 270 eapi_filter=eapi_filter, eapi_default=repo.eapi) 271 return ret
272
273 - def _parse_repository_files_to_dict_of_dicts(self, file_name, repositories, eapi_filter=None):
274 ret = {} 275 for repo in repositories.repos_with_profiles(): 276 ret[repo.name] = self._parse_file_to_dict( 277 os.path.join(repo.location, "profiles", file_name), 278 eapi_filter=eapi_filter, eapi_default=repo.eapi, 279 allow_build_id=("build-id" in repo.profile_formats)) 280 return ret
281
282 - def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations, 283 eapi_filter=None):
284 return tuple(self._parse_file_to_tuple( 285 os.path.join(profile.location, file_name), 286 recursive=profile.portage1_directories, 287 eapi_filter=eapi_filter, eapi=profile.eapi, 288 eapi_default=None) for profile in locations)
289
290 - def _parse_profile_files_to_tuple_of_dicts(self, file_name, locations, 291 juststrings=False, eapi_filter=None):
292 return tuple(self._parse_file_to_dict( 293 os.path.join(profile.location, file_name), juststrings, 294 recursive=profile.portage1_directories, eapi_filter=eapi_filter, 295 user_config=profile.user_config, eapi=profile.eapi, 296 eapi_default=None, allow_build_id=profile.allow_build_id) 297 for profile in locations)
298
299 - def _parse_repository_usealiases(self, repositories):
300 ret = {} 301 for repo in repositories.repos_with_profiles(): 302 file_name = os.path.join(repo.location, "profiles", "use.aliases") 303 eapi = read_corresponding_eapi_file( 304 file_name, default=repo.eapi) 305 useflag_re = _get_useflag_re(eapi) 306 raw_file_dict = grabdict(file_name, recursive=True) 307 file_dict = {} 308 for real_flag, aliases in raw_file_dict.items(): 309 if useflag_re.match(real_flag) is None: 310 writemsg(_("--- Invalid real USE flag in '%s': '%s'\n") % (file_name, real_flag), noiselevel=-1) 311 else: 312 for alias in aliases: 313 if useflag_re.match(alias) is None: 314 writemsg(_("--- Invalid USE flag alias for '%s' real USE flag in '%s': '%s'\n") % 315 (real_flag, file_name, alias), noiselevel=-1) 316 else: 317 if any(alias in v for k, v in file_dict.items() if k != real_flag): 318 writemsg(_("--- Duplicated USE flag alias in '%s': '%s'\n") % 319 (file_name, alias), noiselevel=-1) 320 else: 321 file_dict.setdefault(real_flag, []).append(alias) 322 ret[repo.name] = file_dict 323 return ret
324
325 - def _parse_repository_packageusealiases(self, repositories):
326 ret = {} 327 for repo in repositories.repos_with_profiles(): 328 file_name = os.path.join(repo.location, "profiles", "package.use.aliases") 329 eapi = read_corresponding_eapi_file( 330 file_name, default=repo.eapi) 331 useflag_re = _get_useflag_re(eapi) 332 lines = grabfile(file_name, recursive=True) 333 file_dict = {} 334 for line in lines: 335 elements = line.split() 336 atom = elements[0] 337 try: 338 atom = Atom(atom, eapi=eapi) 339 except InvalidAtom: 340 writemsg(_("--- Invalid atom in '%s': '%s'\n") % (file_name, atom)) 341 continue 342 if len(elements) == 1: 343 writemsg(_("--- Missing real USE flag for '%s' in '%s'\n") % (atom, file_name), noiselevel=-1) 344 continue 345 real_flag = elements[1] 346 if useflag_re.match(real_flag) is None: 347 writemsg(_("--- Invalid real USE flag for '%s' in '%s': '%s'\n") % (atom, file_name, real_flag), noiselevel=-1) 348 else: 349 for alias in elements[2:]: 350 if useflag_re.match(alias) is None: 351 writemsg(_("--- Invalid USE flag alias for '%s' real USE flag for '%s' in '%s': '%s'\n") % 352 (real_flag, atom, file_name, alias), noiselevel=-1) 353 else: 354 # Duplicated USE flag aliases in entries for different atoms 355 # matching the same package version are detected in getUseAliases(). 356 if any(alias in v for k, v in file_dict.get(atom.cp, {}).get(atom, {}).items() if k != real_flag): 357 writemsg(_("--- Duplicated USE flag alias for '%s' in '%s': '%s'\n") % 358 (atom, file_name, alias), noiselevel=-1) 359 else: 360 file_dict.setdefault(atom.cp, {}).setdefault(atom, {}).setdefault(real_flag, []).append(alias) 361 ret[repo.name] = file_dict 362 return ret
363
364 - def _isStable(self, pkg):
365 if self._user_config: 366 try: 367 return pkg.stable 368 except AttributeError: 369 # KEYWORDS is unavailable (prior to "depend" phase) 370 return False 371 372 try: 373 pkg._metadata 374 except AttributeError: 375 # KEYWORDS is unavailable (prior to "depend" phase) 376 return False 377 378 # Since repoman uses different config instances for 379 # different profiles, we have to be careful to do the 380 # stable check against the correct profile here. 381 return self._is_stable(pkg)
382
383 - def getUseMask(self, pkg=None, stable=None):
384 if pkg is None: 385 return frozenset(stack_lists( 386 self._usemask_list, incremental=True)) 387 388 slot = None 389 cp = getattr(pkg, "cp", None) 390 if cp is None: 391 slot = dep_getslot(pkg) 392 repo = dep_getrepo(pkg) 393 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 394 cp = pkg.cp 395 396 if stable is None: 397 stable = self._isStable(pkg) 398 399 usemask = [] 400 401 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: 402 repos = [] 403 try: 404 repos.extend(repo.name for repo in 405 self.repositories[pkg.repo].masters) 406 except KeyError: 407 pass 408 repos.append(pkg.repo) 409 for repo in repos: 410 usemask.append(self._repo_usemask_dict.get(repo, {})) 411 if stable: 412 usemask.append(self._repo_usestablemask_dict.get(repo, {})) 413 cpdict = self._repo_pusemask_dict.get(repo, {}).get(cp) 414 if cpdict: 415 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 416 if pkg_usemask: 417 usemask.extend(pkg_usemask) 418 if stable: 419 cpdict = self._repo_pusestablemask_dict.get(repo, {}).get(cp) 420 if cpdict: 421 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 422 if pkg_usemask: 423 usemask.extend(pkg_usemask) 424 425 for i, pusemask_dict in enumerate(self._pusemask_list): 426 if self._usemask_list[i]: 427 usemask.append(self._usemask_list[i]) 428 if stable and self._usestablemask_list[i]: 429 usemask.append(self._usestablemask_list[i]) 430 cpdict = pusemask_dict.get(cp) 431 if cpdict: 432 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 433 if pkg_usemask: 434 usemask.extend(pkg_usemask) 435 if stable: 436 cpdict = self._pusestablemask_list[i].get(cp) 437 if cpdict: 438 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) 439 if pkg_usemask: 440 usemask.extend(pkg_usemask) 441 442 return frozenset(stack_lists(usemask, incremental=True))
443
444 - def getUseForce(self, pkg=None, stable=None):
445 if pkg is None: 446 return frozenset(stack_lists( 447 self._useforce_list, incremental=True)) 448 449 cp = getattr(pkg, "cp", None) 450 if cp is None: 451 slot = dep_getslot(pkg) 452 repo = dep_getrepo(pkg) 453 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 454 cp = pkg.cp 455 456 if stable is None: 457 stable = self._isStable(pkg) 458 459 useforce = [] 460 461 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: 462 repos = [] 463 try: 464 repos.extend(repo.name for repo in 465 self.repositories[pkg.repo].masters) 466 except KeyError: 467 pass 468 repos.append(pkg.repo) 469 for repo in repos: 470 useforce.append(self._repo_useforce_dict.get(repo, {})) 471 if stable: 472 useforce.append(self._repo_usestableforce_dict.get(repo, {})) 473 cpdict = self._repo_puseforce_dict.get(repo, {}).get(cp) 474 if cpdict: 475 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 476 if pkg_useforce: 477 useforce.extend(pkg_useforce) 478 if stable: 479 cpdict = self._repo_pusestableforce_dict.get(repo, {}).get(cp) 480 if cpdict: 481 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 482 if pkg_useforce: 483 useforce.extend(pkg_useforce) 484 485 for i, puseforce_dict in enumerate(self._puseforce_list): 486 if self._useforce_list[i]: 487 useforce.append(self._useforce_list[i]) 488 if stable and self._usestableforce_list[i]: 489 useforce.append(self._usestableforce_list[i]) 490 cpdict = puseforce_dict.get(cp) 491 if cpdict: 492 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 493 if pkg_useforce: 494 useforce.extend(pkg_useforce) 495 if stable: 496 cpdict = self._pusestableforce_list[i].get(cp) 497 if cpdict: 498 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) 499 if pkg_useforce: 500 useforce.extend(pkg_useforce) 501 502 return frozenset(stack_lists(useforce, incremental=True))
503
504 - def getUseAliases(self, pkg):
505 if hasattr(pkg, "eapi") and not eapi_has_use_aliases(pkg.eapi): 506 return {} 507 508 cp = getattr(pkg, "cp", None) 509 if cp is None: 510 slot = dep_getslot(pkg) 511 repo = dep_getrepo(pkg) 512 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 513 cp = pkg.cp 514 515 usealiases = {} 516 517 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: 518 repos = [] 519 try: 520 repos.extend(repo.name for repo in 521 self.repositories[pkg.repo].masters) 522 except KeyError: 523 pass 524 repos.append(pkg.repo) 525 for repo in repos: 526 usealiases_dict = self._repo_usealiases_dict.get(repo, {}) 527 for real_flag, aliases in usealiases_dict.items(): 528 for alias in aliases: 529 if any(alias in v for k, v in usealiases.items() if k != real_flag): 530 writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") % 531 (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1) 532 else: 533 usealiases.setdefault(real_flag, []).append(alias) 534 cp_usealiases_dict = self._repo_pusealiases_dict.get(repo, {}).get(cp) 535 if cp_usealiases_dict: 536 usealiases_dict_list = ordered_by_atom_specificity(cp_usealiases_dict, pkg) 537 for usealiases_dict in usealiases_dict_list: 538 for real_flag, aliases in usealiases_dict.items(): 539 for alias in aliases: 540 if any(alias in v for k, v in usealiases.items() if k != real_flag): 541 writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") % 542 (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1) 543 else: 544 usealiases.setdefault(real_flag, []).append(alias) 545 546 return usealiases
547
548 - def getPUSE(self, pkg):
549 cp = getattr(pkg, "cp", None) 550 if cp is None: 551 slot = dep_getslot(pkg) 552 repo = dep_getrepo(pkg) 553 pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) 554 cp = pkg.cp 555 ret = "" 556 cpdict = self._pusedict.get(cp) 557 if cpdict: 558 puse_matches = ordered_by_atom_specificity(cpdict, pkg) 559 if puse_matches: 560 puse_list = [] 561 for x in puse_matches: 562 puse_list.extend(x) 563 ret = " ".join(puse_list) 564 return ret
565
566 - def extract_global_USE_changes(self, old=""):
567 ret = old 568 cpdict = self._pusedict.get("*/*") 569 if cpdict is not None: 570 v = cpdict.pop("*/*", None) 571 if v is not None: 572 ret = " ".join(v) 573 if old: 574 ret = old + " " + ret 575 if not cpdict: 576 #No tokens left in atom_license_map, remove it. 577 del self._pusedict["*/*"] 578 return ret
579