More repository handling cleanup
authorSebastian Luther <SebastianLuther@gmx.de>
Thu, 30 Sep 2010 10:36:37 +0000 (12:36 +0200)
committerZac Medico <zmedico@gentoo.org>
Thu, 30 Sep 2010 22:36:32 +0000 (15:36 -0700)
pym/_emerge/MergeListItem.py
pym/_emerge/main.py
pym/portage/dbapi/porttree.py
pym/portage/package/ebuild/_config/MaskManager.py
pym/portage/repository/config.py

index 0eadb7d9912bae4912e01e1a1f8ce359edbf8c5a..1dcc1780a2b24a41d7f3458443c2f0d77c14ce0d 100644 (file)
@@ -59,7 +59,7 @@ class MergeListItem(CompositeTask):
                        colorize("GOOD", pkg.cpv))
 
                portdb = pkg.root_config.trees["porttree"].dbapi
-               portdir_repo_name = portdb._repository_map.get(portdb.porttree_root)
+               portdir_repo_name = portdb.getRepositoryName(portdb.porttree_root)
                if portdir_repo_name:
                        pkg_repo_name = pkg.repo
                        if pkg_repo_name != portdir_repo_name:
index 48b0955d051f76533c9bb85b93fe923e868684ff..fe48763d0d66953b59863a1e85957a11e8265e9d 100644 (file)
@@ -1207,7 +1207,7 @@ def repo_name_duplicate_check(trees):
                if 'porttree' in root_trees:
                        portdb = root_trees['porttree'].dbapi
                        if portdb.settings.get('PORTAGE_REPO_DUPLICATE_WARN') != '0':
-                               for repo_name, paths in portdb._ignored_repos:
+                               for repo_name, paths in portdb.getIgnoredRepos():
                                        k = (root, repo_name, portdb.getRepositoryPath(repo_name))
                                        ignored_repos.setdefault(k, []).extend(paths)
 
index c401c4745b14b271aaed055a36aee1e803b80d53..8d71b23254404238ed90523fa89be6f0e96c0039 100644 (file)
@@ -11,7 +11,6 @@ portage.proxy.lazyimport.lazyimport(globals(),
        'portage.data:portage_gid,secpass',
        'portage.dbapi.dep_expand:dep_expand',
        'portage.dep:dep_getkey,match_from_list,use_reduce',
-       'portage.env.loaders:KeyValuePairFileLoader',
        'portage.package.ebuild.doebuild:doebuild',
        'portage.util:ensure_dirs,shlex_split,writemsg,writemsg_level',
        'portage.util.listdir:listdir',
@@ -20,7 +19,6 @@ portage.proxy.lazyimport.lazyimport(globals(),
 
 from portage.cache.cache_errors import CacheError
 from portage.cache.mappings import Mapping
-from portage.const import REPO_NAME_LOC
 from portage.dbapi import dbapi
 from portage.exception import PortageException, \
        FileNotFound, InvalidDependString, InvalidPackageName
@@ -66,7 +64,15 @@ class portdbapi(dbapi):
        def _categories(self):
                return self.settings.categories
 
-       def __init__(self, _unused_param=None, mysettings=None):
+       @property
+       def porttrees(self):
+               return list(reversed(self.settings.repositories.repoLocationList()))
+
+       @property
+       def porttree_root(self):
+               return self.settings.repositories.mainRepoLocation()
+
+       def __init__(self, mysettings=None):
                """
                @param _unused_param: deprecated, use mysettings['PORTDIR'] instead
                @type _unused_param: None
@@ -82,14 +88,8 @@ class portdbapi(dbapi):
                        from portage import settings
                        self.settings = config(clone=settings)
 
-               porttree_root = self.settings['PORTDIR']
-
-               if _unused_param is not None and _unused_param != porttree_root:
-                       warnings.warn("The first parameter of the " + \
-                               "portage.dbapi.porttree.portdbapi" + \
-                               " constructor is now unused. " + \
-                               "mysettings['PORTDIR'] will be used instead.",
-                               DeprecationWarning, stacklevel=2)
+               self.repositories = self.settings.repositories
+               self.treemap = self.repositories.treemap
 
                # This is strictly for use in aux_get() doebuild calls when metadata
                # is generated by the depend phase.  It's safest to use a clone for
@@ -97,7 +97,7 @@ class portdbapi(dbapi):
                # instance that is passed in.
                self.doebuild_settings = config(clone=self.settings)
                self.depcachedir = os.path.realpath(self.settings.depcachedir)
-
+               
                if os.environ.get("SANDBOX_ON") == "1":
                        # Make api consumers exempt from sandbox violations
                        # when doing metadata cache updates.
@@ -107,35 +107,14 @@ class portdbapi(dbapi):
                                os.environ["SANDBOX_WRITE"] = \
                                        ":".join(filter(None, sandbox_write))
 
-               #adding porttress from repositories
-               porttrees = [os.path.realpath(x) for x in \
-                       self.settings.repositories.repoLocationList()]
-               self._missing_repo_names = self.settings.repositories.missing_repo_names
-
-               # Ensure that each repo_name is unique. Later paths override
-               # earlier ones that correspond to the same name.
-               self._ignored_repos = self.settings.repositories.ignored_repos
-
-               self._repository_map = {}
-               for k, v in self.settings.repositories.location_map.items():
-                       self._repository_map[os.path.realpath(k)] = v
-               self.treemap = {}
-               for k, v in self.settings.repositories.treemap.items():
-                       self.treemap[k] = os.path.realpath(v)
-
-               self.porttrees = porttrees
-               porttree_root = os.path.realpath(
-                       self.settings.repositories.mainRepoLocation())
-               self.porttree_root = porttree_root
-
-               self.eclassdb = eclass_cache.cache(porttree_root)
+               self.eclassdb = eclass_cache.cache(self.settings.repositories.mainRepoLocation())
 
                # This is used as sanity check for aux_get(). If there is no
                # root eclass dir, we assume that PORTDIR is invalid or
                # missing. This check allows aux_get() to detect a missing
                # portage tree and return early by raising a KeyError.
                self._have_root_eclass_dir = os.path.isdir(
-                       os.path.join(self.porttree_root, "eclass"))
+                       os.path.join(self.settings.repositories.mainRepoLocation(), "eclass"))
 
                self.metadbmodule = self.settings.load_best_module("portdbapi.metadbmodule")
 
@@ -143,102 +122,28 @@ class portdbapi(dbapi):
                self.xcache = {}
                self.frozen = 0
 
+               #Create eclass dbs
                self._repo_info = {}
-               eclass_dbs = {porttree_root : self.eclassdb}
-               local_repo_configs = self.settings.repositories.prepos
-               default_loc_repo_config = None
-               repo_aliases = {}
-               if local_repo_configs is not None:
-                       default_loc_repo_config = local_repo_configs.get('DEFAULT')
-                       for repo_name, loc_repo_conf in local_repo_configs.items():
-                               if loc_repo_conf.aliases is not None:
-                                       for alias in loc_repo_conf.aliases:
-                                               overridden_alias = repo_aliases.get(alias)
-                                               if overridden_alias is not None:
-                                                       writemsg_level(_("!!! Alias '%s' " \
-                                                               "created for '%s' overrides " \
-                                                               "'%s' alias in " \
-                                                               "'%s'\n") % (alias, repo_name,
-                                                               overridden_alias,
-                                                               'repos.conf'),
-                                                               level=logging.WARNING, noiselevel=-1)
-                                               repo_aliases[alias] = repo_name
-
-               for path in self.porttrees:
-                       if path in self._repo_info:
+               eclass_dbs = {self.settings.repositories.mainRepoLocation() : self.eclassdb}
+               for repo in self.repositories:
+                       if repo.location in self._repo_info:
                                continue
 
-                       repo_name = self._repository_map.get(path)
-
-                       loc_repo_conf = None
-                       if local_repo_configs is not 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
-
-                       layout_filename = os.path.join(path, "metadata/layout.conf")
-                       layout_file = KeyValuePairFileLoader(layout_filename, None, None)
-                       layout_data, layout_errors = layout_file.load()
-                       porttrees = []
-
-                       masters = None
-                       if loc_repo_conf is not None and \
-                               loc_repo_conf.masters is not None:
-                               masters = loc_repo_conf.masters
-                       else:
-                               masters = layout_data.get('masters', '').split()
-
-                       for master_name in masters:
-                               master_name = repo_aliases.get(master_name, master_name)
-                               master_path = self.treemap.get(master_name)
-                               if master_path is None:
-                                       writemsg_level(_("Unavailable repository '%s' " \
-                                               "referenced by masters entry in '%s'\n") % \
-                                               (master_name, layout_filename),
-                                               level=logging.ERROR, noiselevel=-1)
-                               else:
-                                       porttrees.append(master_path)
-
-                       if not porttrees and path != porttree_root:
-                               # Make PORTDIR the default master, but only if our
-                               # heuristics suggest that it's necessary.
-                               profiles_desc = os.path.join(path, 'profiles', 'profiles.desc')
-                               eclass_dir = os.path.join(path, 'eclass')
-                               if not os.path.isfile(profiles_desc) or \
-                                       not os.path.isdir(eclass_dir):
-                                       porttrees.append(porttree_root)
-
-                       porttrees.append(path)
-
-                       if loc_repo_conf is not None and \
-                                       loc_repo_conf.eclass_overrides 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,
-                                                               'repos.conf'),
-                                                               level=logging.ERROR, noiselevel=-1)
-                                                       continue
-                                               porttrees.append(other_path)
-
                        eclass_db = None
-                       for porttree in porttrees:
-                               tree_db = eclass_dbs.get(porttree)
+                       for eclass_location in repo.eclass_locations:
+                               tree_db = eclass_dbs.get(eclass_location)
                                if tree_db is None:
-                                       tree_db = eclass_cache.cache(porttree)
-                                       eclass_dbs[porttree] = tree_db
+                                       tree_db = eclass_cache.cache(eclass_location)
+                                       eclass_dbs[eclass_location] = tree_db
                                if eclass_db is None:
                                        eclass_db = tree_db.copy()
                                else:
                                        eclass_db.append(tree_db)
 
-                       self._repo_info[path] = _repo_info(repo_name, path, eclass_db)
+                       self._repo_info[repo.location] = _repo_info(repo.name, repo.location, eclass_db)
 
                #Keep a list of repo names, sorted by priority (highest priority first).
-               self._ordered_repo_name_list = tuple(self._repo_info[path].name for path in reversed(self.porttrees))
+               self._ordered_repo_name_list = tuple(reversed(self.repositories.prepos_order))
 
                self.auxdbmodule = self.settings.load_best_module("portdbapi.auxdbmodule")
                self.auxdb = {}
@@ -261,7 +166,7 @@ class portdbapi(dbapi):
                filtered_auxdbkeys.sort()
                from portage.cache import metadata_overlay, volatile
                if not depcachedir_w_ok:
-                       for x in self.porttrees:
+                       for x in reversed(self.repositories.repoLocationList()):
                                db_ro = self.auxdbmodule(self.depcachedir, x,
                                        filtered_auxdbkeys, gid=portage_gid, readonly=True)
                                self.auxdb[x] = metadata_overlay.database(
@@ -269,7 +174,7 @@ class portdbapi(dbapi):
                                        gid=portage_gid, db_rw=volatile.database,
                                        db_ro=db_ro)
                else:
-                       for x in self.porttrees:
+                       for x in reversed(self.repositories.repoLocationList()):
                                if x in self.auxdb:
                                        continue
                                # location, label, auxdbkeys
@@ -278,7 +183,7 @@ class portdbapi(dbapi):
                                if self.auxdbmodule is metadata_overlay.database:
                                        self.auxdb[x].db_ro.ec = self._repo_info[x].eclass_db
                if "metadata-transfer" not in self.settings.features:
-                       for x in self.porttrees:
+                       for x in reversed(self.repositories.repoLocationList()):
                                if x in self._pregen_auxdb:
                                        continue
                                if os.path.isdir(os.path.join(x, "metadata", "cache")):
@@ -324,9 +229,7 @@ class portdbapi(dbapi):
                        x.sync()
 
        def findLicensePath(self, license_name):
-               mytrees = self.porttrees[:]
-               mytrees.reverse()
-               for x in mytrees:
+               for x in reversed(self.repositories.repoLocationList()):
                        license_path = os.path.join(x, "licenses", license_name)
                        if os.access(license_path, os.R_OK):
                                return license_path
@@ -355,7 +258,10 @@ class portdbapi(dbapi):
                        if the path does not correspond a known repository
                @rtype: String or None
                """
-               return self._repository_map.get(canonical_repo_path)
+               try:
+                       return self.repositories.get_name_for_location(canonical_repo_path)
+               except KeyError:
+                       return None
 
        def getRepositories(self):
                """
@@ -369,7 +275,14 @@ class portdbapi(dbapi):
                """
                Returns a list of repository paths that lack profiles/repo_name.
                """
-               return self._missing_repo_names
+               return self.settings.repositories.missing_repo_names
+
+       def getIgnoredRepos(self):
+               """
+               Returns a list of repository paths that have been ignored, because
+               another repo with the same name exists.
+               """
+               return self.settings.repositories.ignored_repos
 
        def findname2(self, mycpv, mytree=None, myrepo = None):
                """ 
@@ -402,8 +315,7 @@ class portdbapi(dbapi):
                if mytree:
                        mytrees = [mytree]
                else:
-                       mytrees = self.porttrees[:]
-                       mytrees.reverse()
+                       mytrees = reversed(self.repositories.repoLocationList())
 
                relative_path = mysplit[0] + _os.sep + psplit[0] + _os.sep + \
                        mysplit[1] + ".ebuild"
@@ -590,8 +502,7 @@ class portdbapi(dbapi):
                                mydata = proc.metadata
 
                # do we have a origin repository name for the current package
-               mydata["repository"] = self._repository_map.get(mylocation, "")
-
+               mydata["repository"] = self.repositories.get_name_for_location(mylocation)
                mydata["INHERITED"] = ' '.join(mydata.get("_eclasses_", []))
                mydata["_mtime_"] = st[stat.ST_MTIME]
 
@@ -770,7 +681,7 @@ class portdbapi(dbapi):
                if categories is None:
                        categories = self.settings.categories
                if trees is None:
-                       trees = self.porttrees
+                       trees = reversed(self.repositories.repoLocationList())
                for x in categories:
                        for oroot in trees:
                                for y in listdir(oroot+"/"+x, EmptyOnError=1, ignorecvs=1, dirsonly=1):
@@ -803,7 +714,7 @@ class portdbapi(dbapi):
                                # assume it's iterable
                                mytrees = mytree
                else:
-                       mytrees = self.porttrees
+                       mytrees = reversed(self.repositories.repoLocationList())
                for oroot in mytrees:
                        try:
                                file_list = os.listdir(os.path.join(oroot, mycp))
@@ -899,7 +810,7 @@ class portdbapi(dbapi):
                                mylist = self.cp_list(mykey)
                        else:
                                mylist = match_from_list(mydep, self.cp_list(mykey,
-                                       mytree=self._repository_map.get(mydep.repo)))
+                                       mytree=self.repositories.get_location_for_name(mydep.repo)))
                        myval = ""
                        settings = self.settings
                        local_config = settings.local_config
index 70ded2dae188f6306c809027fe7edf1cac4f4fa6..c68a7a421af8de9a59a29c95c7279334ed73ee9b 100644 (file)
@@ -29,18 +29,16 @@ class MaskManager(object):
                        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 = []
-                               main_repo = repositories.mainRepo()
-                               if main_repo is not None:
-                                       masters.append(main_repo)
-                       for master in masters:
+                       for master in repo.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))
+                       if not repo.masters:
+                               lines.append(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(stack_lists(lines), repo.name, remember_source_file=True))
 
                repo_pkgunmasklines = []
index 73cddff426e3064230fea2c7e30c3a3c6eb029ed..022c0c8d8c20edae18efaf209003e6f5cee2a8aa 100644 (file)
@@ -1,23 +1,27 @@
 # Copyright 2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import codecs
+import logging
+
 try:
        from configparser import SafeConfigParser
 except ImportError:
        from ConfigParser import SafeConfigParser
 from portage import os
 from portage.const import USER_CONFIG_PATH, GLOBAL_CONFIG_PATH, REPO_NAME_LOC
-from portage.util import normalize_path, writemsg, shlex_split
+from portage.env.loaders import KeyValuePairFileLoader
+from portage.util import normalize_path, writemsg, writemsg_level, shlex_split
 from portage.localization import _
 from portage import _unicode_encode
 from portage import _encodings
 
-import codecs
-
 class RepoConfig(object):
        """Stores config of one repository"""
-       __slots__ = ['aliases', 'eclass_overrides', 'location', 'masters', 'main_repo',
+
+       __slots__ = ['aliases', 'eclass_overrides', 'eclass_locations', 'location', 'user_location', 'masters', 'main_repo',
                '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
@@ -31,12 +35,13 @@ class RepoConfig(object):
                if eclass_overrides is not None:
                        eclass_overrides = tuple(eclass_overrides.split())
                self.eclass_overrides = eclass_overrides
+               #Locations are computed later.
+               self.eclass_locations = None
 
-               masters = repo_opts.get('masters')
-               if masters is not None:
-                       masters = tuple(masters.split())
-               self.masters = masters
+               #Masters are only read from layout.conf.
+               self.masters = None
 
+               #The main-repo key makes only sense for the 'DEFAULT' section.
                self.main_repo = repo_opts.get('main-repo')
 
                priority = repo_opts.get('priority')
@@ -57,18 +62,21 @@ class RepoConfig(object):
                        format = format.strip()
                self.format = format
 
-               self.missing_repo_name = False
-
                location = repo_opts.get('location')
+               self.user_location = location
                if location is not None:
-                       location = normalize_path(location)
                        if os.path.isdir(location):
-                               repo_name = self._get_repo_name(location)
-                               if repo_name:
-                                       name = repo_name
-               self.name = name
+                               location = os.path.realpath(location)
                self.location = location
 
+               missing = True
+               if self.location is not None:
+                       name, missing = self._read_repo_name(self.location)
+               elif name == "DEFAULT": 
+                       missing = False
+               self.name = name
+               self.missing_repo_name = missing
+
        def update(self, new_repo):
                """Update repository with options in another RepoConfig"""
                if new_repo.aliases is not None:
@@ -86,18 +94,20 @@ class RepoConfig(object):
                if new_repo.sync is not None:
                        self.sync = new_repo.sync
 
-       def _get_repo_name(self, repo_path):
-               """Read repo_name from repo_path"""
+       def _read_repo_name(self, repo_path):
+               """
+               Read repo_name from repo_path.
+               Returns repo_name, missing.
+               """
                repo_name_path = os.path.join(repo_path, REPO_NAME_LOC)
                try:
                        return codecs.open(
                                _unicode_encode(repo_name_path,
                                encoding=_encodings['fs'], errors='strict'),
                                mode='r', encoding=_encodings['repo.content'],
-                               errors='replace').readline().strip()
+                               errors='replace').readline().strip(), False
                except EnvironmentError:
-                       self.missing_repo_name = True
-                       return "x-" + os.path.basename(repo_path)
+                       return "x-" + os.path.basename(repo_path), True
 
 class RepoConfigLoader(object):
        """Loads and store config of several repositories, loaded from PORTDIR_OVERLAY or repos.conf"""
@@ -145,7 +155,6 @@ class RepoConfigLoader(object):
                                for ov in overlays:
                                        if os.path.isdir(ov):
                                                repo = RepoConfig(None, {'location' : ov})
-
                                                if repo.name in prepos:
                                                        old_location = prepos[repo.name].location
                                                        if old_location is not None and old_location != repo.location:
@@ -187,6 +196,35 @@ class RepoConfigLoader(object):
 
                self.missing_repo_names = frozenset(repo.location for repo in prepos.values() if repo.missing_repo_name)
 
+               #Parse layout.conf and read masters key.
+               for repo in prepos.values():
+                       if not repo.location:
+                               continue
+                       layout_filename = os.path.join(repo.location, "metadata", "layout.conf")
+                       layout_file = KeyValuePairFileLoader(layout_filename, None, None)
+                       layout_data, layout_errors = layout_file.load()
+
+                       masters = layout_data.get('masters')
+                       if masters:
+                               master = masters.plit()
+                       repo.masters = masters
+
+               #Take aliases into account.
+               new_prepos = {}
+               for repo_name, repo in prepos.items():
+                       names = set()
+                       names.add(repo_name)
+                       if repo.aliases:
+                               names.update(repo.aliases)
+
+                       for name in names:
+                               if name in new_prepos:
+                                       writemsg_level(_("!!! Repository name or alias '%s', " + \
+                                               "defined for repository '%s', overrides " + \
+                                               "existing alias or repository.\n") % (name, repo_name), level=logging.WARNING, noiselevel=-1)
+                               new_prepos[name] = repo
+               prepos = new_prepos
+
                for (name, r) in prepos.items():
                        if r.location is not None:
                                location_map[r.location] = name
@@ -221,6 +259,49 @@ class RepoConfigLoader(object):
                self._prepos_changed = True
                self._repo_location_list = []
 
+               #The 'masters' key currently contains repo names. Replace them with the matching RepoConfig.
+               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(),
+                               else:
+                                       repo.masters = ()
+                       else:
+                               master_repos = []
+                               for master_name in repo.masters:
+                                       if master_name not in prepos:
+                                               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)
+
+               #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
+
+                       eclass_locations = []
+                       eclass_locations.extend(master_repo.location for master_repo in repo.masters)
+                       eclass_locations.append(repo.location)
+
+                       if repo.eclass_overrides:
+                               for other_repo_name in eclass_overrides:
+                                       if other_repo_name in self.prepos:
+                                               eclass_locations.append(self.get_location_for_name(other_repo_name))
+                                       else:
+                                               writemsg_level(_("Unavailable repository '%s' " \
+                                                       "referenced by eclass-overrides entry for " \
+                                                       "'%s'\n") % (other_name, repo_name), level=logging.ERROR, noiselevel=-1)
+                       repo.eclass_locations = tuple(eclass_locations)
+
+               self._prepos_changed = True
+               self._repo_location_list = []
+
                self._check_locations()
 
        def repoLocationList(self):
@@ -231,7 +312,7 @@ class RepoConfigLoader(object):
                                if self.prepos[repo].location is not None:
                                        _repo_location_list.append(self.prepos[repo].location)
                        self._repo_location_list = tuple(_repo_location_list)
-                               
+
                        self._prepos_changed = False
                return self._repo_location_list
 
@@ -268,6 +349,21 @@ class RepoConfigLoader(object):
                        if repo.format != "unavailable":
                                yield repo
 
+       def get_name_for_location(self, location):
+               return self.location_map[location]
+
+       def get_location_for_name(self, repo_name):
+               if repo_name is None:
+                       # This simplifies code in places where
+                       # we want to be able to pass in Atom.repo
+                       # even if it is None.
+                       return None
+               return self.treemap[repo_name]
+
+       def __iter__(self):
+               for repo_name in self.prepos_order:
+                       yield self.prepos[repo_name]
+
 def load_repository_config(settings):
        #~ repoconfigpaths = [os.path.join(settings.global_config_path, "repos.conf")]
        #~ repoconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"],