Improved profiles/p.mask handling
authorSebastian Luther <SebastianLuther@gmx.de>
Sat, 25 Sep 2010 14:20:48 +0000 (16:20 +0200)
committerZac Medico <zmedico@gentoo.org>
Mon, 27 Sep 2010 06:50:15 +0000 (23:50 -0700)
It's now possible for an repo to revert masks from the master for its own packages.

pym/portage/package/ebuild/_config/LocationsManager.py
pym/portage/package/ebuild/_config/MaskManager.py
pym/portage/package/ebuild/config.py
pym/portage/repository/config.py
pym/portage/util/__init__.py

index 83d61050f36172ed480ac29b4b48becaddf02c8f..b857f32622d0ddefb1065d55b5b62fc4574b40ea 100644 (file)
@@ -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),
-               )
index c06e346634a8086a8d2927173898776ac583749b..f41636b48f89c9357403e44297c140d4243ad962 100644 (file)
@@ -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)
index e6e5d01c73af6bb9387b4f73b7393a8e8c3e1867..477444b3cf1b9b951b592f2657f0edccfdb8cc18 100644 (file)
@@ -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)
 
index 7f0d392a5145c9ad1d81d7c9a615238a62bd64e1..0d44120820c27a9a4daa6064333320d06cff1860 100644 (file)
@@ -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"],
index 0b0e0435e7777f34eb1cc5bee20a8d562b21b9e9..0c2dc3382a7b7c1efa3e7f2de5be2e7a64e591a3 100644 (file)
@@ -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):