From 03e4da855927aa69687acad97246be50096b6b00 Mon Sep 17 00:00:00 2001 From: Sebastian Luther Date: Sat, 25 Sep 2010 16:20:48 +0200 Subject: Improved profiles/p.mask handling It's now possible for an repo to revert masks from the master for its own packages. --- .../package/ebuild/_config/LocationsManager.py | 5 -- pym/portage/package/ebuild/_config/MaskManager.py | 53 +++++++++++++--------- pym/portage/package/ebuild/config.py | 2 +- pym/portage/repository/config.py | 17 ++++++- pym/portage/util/__init__.py | 35 ++++++++++++-- 5 files changed, 80 insertions(+), 32 deletions(-) diff --git a/pym/portage/package/ebuild/_config/LocationsManager.py b/pym/portage/package/ebuild/_config/LocationsManager.py index 83d61050f..b857f3262 100644 --- a/pym/portage/package/ebuild/_config/LocationsManager.py +++ b/pym/portage/package/ebuild/_config/LocationsManager.py @@ -176,8 +176,3 @@ class LocationsManager(object): self.profile_locations = tuple(self.profile_locations) self.profile_and_user_locations = tuple(self.profile_and_user_locations) - - self.pmask_locations = ( - tuple([os.path.join(portdir, "profiles")] + self.overlay_profiles), - tuple(self.profiles), - ) diff --git a/pym/portage/package/ebuild/_config/MaskManager.py b/pym/portage/package/ebuild/_config/MaskManager.py index c06e34663..f41636b48 100644 --- a/pym/portage/package/ebuild/_config/MaskManager.py +++ b/pym/portage/package/ebuild/_config/MaskManager.py @@ -5,38 +5,49 @@ __all__ = ( 'MaskManager', ) -from itertools import chain from portage import os from portage.dep import ExtendedAtomDict, match_from_list, _repo_separator, _slot_separator -from portage.util import grabfile_package, stack_lists +from portage.util import append_repo, grabfile_package, stack_lists from portage.versions import cpv_getkey class MaskManager(object): - def __init__(self, pmask_locations, abs_user_config, + def __init__(self, repositories, profiles, abs_user_config, user_config=True, strict_umatched_removal=False): self._punmaskdict = ExtendedAtomDict(list) self._pmaskdict = ExtendedAtomDict(list) - repo_profiles, profiles = pmask_locations + #Read profile/package.mask form every repo. + #Repositories inherit masks from their parent profiles and + #are able to remove mask from them with -atoms. + #Such a removal affects only the current repo, but not the parent. + #Add ::repo specs to every atom to make sure atoms only affect + #packages from the current repo. - #Read profile/package.mask form every repo. Stack them immediately - #to make sure that -atoms don't effect other repos. repo_pkgmasklines = [] - repo_pkgunmasklines = [] - for x in repo_profiles: - repo_pkgmasklines.append(stack_lists([grabfile_package( - os.path.join(x, "package.mask"), recursive=1, remember_source_file=True, verify_eapi=True)], \ - incremental=1, remember_source_file=True, - warn_for_unmatched_removal=True, + for repo in repositories.repos_with_profiles(): + lines = [] + repo_lines = grabfile_package(os.path.join(repo.location, "profiles", "package.mask"), \ + recursive=1, remember_source_file=True, verify_eapi=True) + masters = repo.masters + if masters is None: + masters = [repositories.mainRepo()] + for master in masters: + master_lines = grabfile_package(os.path.join(master.location, "profiles", "package.mask"), \ + recursive=1, remember_source_file=True, verify_eapi=True) + lines.append(stack_lists([master_lines, repo_lines], incremental=1, + remember_source_file=True, warn_for_unmatched_removal=True, strict_warn_for_unmatched_removal=strict_umatched_removal)) - repo_pkgunmasklines.append(stack_lists([grabfile_package( - os.path.join(x, "package.unmask"), recursive=1, remember_source_file=True, verify_eapi=True)], \ - incremental=1, remember_source_file=True, - warn_for_unmatched_removal=True, - strict_warn_for_unmatched_removal=strict_umatched_removal)) - repo_pkgmasklines = list(chain.from_iterable(repo_pkgmasklines)) - repo_pkgunmasklines = list(chain.from_iterable(repo_pkgunmasklines)) + repo_pkgmasklines.extend(append_repo(stack_lists(lines), repo.name, remember_source_file=True)) + + repo_pkgunmasklines = [] + for repo in repositories.repos_with_profiles(): + repo_lines = grabfile_package(os.path.join(repo.location, "profiles", "package.unmask"), \ + recursive=1, remember_source_file=True, verify_eapi=True) + lines = stack_lists([repo_lines], incremental=1, \ + remember_source_file=True, warn_for_unmatched_removal=True, + strict_warn_for_unmatched_removal=strict_umatched_removal) + repo_pkgmasklines.extend(append_repo(lines, repo.name)) #Read package.mask form the user's profile. Stack them in the end #to allow profiles to override masks from their parent profiles. @@ -69,9 +80,9 @@ class MaskManager(object): #Stack everything together. At this point, only user_pkgmasklines may contain -atoms. #Don't warn for unmatched -atoms here, since we don't do it for any other user config file. pkgmasklines = stack_lists([repo_pkgmasklines, profile_pkgmasklines, user_pkgmasklines], \ - incremental=1, remember_source_file=True, warn_for_unmatched_removal=False) + incremental=1, remember_source_file=True, warn_for_unmatched_removal=False, ignore_repo=True) pkgunmasklines = stack_lists([repo_pkgunmasklines, profile_pkgunmasklines, user_pkgunmasklines], \ - incremental=1, remember_source_file=True, warn_for_unmatched_removal=False) + incremental=1, remember_source_file=True, warn_for_unmatched_removal=False, ignore_repo=True) for x, source_file in pkgmasklines: self._pmaskdict.setdefault(x.cp, []).append(x) diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py index e6e5d01c7..477444b3c 100644 --- a/pym/portage/package/ebuild/config.py +++ b/pym/portage/package/ebuild/config.py @@ -558,7 +558,7 @@ class config(object): self.configdict["conf"].get("ACCEPT_LICENSE", "")) #Read package.mask and package.unmask from profiles and optionally from user config - self._mask_manager = MaskManager(locations_manager.pmask_locations, + self._mask_manager = MaskManager(self.repositories, self.profiles, abs_user_config, user_config=local_config, strict_umatched_removal=_unmatched_removal) diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py index 7f0d392a5..0d4412082 100644 --- a/pym/portage/repository/config.py +++ b/pym/portage/repository/config.py @@ -17,7 +17,7 @@ import codecs class RepoConfig(object): """Stores config of one repository""" __slots__ = ['aliases', 'eclass_overrides', 'location', 'masters', 'main_repo', - 'missing_repo_name', 'name', 'priority', 'sync'] + 'missing_repo_name', 'name', 'priority', 'sync', 'format'] def __init__(self, name, repo_opts): """Build a RepoConfig with options in repo_opts Try to read repo_name in repository location, but if @@ -52,6 +52,11 @@ class RepoConfig(object): sync = sync.strip() self.sync = sync + format = repo_opts.get('format') + if format is not None: + format = format.strip() + self.format = format + self.missing_repo_name = False location = repo_opts.get('location') @@ -236,6 +241,10 @@ class RepoConfigLoader(object): else: return '' + def mainRepo(self): + """Returns the main repo""" + return self.prepos[self.prepos['DEFAULT'].main_repo] + def _check_locations(self): """Check if repositories location are correct and show a warning message if not""" for (name, r) in self.prepos.items(): @@ -248,6 +257,12 @@ class RepoConfigLoader(object): writemsg(_("!!! Invalid Repository Location" " (not a dir): '%s'\n") % r.location, noiselevel=-1) + def repos_with_profiles(self): + for repo_name in self.prepos_order: + repo = self.prepos[repo_name] + if repo.format != "unavailable": + yield repo + def load_repository_config(settings): #~ repoconfigpaths = [os.path.join(settings.global_config_path, "repos.conf")] #~ repoconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], diff --git a/pym/portage/util/__init__.py b/pym/portage/util/__init__.py index 0b0e0435e..0c2dc3382 100644 --- a/pym/portage/util/__init__.py +++ b/pym/portage/util/__init__.py @@ -231,8 +231,19 @@ def stack_dicts(dicts, incremental=0, incrementals=[], ignore_none=0): final_dict[k] = v return final_dict +def append_repo(atom_list, repo_name, remember_source_file=False): + """ + Takes a list of valid atoms without repo spec and appends ::repo_name. + """ + if remember_source_file: + return [(Atom(atom + "::" + repo_name, allow_wildcard=True, allow_repo=True), source) \ + for atom, source in atom_list] + else: + return [Atom(atom + "::" + repo_name, allow_wildcard=True, allow_repo=True) \ + for atom in atom_list] + def stack_lists(lists, incremental=1, remember_source_file=False, - warn_for_unmatched_removal=False, strict_warn_for_unmatched_removal=False): + warn_for_unmatched_removal=False, strict_warn_for_unmatched_removal=False, ignore_repo=False): """Stacks an array of list-types into one array. Optionally removing distinct values using '-value' notation. Higher index is preferenced. @@ -255,9 +266,25 @@ def stack_lists(lists, incremental=1, remember_source_file=False, if token == "-*": new_list.clear() elif token[:1] == '-': - try: - new_list.pop(token[1:]) - except KeyError: + matched = False + if ignore_repo and not "::" in token: + #Let -cat/pkg remove cat/pkg::repo. + to_be_removed = [] + for atom in new_list: + if atom == token[1:] or atom.split("::")[0] == token[1:]: + to_be_removed.append(atom) + if to_be_removed: + matched = True + for atom in to_be_removed: + new_list.pop(atom) + else: + try: + new_list.pop(token[1:]) + matched = True + except KeyError: + pass + + if not matched: if source_file and \ (strict_warn_for_unmatched_removal or \ token_key not in matched_removals): -- cgit v1.2.3-1-g7c22