Add support for the following attributes in layout.conf to allow more
authorArfrever Frehtes Taifersar Arahesis <Arfrever@Apache.Org>
Sat, 18 Jan 2014 11:33:01 +0000 (12:33 +0100)
committerArfrever Frehtes Taifersar Arahesis <Arfrever@Apache.Org>
Sat, 18 Jan 2014 11:33:01 +0000 (12:33 +0100)
precise configuration of inheritance of settings from repositories:
  eclass-masters
  package.mask-masters
  use.aliases-masters
  use.force-masters
  use.mask-masters

man/portage.5
pym/portage/package/ebuild/_config/MaskManager.py
pym/portage/package/ebuild/_config/UseManager.py
pym/portage/package/ebuild/getmaskingreason.py
pym/portage/repository/config.py

index 0aac56947ba8f1195f1a86c4c3f77ac25e68d2bd..50905291cd25feb5ae861c7955dc32265d787d50 100644 (file)
@@ -800,7 +800,9 @@ since operations performed by these tools are inherently
 Specifies names of attributes, which should be forcefully respected by
 \fBegencache\fR(1), \fBemirrordist\fR(1) and \fBrepoman\fR(1).
 .br
-Valid values: aliases, eclass\-overrides, masters
+Valid values: aliases, eclass\-masters, eclass\-overrides, masters,
+package.mask\-masters, use.aliases\-masters, use.force\-masters,
+use.mask\-masters
 .RE
 
 .I Attributes supported in sections of repositories:
@@ -834,21 +836,24 @@ since operations performed by these tools are inherently
 Specifies names of attributes, which should be forcefully respected by
 \fBegencache\fR(1), \fBemirrordist\fR(1) and \fBrepoman\fR(1).
 .br
-Valid values: aliases, eclass\-overrides, masters
+Valid values: aliases, eclass\-masters, eclass\-overrides, masters,
+package.mask\-masters, use.aliases\-masters, use.force\-masters,
+use.mask\-masters
 .TP
 .B location
 Specifies location of given repository.
 .TP
-.B masters
-Specifies master repositories of given repository.
+.B masters, eclass\-masters, package.mask\-masters, use.aliases\-masters, use.force\-masters, use.mask\-masters
+Specifies master repositories of given repository. See documentation of
+\fBlayout.conf\fR file for more details.
 .br
-Setting this attribute is generally not recommended since resulting changes
+Setting these attribute is generally not recommended since resulting changes
 in eclass inheritance may trigger performance issues due to invalidation
 of metadata cache.
 .br
-When 'force = masters' attribute is not set, \fBegencache\fR(1),
-\fBemirrordist\fR(1) and \fBrepoman\fR(1) ignore this attribute,
-since operations performed by these tools are inherently
+When 'force = ${attribute}' (e.g. 'force = masters') attribute is not set,
+\fBegencache\fR(1), \fBemirrordist\fR(1) and \fBrepoman\fR(1) ignore given
+attribute, since operations performed by these tools are inherently
 \fBnot\fR \fIsite\-specific\fR.
 .TP
 .B priority
@@ -986,9 +991,10 @@ Specifies information about the repository layout.
 \fB/etc/portage/repos.conf\fR.
 Settings in \fBrepos.conf\fR take precedence over settings in
 \fBlayout.conf\fR, except tools such as \fBrepoman\fR(1) and \fBegencache\fR(1)
-ignore "aliases", "eclass-overrides" and "masters" attributes set in
-\fBrepos.conf\fR since their operations are inherently \fBnot\fR
-\fIsite\-specific\fR.
+ignore "aliases", "eclass\-masters", "eclass\-overrides", "masters",
+"package.mask\-masters", "use.aliases\-masters", "use.force\-masters" and
+"use.mask\-masters" attributes set in \fBrepos.conf\fR since their operations
+are inherently \fBnot\fR \fIsite\-specific\fR.
 
 .I Format:
 .nf
@@ -996,7 +1002,7 @@ ignore "aliases", "eclass-overrides" and "masters" attributes set in
 \- attributes are specified in "${attribute} = ${value}" format
 .fi
 
-.I Supported attributes.
+.I Supported attributes:
 .RS
 .RS
 .TP
@@ -1009,6 +1015,14 @@ List of EAPIs which are not allowed in this repo.
 .BR eapis\-deprecated
 List of EAPIs which are allowed but generate warnings when used.
 .TP
+.BR eclass\-masters
+Names of repositories wherefrom eclasses can be inherited.
+.br
+This attribute overrides \fBmasters\fR attribute and should be used only when
+there is a need to set this attribute to a different value than value of
+\fBmasters\fR attribute. See documentation of \fBmasters\fR attribute for more
+details.
+.TP
 .BR masters
 Names of repositories which satisfy dependencies on eclasses and from which
 settings specified in various repository\-level files (\fBpackage.mask\fR,
@@ -1018,6 +1032,15 @@ the repositories that is configured in \fBrepos.conf\fR file. Repositories
 listed toward the right of the \fBmasters\fR list take precedence over those
 listed toward the left of the list.
 .TP
+.BR package.mask-masters
+Names of repositories wherefrom settings specified in repository\-level
+\fBpackage.mask\fR files are inherited.
+.br
+This attribute overrides \fBmasters\fR attribute and should be used only when
+there is a need to set this attribute to a different value than value of
+\fBmasters\fR attribute. See documentation of \fBmasters\fR attribute for more
+details.
+.TP
 .BR repo\-name " = <value of profiles/repo_name>"
 The name of this repository (overrides profiles/repo_name if it exists).
 .TP
@@ -1030,6 +1053,35 @@ Boolean value whether we should sign Manifest files in this repo.
 .BR thin\-manifests " = [true|" false "]"
 Boolean value whether Manifest files contain only DIST entries.
 .TP
+.BR use.aliases\-masters
+Names of repositories wherefrom settings specified in repository\-level
+\fBpackage.use.aliases\fR and \fBuse.aliases\fR files are inherited.
+.br
+This attribute overrides \fBmasters\fR attribute and should be used only when
+there is a need to set this attribute to a different value than value of
+\fBmasters\fR attribute. See documentation of \fBmasters\fR attribute for more
+details.
+.TP
+.BR use.force\-masters
+Names of repositories wherefrom settings specified in repository\-level
+\fBpackage.use.force\fR, \fBpackage.use.stable.force\fR, \fBuse.force\fR and
+\fBuse.stable.force\fR files are inherited.
+.br
+This attribute overrides \fBmasters\fR attribute and should be used only when
+there is a need to set this attribute to a different value than value of
+\fBmasters\fR attribute. See documentation of \fBmasters\fR attribute for more
+details.
+.TP
+.BR use.mask\-masters
+Names of repositories wherefrom settings specified in repository\-level
+\fBpackage.use.mask\fR, \fBpackage.use.stable.mask\fR, \fuse.mask\fR and
+\fBuse.stable.mask\fR files are inherited.
+.br
+This attribute overrides \fBmasters\fR attribute and should be used only when
+there is a need to set this attribute to a different value than value of
+\fBmasters\fR attribute. See documentation of \fBmasters\fR attribute for more
+details.
+.TP
 .BR use\-manifests " = [" strict "|true|false]"
 How Manifest files get used.  Possible values are "strict" (require an entry
 for every file), "true" (if an entry exists for a file, enforce it), or "false"
index aeb04d7c8f3eb6b8b1900121f8af6083936b8009..4358b63e165a88e43171f3a5ca16273b8c3a0a8a 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2010-2013 Gentoo Foundation
+# Copyright 2010-2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 __all__ = (
@@ -58,7 +58,11 @@ class MaskManager(object):
                        removals = frozenset(line[0][1:] for line in repo_lines
                                if line[0][:1] == "-")
                        matched_removals = set()
-                       for master in repo.masters:
+                       if repo.package_mask_masters is not None:
+                               masters = repo.package_mask_masters
+                       else:
+                               masters = repo.masters
+                       for master in masters:
                                master_lines = grab_pmask(master.location, master)
                                for line in master_lines:
                                        if line[0] in removals:
@@ -75,7 +79,7 @@ class MaskManager(object):
                        # It's safe to warn for unmatched removal if masters have not
                        # been overridden by the user, which is guaranteed when
                        # user_config is false (when called by repoman).
-                       if repo.masters:
+                       if masters:
                                unmatched_removals = removals.difference(matched_removals)
                                if unmatched_removals and not user_config:
                                        source_file = os.path.join(repo.location,
index 0d00810b6af7593eece1c81d8ad72f1f25b7dce0..a65e5bd6386ddf230e7391ea1de87b8feaa70028 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2010-2013 Gentoo Foundation
+# Copyright 2010-2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 __all__ = (
@@ -312,8 +312,11 @@ class UseManager(object):
                if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
                        repos = []
                        try:
-                               repos.extend(repo.name for repo in
-                                       self.repositories[pkg.repo].masters)
+                               if self.repositories[pkg.repo].use_mask_masters is not None:
+                                       masters = self.repositories[pkg.repo].use_mask_masters
+                               else:
+                                       masters = self.repositories[pkg.repo].masters
+                               repos.extend(repo.name for repo in masters)
                        except KeyError:
                                pass
                        repos.append(pkg.repo)
@@ -372,8 +375,11 @@ class UseManager(object):
                if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
                        repos = []
                        try:
-                               repos.extend(repo.name for repo in
-                                       self.repositories[pkg.repo].masters)
+                               if self.repositories[pkg.repo].use_force_masters is not None:
+                                       masters = self.repositories[pkg.repo].use_force_masters
+                               else:
+                                       masters = self.repositories[pkg.repo].masters
+                               repos.extend(repo.name for repo in masters)
                        except KeyError:
                                pass
                        repos.append(pkg.repo)
@@ -428,8 +434,11 @@ class UseManager(object):
                if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
                        repos = []
                        try:
-                               repos.extend(repo.name for repo in
-                                       self.repositories[pkg.repo].masters)
+                               if self.repositories[pkg.repo].use_aliases_masters is not None:
+                                       masters = self.repositories[pkg.repo].use_aliases_masters
+                               else:
+                                       masters = self.repositories[pkg.repo].masters
+                               repos.extend(repo.name for repo in masters)
                        except KeyError:
                                pass
                        repos.append(pkg.repo)
index 70a6bf2e611675055da15984eb4d12e8f849dfb4..673b40ac984394e82136c6b74ec388099509596f 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2010-2013 Gentoo Foundation
+# Copyright 2010-2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 __all__ = ['getmaskingreason']
@@ -70,7 +70,11 @@ def getmaskingreason(mycpv, metadata=None, settings=None,
 
        locations = []
        if pkg.repo in settings.repositories:
-               for repo in settings.repositories[pkg.repo].masters + (settings.repositories[pkg.repo],):
+               if settings.repositories[pkg.repo].package_mask_masters is not None:
+                       masters = settings.repositories[pkg.repo].package_mask_masters
+               else:
+                       masters = settings.repositories[pkg.repo].masters
+               for repo in masters + (settings.repositories[pkg.repo],):
                        locations.append(os.path.join(repo.location, "profiles"))
        locations.extend(settings.profiles)
        locations.append(os.path.join(settings["PORTAGE_CONFIGROOT"],
index 71b75fb5f3b780be7f6edd3540dacca3210a8275..b7ee34f5abbf53f4599059946b840709f1b1d123 100644 (file)
@@ -44,6 +44,9 @@ _valid_profile_formats = frozenset(
 _portage1_profiles_allow_directories = frozenset(
        ["portage-1-compat", "portage-1", 'portage-2'])
 
+_masters_attributes = dict((x, x.replace("-", "_").replace(".", "_")) for x in
+       ("masters", "eclass-masters", "package.mask-masters", "use.aliases-masters", "use.force-masters", "use.mask-masters"))
+
 _repo_name_sub_re = re.compile(r'[^\w-]')
 
 def _gen_valid_repo(name):
@@ -80,11 +83,12 @@ class RepoConfig(object):
                'cache_formats', 'create_manifest', 'disable_manifest', 'eapi',
                'eclass_db', 'eclass_locations', 'eclass_overrides',
                'find_invalid_path_char', 'force', 'format', 'local_config', 'location',
-               'main_repo', 'manifest_hashes', 'masters', 'missing_repo_name',
+               'main_repo', 'manifest_hashes', 'missing_repo_name',
                'name', 'portage1_profiles', 'portage1_profiles_compat', 'priority',
                'profile_formats', 'sign_commit', 'sign_manifest', 'sync_cvs_repo',
                'sync_type', 'sync_uri', 'thin_manifest', 'update_changelog',
-               'user_location', '_eapis_banned', '_eapis_deprecated', '_masters_orig')
+               'user_location', '_eapis_banned', '_eapis_deprecated', '_masters_orig') + \
+               tuple(_masters_attributes.values())
 
        def __init__(self, name, repo_opts, local_config=True):
                """Build a RepoConfig with options in repo_opts
@@ -106,7 +110,6 @@ class RepoConfig(object):
                                aliases = tuple(aliases.split())
                else:
                        aliases = None
-
                self.aliases = aliases
 
                if local_config or 'eclass-overrides' in force:
@@ -115,21 +118,21 @@ class RepoConfig(object):
                                eclass_overrides = tuple(eclass_overrides.split())
                else:
                        eclass_overrides = None
-
                self.eclass_overrides = eclass_overrides
+
                # Eclass databases and locations are computed later.
                self.eclass_db = None
                self.eclass_locations = None
 
-               if local_config or 'masters' in force:
-                       # Masters from repos.conf override layout.conf.
-                       masters = repo_opts.get('masters')
-                       if masters is not None:
-                               masters = tuple(masters.split())
-               else:
-                       masters = None
-
-               self.masters = masters
+               for attr, underscorized_attr in _masters_attributes.items():
+                       if local_config or attr in force:
+                               # Masters from repos.conf override layout.conf.
+                               masters = repo_opts.get(attr)
+                               if masters is not None:
+                                       masters = tuple(masters.split())
+                       else:
+                               masters = None
+                       setattr(self, underscorized_attr, masters)
 
                #The main-repo key makes only sense for the 'DEFAULT' section.
                self.main_repo = repo_opts.get('main-repo')
@@ -216,8 +219,9 @@ class RepoConfig(object):
 
                        # layout.conf masters may be overridden here if we have a masters
                        # setting from the user's repos.conf
-                       if self.masters is None:
-                               self.masters = layout_data['masters']
+                       for attr, underscorized_attr in _masters_attributes.items():
+                               if getattr(self, underscorized_attr) is None:
+                                       setattr(self, underscorized_attr, layout_data[attr])
 
                        if (local_config or 'aliases' in force) and layout_data['aliases']:
                                aliases = self.aliases
@@ -370,8 +374,10 @@ class RepoConfig(object):
                        repo_msg.append(indent + "sync-type: " + self.sync_type)
                if self.sync_uri:
                        repo_msg.append(indent + "sync-uri: " + self.sync_uri)
-               if self.masters:
-                       repo_msg.append(indent + "masters: " + " ".join(master.name for master in self.masters))
+               for attr, underscorized_attr in _masters_attributes.items():
+                       masters = getattr(self, underscorized_attr)
+                       if masters:
+                               repo_msg.append(indent + attr + ": " + " ".join(master.name for master in masters))
                if self.priority is not None:
                        repo_msg.append(indent + "priority: " + str(self.priority))
                if self.aliases:
@@ -743,36 +749,43 @@ class RepoConfigLoader(object):
                for repo_name, repo in prepos.items():
                        if repo_name == "DEFAULT":
                                continue
-                       if repo.masters is None:
-                               if self.mainRepo() and repo_name != self.mainRepo().name:
-                                       repo.masters = self.mainRepo(),
+                       for attr, underscorized_attr in _masters_attributes.items():
+                               masters = getattr(repo, underscorized_attr)
+                               if masters is None:
+                                       if attr == 'masters':
+                                               if self.mainRepo() and repo_name != self.mainRepo().name:
+                                                       setattr(repo, underscorized_attr, (self.mainRepo(),))
+                                               else:
+                                                       setattr(repo, underscorized_attr, ())
                                else:
-                                       repo.masters = ()
-                       else:
-                               if repo.masters and isinstance(repo.masters[0], RepoConfig):
-                                       # This one has already been processed
-                                       # because it has an alias.
-                                       continue
-                               master_repos = []
-                               for master_name in repo.masters:
-                                       if master_name not in prepos:
-                                               layout_filename = os.path.join(repo.user_location,
-                                                       "metadata", "layout.conf")
-                                               writemsg_level(_("Unavailable repository '%s' " \
-                                                       "referenced by masters entry in '%s'\n") % \
-                                                       (master_name, layout_filename),
-                                                       level=logging.ERROR, noiselevel=-1)
-                                       else:
-                                               master_repos.append(prepos[master_name])
-                               repo.masters = tuple(master_repos)
+                                       if masters and isinstance(masters[0], RepoConfig):
+                                               # This one has already been processed
+                                               # because it has an alias.
+                                               continue
+                                       master_repos = []
+                                       for master_name in masters:
+                                               if master_name not in prepos:
+                                                       layout_filename = os.path.join(repo.user_location,
+                                                               "metadata", "layout.conf")
+                                                       writemsg_level(_("Unavailable repository '%s' " \
+                                                               "referenced by %s attribute in '%s'\n") % \
+                                                               (master_name, attr, layout_filename),
+                                                               level=logging.ERROR, noiselevel=-1)
+                                               else:
+                                                       master_repos.append(prepos[master_name])
+                                       setattr(repo, underscorized_attr, tuple(master_repos))
 
                #The 'eclass_overrides' key currently contains repo names. Replace them with the matching repo paths.
                for repo_name, repo in prepos.items():
                        if repo_name == "DEFAULT":
                                continue
 
+                       if repo.eclass_masters is not None:
+                               masters = repo.eclass_masters
+                       else:
+                               masters = repo.masters
                        eclass_locations = []
-                       eclass_locations.extend(master_repo.location for master_repo in repo.masters)
+                       eclass_locations.extend(master_repo.location for master_repo in masters)
                        # Only append the current repo to eclass_locations if it's not
                        # there already. This allows masters to have more control over
                        # eclass override order, which may be useful for scenarios in
@@ -921,23 +934,24 @@ class RepoConfigLoader(object):
                return repo_name in self.prepos
 
        def config_string(self):
-               str_or_int_keys = ("format", "location", "main_repo", "priority", "sync_cvs_repo", "sync_type", "sync_uri")
-               str_tuple_keys = ("aliases", "eclass_overrides", "force")
-               repo_config_tuple_keys = ("masters",)
-               keys = str_or_int_keys + str_tuple_keys + repo_config_tuple_keys
+               str_or_int_attrs = ("format", "location", "main-repo", "priority", "sync-cvs-repo", "sync-type", "sync-uri")
+               str_tuple_attrs = ("aliases", "eclass-overrides", "force")
+               repo_config_tuple_attrs = tuple(_masters_attributes.keys())
+               attrs = str_or_int_attrs + str_tuple_attrs + repo_config_tuple_attrs
                config_string = ""
                for repo_name, repo in sorted(self.prepos.items()):
                        config_string += "\n[%s]\n" % repo_name
-                       for key in sorted(keys):
-                               if key == "main_repo" and repo_name != "DEFAULT":
+                       for attr in sorted(attrs):
+                               underscorized_attr = attr.replace("-", "_").replace(".", "_")
+                               if attr == "main-repo" and repo_name != "DEFAULT":
                                        continue
-                               if getattr(repo, key) is not None:
-                                       if key in str_or_int_keys:
-                                               config_string += "%s = %s\n" % (key.replace("_", "-"), getattr(repo, key))
-                                       elif key in str_tuple_keys:
-                                               config_string += "%s = %s\n" % (key.replace("_", "-"), " ".join(getattr(repo, key)))
-                                       elif key in repo_config_tuple_keys:
-                                               config_string += "%s = %s\n" % (key.replace("_", "-"), " ".join(x.name for x in getattr(repo, key)))
+                               if getattr(repo, underscorized_attr) is not None:
+                                       if attr in str_or_int_attrs:
+                                               config_string += "%s = %s\n" % (attr, getattr(repo, underscorized_attr))
+                                       elif attr in str_tuple_attrs:
+                                               config_string += "%s = %s\n" % (attr, " ".join(getattr(repo, underscorized_attr)))
+                                       elif attr in repo_config_tuple_attrs:
+                                               config_string += "%s = %s\n" % (attr, " ".join(x.name for x in getattr(repo, underscorized_attr)))
                return config_string.lstrip("\n")
 
 def load_repository_config(settings, extra_files=None):
@@ -971,15 +985,17 @@ def parse_layout_conf(repo_location, repo_name=None):
 
        data = {}
 
-       # None indicates abscence of a masters setting, which later code uses
+       # None indicates absence of a masters setting, which later code uses
        # to trigger a backward compatibility fallback that sets an implicit
        # master. In order to avoid this fallback behavior, layout.conf can
        # explicitly set masters to an empty value, which will result in an
        # empty tuple here instead of None.
-       masters = layout_data.get('masters')
-       if masters is not None:
-               masters = tuple(masters.split())
-       data['masters'] = masters
+       for attr in _masters_attributes.keys():
+               masters = layout_data.get(attr)
+               if masters is not None:
+                       masters = tuple(masters.split())
+               data[attr] = masters
+
        data['aliases'] = tuple(layout_data.get('aliases', '').split())
 
        data['allow-provide-virtual'] = \