Bug #265747 - Add a new /etc/portage/repos.conf config file which can be used
authorZac Medico <zmedico@gentoo.org>
Thu, 30 Apr 2009 07:06:46 +0000 (07:06 -0000)
committerZac Medico <zmedico@gentoo.org>
Thu, 30 Apr 2009 07:06:46 +0000 (07:06 -0000)
to configure site-specific eclass override behavior. Note that configuration
settings which are specified here do not apply to tools such as repoman(1)
and egencache(1) since their operations are inherently not site-specific.
Beware that use of eclass-overrides is generally not recommended and that it
may trigger performance issues under some circumstances (see bug #124041).

Example:

# make all repositories inherit eclasses from the java-overlay and
# java-experimental repositories, with eclasses from java-experimental
# taking precedence over those from java-overlay
[DEFAULT]
eclass-overrides = java-overlay java-experimental

# disable all eclass overrides for the gentoo repository
[gentoo]
eclass-overrides = (trunk r13325)

svn path=/main/branches/2.1.6/; revision=13490

man/portage.5
pym/portage/__init__.py
pym/portage/dbapi/porttree.py

index d9bb60f1579c1e22b319ea34c83940972d2a28c3..dc02a7be3116f5174e5f8aa0267c646dcc8988f4 100644 (file)
@@ -54,6 +54,7 @@ package.keywords
 package.mask
 package.unmask
 package.use
+repos.conf
 .fi
 .TP
 .BR /etc/portage/profile/
@@ -545,6 +546,27 @@ documentation for QT.  Easy as pie my friend!
 # disable mysql support for QT
 x11\-libs/qt \-mysql
 .fi
+.TP
+.BR repos.conf
+Specifies \fIsite\-specific\fR repository configuration information. Note that
+configuration settings which are specified here do not apply to tools
+such as \fBrepoman\fR(1) and \fBegencache\fR(1) since their operations
+are inherently \fBnot\fR \fIsite\-specific\fR. Beware that use of
+\fBeclass\-overrides\fR is generally not recommended and that it may trigger
+performance issues under some circumstances (see \fBbug #124041\fR).
+
+.I Example:
+.nf
+# make all repositories inherit eclasses from the java\-overlay and
+# java\-experimental repositories, with eclasses from java\-experimental
+# taking precedence over those from java\-overlay
+[DEFAULT]
+eclass\-overrides = java\-overlay java\-experimental
+
+# disable all eclass overrides for ebuilds from the gentoo repository
+[gentoo]
+eclass\-overrides =
+.fi
 .RE
 .TP
 .BR /usr/portage/metadata/
index 7898733655df311294723d94f181621508230fe6..8db058d0ad90ac05737e306a63083893311d7c17 100644 (file)
@@ -987,6 +987,13 @@ def _lazy_iuse_regex(iuse_implicit):
        regex = regex.replace("\\.\\*", ".*")
        return regex
 
+class _local_repo_config(object):
+       __slots__ = ('eclass_overrides', 'name',)
+       def __init__(self, name, repo_opts):
+               self.name = name
+               self.eclass_overrides = \
+                       tuple(repo_opts.get('eclass-overrides', '').split())
+
 class config(object):
        """
        This class encompasses the main portage configuration.  Data is pulled from
@@ -1180,12 +1187,18 @@ class config(object):
 
                self.user_profile_dir = None
                self.local_config = local_config
+               self._local_repo_configs = None
+               self._local_repo_conf_path = None
 
                if clone:
                        self.incrementals = copy.deepcopy(clone.incrementals)
                        self.profile_path = copy.deepcopy(clone.profile_path)
                        self.user_profile_dir = copy.deepcopy(clone.user_profile_dir)
                        self.local_config = copy.deepcopy(clone.local_config)
+                       self._local_repo_configs = \
+                               copy.deepcopy(clone._local_repo_configs)
+                       self._local_repo_conf_path = \
+                               copy.deepcopy(clone._local_repo_conf_path)
 
                        self.module_priority = copy.deepcopy(clone.module_priority)
                        self.modules         = copy.deepcopy(clone.modules)
@@ -1628,6 +1641,38 @@ class config(object):
                                                self._plicensedict[cp] = cp_dict
                                        cp_dict[k] = self.expandLicenseTokens(v)
 
+                               self._local_repo_configs = {}
+                               self._local_repo_conf_path = \
+                                       os.path.join(abs_user_config, 'repos.conf')
+                               from ConfigParser import SafeConfigParser, ParsingError
+                               repo_conf_parser = SafeConfigParser()
+                               try:
+                                       repo_conf_parser.readfp(
+                                               codecs.open(self._local_repo_conf_path,
+                                               mode='r', errors='replace'))
+                               except EnvironmentError, e:
+                                       if e.errno != errno.ENOENT:
+                                               raise
+                                       del e
+                               except ParsingError, e:
+                                       portage.util.writemsg_level(
+                                               "!!! Error parsing '%s': %s\n"  % \
+                                               (self._local_repo_conf_path, e),
+                                               level=logging.ERROR, noiselevel=-1)
+                                       del e
+                               else:
+                                       repo_defaults = repo_conf_parser.defaults()
+                                       if repo_defaults:
+                                               self._local_repo_configs['DEFAULT'] = \
+                                                       _local_repo_config('DEFAULT', repo_defaults)
+                                       for repo_name in repo_conf_parser.sections():
+                                               repo_opts = repo_defaults.copy()
+                                               for opt_name in repo_conf_parser.options(repo_name):
+                                                       repo_opts[opt_name] = \
+                                                               repo_conf_parser.get(repo_name, opt_name)
+                                               self._local_repo_configs[repo_name] = \
+                                                       _local_repo_config(repo_name, repo_opts)
+
                        #getting categories from an external file now
                        categories = [grabfile(os.path.join(x, "categories")) for x in locations]
                        self.categories = tuple(sorted(
index 3cd8b2acbd56e7b865bfe58611d90336589081f2..1bc08b8fa12911d2d3bf0e966631a6a27ba479f8 100644 (file)
@@ -173,10 +173,15 @@ class portdbapi(dbapi):
 
                self._repo_info = {}
                eclass_dbs = {porttree_root : self.eclassdb}
+               local_repo_configs = self.mysettings._local_repo_configs
+               default_loc_repo_config = None
+               if local_repo_configs is not None:
+                       default_loc_repo_config = local_repo_configs.get('DEFAULT')
                for path in self.porttrees:
                        if path in self._repo_info:
                                continue
 
+                       repo_name = self._repository_map.get(path)
                        layout_filename = os.path.join(path, "metadata/layout.conf")
                        layout_file = KeyValuePairFileLoader(layout_filename, None, None)
                        layout_data, layout_errors = layout_file.load()
@@ -200,6 +205,24 @@ class portdbapi(dbapi):
 
                        porttrees.append(path)
 
+                       if local_repo_configs is not None:
+                               loc_repo_conf = None
+                               if repo_name is not None:
+                                       loc_repo_conf = local_repo_configs.get(repo_name)
+                               if loc_repo_conf is None:
+                                       loc_repo_conf = default_loc_repo_config
+                               if loc_repo_conf is not None:
+                                       for other_name in loc_repo_conf.eclass_overrides:
+                                               other_path = self.treemap.get(other_name)
+                                               if other_path is None:
+                                                       writemsg_level(("Unavailable repository '%s' " + \
+                                                               "referenced by eclass-overrides entry in " + \
+                                                               "'%s'\n") % (other_name,
+                                                               self.mysettings._local_repo_conf_path),
+                                                               level=logging.ERROR, noiselevel=-1)
+                                                       continue
+                                               porttrees.append(other_path)
+
                        eclass_db = None
                        for porttree in porttrees:
                                tree_db = eclass_dbs.get(porttree)
@@ -211,8 +234,7 @@ class portdbapi(dbapi):
                                else:
                                        eclass_db.append(tree_db)
 
-                       self._repo_info[path] = _repo_info(self._repository_map.get(path),
-                               path, eclass_db)
+                       self._repo_info[path] = _repo_info(repo_name, path, eclass_db)
 
                self.auxdbmodule = self.mysettings.load_best_module("portdbapi.auxdbmodule")
                self.auxdb = {}