Merged from trunk -r13290:13296
authorFabian Groffen <grobian@gentoo.org>
Sat, 11 Apr 2009 11:26:37 +0000 (11:26 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 11 Apr 2009 11:26:37 +0000 (11:26 -0000)
|13291  |Add portdbapi support for a metadata/layout.conf file which specifies information |
|zmedico|about the repository layout. Currently, only a single "masters" attribute is      |
|       |supported, which is used to specify names of repositories which satisfy           |
|       |dependencies on eclasses and/or ebuilds. Each repository name should correspond   |
|       |the value of a repo_name entry from one of the repositories that is configured via|
|       |the PORTDIR or PORTDIR_OVERLAY variables. Since layout.conf is now used to control|
|       |eclass inheritance, it is now safer to use overlays which contain forked eclasses |
|       |have names identical to those from the main tree. Such eclasses will only apply to|
|       |their containing repository and any other repositories which reference their      |
|       |containing repository via layout.conf. This solves bug #124041 by containing      |
|       |eclass overrides so that they don't necessarily apply to all ebuilds. Thanks to   |
|       |Alistair Bush <ali_bush@g.o> for his initial patch for layout.conf support in     |
|       |repoman (will be merged later). See the "QA Overlay Layout support" thread on the |
|       |gentoo-dev mailing list for more information:                                     |
|       |http://archives.gentoo.org/gentoo-dev/msg_33c61550b4ed2b7b25dd5a4110e1ec81.xml    |

|13292  |Add a --repo option, allowing cache to be generated for overlays.                 |
|zmedico|                                                                                  |

|13293  |Fix code in the portdbapi constructor to cache eclass_cache.cache instances where |
|zmedico|appropriate.                                                                      |

|13294  |Replace references to portdbapi.eclassdb with appropriate references for the      |
|zmedico|specific repo.                                                                    |

|13295  |Add support to repoman for using layout.conf to control which repositories are    |
|zmedico|used to satisfy dependencies. Thanks to Alistair Bush <ali_bush@g.o> for the      |
|       |initial patch. See the "QA Overlay Layout support" thread on the gentoo-dev       |
|       |mailing list for more information:                                                |
|       |http://archives.gentoo.org/gentoo-dev/msg_33c61550b4ed2b7b25dd5a4110e1ec81.xml    |

|13296  |Fix some _doebuild_exit_status_check() calls so that they only happen when the    |
|zmedico|bash process exits successfully (for consistency with usage elsewhere). When      |
|       |calling this functions, we're mainly concerned about false success, and we always |
|       |want to allow things like using bashrc die hooks to clean up $PORTAGE_BUILDDIR for|
|       |users that are building in tmpfs (in which case the exit status file may be       |
|       |removed before bash exits).                                                       |

svn path=/main/branches/prefix/; revision=13319

bin/egencache
bin/repoman
man/egencache.1
man/portage.5
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/cache/metadata.py
pym/portage/cache/util.py
pym/portage/dbapi/porttree.py
pym/portage/eclass_cache.py

index 487901cf085b4911f679dfb3337e75f4f248a8f7..47e4ea2c7b627129ba76f5e4d3cf7d288cef4c7f 100755 (executable)
@@ -34,6 +34,9 @@ def parse_args(args):
        parser.add_option("--update",
                action="store_true",
                help="update metadata/cache/ (generate as necessary)")
+       parser.add_option("--repo",
+               action="store",
+               help="name of repo to operate on (default repo is located at $PORTDIR)")
        parser.add_option("--cache-dir",
                help="location of the metadata cache",
                dest="cache_dir")
@@ -126,7 +129,7 @@ class GenCache(object):
                        max_jobs=max_jobs, max_load=max_load)
                self.returncode = os.EX_OK
                metadbmodule = portdb.mysettings.load_best_module("portdbapi.metadbmodule")
-               self._trg_cache = metadbmodule(portdb.porttree_root,
+               self._trg_cache = metadbmodule(portdb.porttrees[0],
                        "metadata/cache", portage.auxdbkeys[:])
                if rsync:
                        self._trg_cache.raise_stat_collision = True
@@ -259,8 +262,8 @@ def egencache_main(args):
        # completely controlled by commandline arguments.
        env = {}
 
-       # TODO: Implement --repo for choosing a repo.
-       env['PORTDIR_OVERLAY'] = ''
+       if options.repo is None:
+               env['PORTDIR_OVERLAY'] = ''
 
        if options.cache_dir is not None:
                env['PORTAGE_DEPCACHEDIR'] = options.cache_dir
@@ -300,6 +303,15 @@ def egencache_main(args):
        settings.lock()
 
        portdb = portage.portdbapi(settings["PORTDIR"], mysettings=settings)
+       if options.repo is not None:
+               repo_path = portdb.getRepositoryPath(options.repo)
+               if repo_path is None:
+                       parser.error("Unable to locate repository named '%s'" % \
+                               (options.repo,))
+                       return 1
+
+               # Limit ebuilds to the specified repo.
+               portdb.porttrees = [repo_path]
 
        cp_iter = None
        if atoms:
index 058994440ba8b89fcbbc1342e349ece8fe383ab2..b943cd27b2d7da1ce2c47b0c9f6a809f2ec2d46c 100755 (executable)
@@ -479,31 +479,35 @@ if options.mode == 'commit' and not options.pretend and not vcs:
        logging.info("Not in a version controlled repository; enabling pretend mode.")
        options.pretend = True
 
-os.environ["PORTDIR"] = portdir
-if portdir_overlay != portdir:
-       os.environ["PORTDIR_OVERLAY"] = portdir_overlay
-else:
-       os.environ["PORTDIR_OVERLAY"] = ""
+# Ensure that PORTDIR_OVERLAY contains the repository corresponding to $PWD.
+repoman_settings = portage.config(local_config=False)
+repoman_settings['PORTDIR_OVERLAY'] = "%s %s" % \
+       (repoman_settings.get('PORTDIR_OVERLAY', ''), portdir_overlay)
+repoman_settings.backup_changes('PORTDIR_OVERLAY')
+
+root = '/'
+trees = {
+       root : {'porttree' : portage.portagetree(root, settings=repoman_settings)}
+}
+portdb = trees[root]['porttree'].dbapi
+
+# Constrain dependency resolution to the master(s)
+# that are specified in layout.conf.
+portdir_overlay = os.path.realpath(portdir_overlay)
+repo_info = portdb._repo_info[portdir_overlay]
+portdb.porttrees = list(repo_info.eclass_db.porttrees)
+portdir = portdb.porttrees[0]
 
 logging.info('Setting paths:')
-logging.info('PORTDIR = "' + os.environ['PORTDIR'] + '"')
-logging.info('PORTDIR_OVERLAY = "' + os.environ['PORTDIR_OVERLAY']+'"')
+logging.info('PORTDIR = "' + portdir + '"')
+logging.info('PORTDIR_OVERLAY = "%s"' % ' '.join(portdb.porttrees[1:]))
 
-# Now that PORTDIR_OVERLAY is properly overridden, create the portdb.
-repoman_settings = portage.config(local_config=False,
-       config_incrementals=portage.const.INCREMENTALS)
-trees = portage.create_trees()
-trees["/"]["porttree"].settings = repoman_settings
-portdb = trees["/"]["porttree"].dbapi
 portdb.mysettings = repoman_settings
-setconfig = load_default_config(repoman_settings, trees["/"])
-root_config = RootConfig(repoman_settings, trees["/"], setconfig)
+root_config = RootConfig(repoman_settings, trees[root], None)
 # We really only need to cache the metadata that's necessary for visibility
 # filtering. Anything else can be discarded to reduce memory consumption.
 portdb._aux_cache_keys.clear()
 portdb._aux_cache_keys.update(["EAPI", "KEYWORDS", "SLOT"])
-# dep_zapdeps looks at the vardbapi, but it shouldn't for repoman.
-del trees["/"]["vartree"]
 
 myreporoot = os.path.basename(portdir_overlay)
 myreporoot += mydir[len(portdir_overlay):]
@@ -543,24 +547,27 @@ except (IOError, OSError, ParseError), e:
        logging.exception("Couldn't read USE flags from use.desc")
        sys.exit(1)
 
-# retrieve a list of current licenses in portage
+# get lists of valid keywords and licenses
+kwlist = set(portage.grabfile(os.path.join(portdir, "profiles", "arch.list")))
 liclist = set(portage.listdir(os.path.join(portdir, "licenses")))
+
+if portdir_overlay != portdir:
+       for porttree in portdb.porttrees[1:]:
+               try:
+                       liclist.update(os.listdir(os.path.join(porttree, "licenses")))
+               except OSError:
+                       pass
+               kwlist.update(portage.grabfile(os.path.join(porttree,
+                       "profiles", "arch.list")))
+
 if not liclist:
        logging.fatal("Couldn't find licenses?")
        sys.exit(1)
-if portdir_overlay != portdir:
-       liclist.update(portage.listdir(os.path.join(portdir_overlay, "licenses")))
 
-# retrieve list of offical keywords
-kwlist = set(portage.grabfile(os.path.join(portdir, "profiles", "arch.list")))
 if not kwlist:
        logging.fatal("Couldn't read KEYWORDS from arch.list")
        sys.exit(1)
 
-if portdir_overlay != portdir:
-       kwlist.update(portage.grabfile(
-               os.path.join(portdir_overlay, "profiles", "arch.list")))
-
 scanlist=[]
 if repolevel==2:
        #we are inside a category directory
index 67b166f9d7a307be734842f6fe919779f032187a..dbcc44e4bc35f5c18c45cb446e4bc098514adcb7 100644 (file)
@@ -7,9 +7,7 @@ egencache \- generate metadata cache for ebuild repositories
 .SH "DESCRIPTION"
 The egencache program generates metadata cache for ebuild repositories and
 stores it in the \fImetadata/cache/\fR directory within the repository itself,
-for distribution. Currenly, only the repository located at \fBPORTDIR\fR
-(configured in \fBmake.conf(5)\fR) can be updated by this program, but a
-future version will have the ability to select a different repository.
+for distribution.
 .SH ACTIONS
 .TP
 .BR "\-\-update [ATOM] ... "
@@ -40,6 +38,12 @@ Also see the related \fB\-\-load\-average\fR option.
 .BR \-\-load\-average=LOAD
 Specifies that maximum load allowed when spawning multiple jobs.
 .TP
+.BR "\-\-repo=REPO"
+Name of the repo to operate on (default repo is located at \fBPORTDIR\fR).
+The name should correspond the value of a \fBrepo_name\fR entry (see
+\fBportage\fR(5)) from one of the repositories that is configured via the
+\fBPORTDIR\fR or \fBPORTDIR_OVERLAY\fR variables (see \fBmake.conf\fR(5)).
+.TP
 .BR "\-\-rsync"
 When used together with the \fB\-\-update\fR action, this enables a workaround
 for cases in which the content of a cache entry changes and neither the file
index fac8c90ebf99b2c0ea9a6397e1487b34ca703a0b..0ab4ec344cefc895d18f69da332028a5592b26e3 100644 (file)
@@ -59,6 +59,11 @@ categories
 .BR /etc/portage/profile/
 site-specific overrides of \fB/etc/make.profile/\fR
 .TP
+.BR /usr/portage/metadata/
+.nf
+layout.conf
+.fi
+.TP
 .BR /usr/portage/profiles/
 .nf
 arch.list
@@ -543,6 +548,23 @@ media\-other
 .fi
 .RE
 .TP
+.BR /usr/portage/metadata/
+.RS
+.TP
+.BR layout.conf
+Specifies information about the repository layout. Currently, only a single
+"masters" attribute is supported, which is used to specify names of
+repositories which satisfy dependencies on eclasses and/or ebuilds. Each
+repository name should correspond the value of a \fBrepo_name\fR entry
+from one of the repositories that is configured via the \fBPORTDIR\fR or
+\fBPORTDIR_OVERLAY\fR variables (see \fBmake.conf\fR(5)).
+
+.I Example:
+.nf
+masters = gentoo java-overlay
+.fi
+.RE
+.TP
 .BR /usr/portage/profiles/
 Global Gentoo settings that are controlled by the developers.  To override 
 these settings, you can use the files in \fB/etc/portage/\fR.
index 500a2a5dffbc44138f03d7287f7970b931bbdcbc..41beb32f3629ca49093dd42ae24a533f8f249974 100644 (file)
@@ -785,7 +785,10 @@ class RootConfig(object):
                self.iuse_implicit = tuple(sorted(settings._get_implicit_iuse()))
                self.root = self.settings["ROOT"]
                self.setconfig = setconfig
-               self.sets = self.setconfig.getSets()
+               if setconfig is None:
+                       self.sets = {}
+               else:
+                       self.sets = self.setconfig.getSets()
                self.visible_pkgs = PackageVirtualDbapi(self.settings)
 
 def create_world_atom(pkg, args_set, root_config):
@@ -15549,41 +15552,12 @@ def emerge_main():
                repo_name_check(trees)
                config_protect_check(trees)
 
-       eclasses_overridden = {}
        for mytrees in trees.itervalues():
                mydb = mytrees["porttree"].dbapi
                # Freeze the portdbapi for performance (memoize all xmatch results).
                mydb.freeze()
-               eclasses_overridden.update(mydb.eclassdb._master_eclasses_overridden)
        del mytrees, mydb
 
-       if eclasses_overridden and \
-               settings.get("PORTAGE_ECLASS_WARNING_ENABLE") != "0":
-               prefix = bad(" * ")
-               if len(eclasses_overridden) == 1:
-                       writemsg(prefix + "Overlay eclass overrides " + \
-                               "eclass from PORTDIR:\n", noiselevel=-1)
-               else:
-                       writemsg(prefix + "Overlay eclasses override " + \
-                               "eclasses from PORTDIR:\n", noiselevel=-1)
-               writemsg(prefix + "\n", noiselevel=-1)
-               for eclass_name in sorted(eclasses_overridden):
-                       writemsg(prefix + "  '%s/%s.eclass'\n" % \
-                               (eclasses_overridden[eclass_name], eclass_name),
-                               noiselevel=-1)
-               writemsg(prefix + "\n", noiselevel=-1)
-               msg = "It is best to avoid overriding eclasses from PORTDIR " + \
-               "because it will trigger invalidation of cached ebuild metadata " + \
-               "that is distributed with the portage tree. If you must " + \
-               "override eclasses from PORTDIR then you are advised to add " + \
-               "FEATURES=\"metadata-transfer\" to /etc/make.conf and to run " + \
-               "`emerge --regen` after each time that you run `emerge --sync`. " + \
-               "Set PORTAGE_ECLASS_WARNING_ENABLE=\"0\" in /etc/make.conf if " + \
-               "you would like to disable this warning."
-               from textwrap import wrap
-               for line in wrap(msg, 72):
-                       writemsg("%s%s\n" % (prefix, line), noiselevel=-1)
-
        if "moo" in myfiles:
                print """
 
index 88ec62c4bf2848ab5450df2c1549870bd6c626ef..0e0cefb1b0c5d17d504d1a5f152831a2d849673f 100644 (file)
@@ -1112,7 +1112,7 @@ class config(object):
                "PORTAGE_BACKGROUND",
                "PORTAGE_BINHOST_CHUNKSIZE", "PORTAGE_CALLER",
                "PORTAGE_COUNTER_HASH",
-               "PORTAGE_ECLASS_WARNING_ENABLE", "PORTAGE_ELOG_CLASSES",
+               "PORTAGE_ELOG_CLASSES",
                "PORTAGE_ELOG_MAILFROM", "PORTAGE_ELOG_MAILSUBJECT",
                "PORTAGE_ELOG_MAILURI", "PORTAGE_ELOG_SYSTEM",
                "PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS", "PORTAGE_FETCH_RESUME_MIN_SIZE",
@@ -4770,13 +4770,15 @@ def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0,
 
        if returnpid:
                return phase_retval
-       msg = _doebuild_exit_status_check(mydo, mysettings)
-       if msg:
-               phase_retval = 1
-               from textwrap import wrap
-               from portage.elog.messages import eerror
-               for l in wrap(msg, 72):
-                       eerror(l, phase=mydo, key=mysettings.mycpv)
+
+       if phase_retval == os.EX_OK:
+               msg = _doebuild_exit_status_check(mydo, mysettings)
+               if msg:
+                       phase_retval = 1
+                       from textwrap import wrap
+                       from portage.elog.messages import eerror
+                       for l in wrap(msg, 72):
+                               eerror(l, phase=mydo, key=mysettings.mycpv)
 
        _post_phase_userpriv_perms(mysettings)
        if mydo == "install":
@@ -5049,13 +5051,14 @@ def _spawn_misc_sh(mysettings, commands, **kwargs):
                        logfile=logfile, **kwargs)
        finally:
                pass
-       msg = _doebuild_exit_status_check(mydo, mysettings)
-       if msg:
-               rval = 1
-               from textwrap import wrap
-               from portage.elog.messages import eerror
-               for l in wrap(msg, 72):
-                       eerror(l, phase=mydo, key=mysettings.mycpv)
+       if rval == os.EX_OK:
+               msg = _doebuild_exit_status_check(mydo, mysettings)
+               if msg:
+                       rval = 1
+                       from textwrap import wrap
+                       from portage.elog.messages import eerror
+                       for l in wrap(msg, 72):
+                               eerror(l, phase=mydo, key=mysettings.mycpv)
        return rval
 
 _testing_eapis = frozenset(["3_pre1"])
@@ -5196,6 +5199,12 @@ def doebuild_environment(myebuild, mydo, myroot, mysettings, debug, use_cache, m
        mysettings["FILESDIR"] = os.path.join(pkg_dir, "files")
        mysettings["PF"]       = mypv
 
+       if hasattr(mydbapi, '_repo_info'):
+               mytree = os.path.dirname(os.path.dirname(pkg_dir))
+               repo_info = mydbapi._repo_info[mytree]
+               mysettings['PORTDIR'] = repo_info.portdir
+               mysettings['PORTDIR_OVERLAY'] = repo_info.portdir_overlay
+
        mysettings["PORTDIR"] = os.path.realpath(mysettings["PORTDIR"])
        mysettings["DISTDIR"] = os.path.realpath(mysettings["DISTDIR"])
        mysettings["RPMDIR"]  = os.path.realpath(mysettings["RPMDIR"])
index a8be010950a4d4f6f99993f910bda11d58e829e4..e3f6fc57121a87bff42fdfa47c1ed06959fa4ba0 100644 (file)
@@ -29,7 +29,7 @@ class database(flat_hash.database):
                loc = location
                super(database, self).__init__(location, *args, **config)
                self.location = os.path.join(loc, "metadata","cache")
-               self.ec = portage.eclass_cache.cache(loc)
+               self.ec = None
                self.raise_stat_collision = False
 
        def _parse_data(self, data, cpv):
@@ -53,9 +53,11 @@ class database(flat_hash.database):
 
                if "_eclasses_" not in d:
                        if "INHERITED" in d:
+                               if self.ec is None:
+                                       self.ec = portage.eclass_cache.cache(self.location)
                                try:
                                        d["_eclasses_"] = self.ec.get_eclass_data(
-                                               d["INHERITED"].split(), from_master_only=True)
+                                               d["INHERITED"].split())
                                except KeyError, e:
                                        # INHERITED contains a non-existent eclass.
                                        raise cache_errors.CacheCorruption(cpv, e)
index 0f2685c0a96e8fc1c4030c7e543f42a69e58a5ee..bdee52ddc70de1673d6cd25a7db30cc8e6e562d5 100644 (file)
@@ -102,8 +102,7 @@ def mirror_cache(valid_nodes_iterable, src_cache, trg_cache, eclass_cache=None,
                                # Even if _eclasses_ already exists, replace it with data from
                                # eclass_cache, in order to insert local eclass paths.
                                try:
-                                       eclasses = eclass_cache.get_eclass_data(inherited,
-                                               from_master_only=True)
+                                       eclasses = eclass_cache.get_eclass_data(inherited)
                                except KeyError:
                                        # INHERITED contains a non-existent eclass.
                                        noise.eclass_stale(x)
index 9d4b1523d482f5e52ab16fedf44783728eab260f..3cd8b2acbd56e7b865bfe58611d90336589081f2 100644 (file)
@@ -8,7 +8,8 @@ import portage
 portage.proxy.lazyimport.lazyimport(globals(),
        'portage.checksum',
        'portage.dep:dep_getkey,match_from_list,paren_reduce,use_reduce',
-       'portage.util:ensure_dirs,writemsg',
+       'portage.env.loaders:KeyValuePairFileLoader',
+       'portage.util:ensure_dirs,writemsg,writemsg_level',
        'portage.versions:best,catpkgsplit,pkgsplit,ver_regexp',
 )
 
@@ -25,7 +26,7 @@ from portage import eclass_cache, auxdbkeys, doebuild, flatten, \
        listdir, dep_expand, eapi_is_supported, key_expand, dep_check, \
        _eapi_is_deprecated
 
-import codecs, os, stat
+import codecs, logging, os, stat
 from itertools import izip
 
 def _src_uri_validate(cpv, eapi, src_uri):
@@ -95,6 +96,15 @@ def _src_uri_validate(cpv, eapi, src_uri):
                        "getFetchMap(): '%s' SRC_URI arrow missing right operand" % \
                        (cpv,))
 
+class _repo_info(object):
+       __slots__ = ('name', 'path', 'eclass_db', 'portdir', 'portdir_overlay')
+       def __init__(self, name, path, eclass_db):
+               self.name = name
+               self.path = path
+               self.eclass_db = eclass_db
+               self.portdir = eclass_db.porttrees[0]
+               self.portdir_overlay = ' '.join(eclass_db.porttrees[1:])
+
 class portdbapi(dbapi):
        """this tree will scan a portage directory located at root (passed to init)"""
        portdbapi_instances = []
@@ -116,10 +126,8 @@ class portdbapi(dbapi):
                # instance that is passed in.
                self.doebuild_settings = config(clone=self.mysettings)
 
-               #self.root=settings["PORTDIR"]
+               porttree_root = os.path.realpath(porttree_root)
                self.porttree_root = porttree_root
-               if porttree_root:
-                       self.porttree_root = os.path.realpath(porttree_root)
 
                self.depcachedir = os.path.realpath(self.mysettings.depcachedir)
 
@@ -132,8 +140,7 @@ class portdbapi(dbapi):
                                os.environ["SANDBOX_WRITE"] = \
                                        ":".join(filter(None, sandbox_write))
 
-               self.eclassdb = eclass_cache.cache(self.porttree_root,
-                       overlays=self.mysettings["PORTDIR_OVERLAY"].split())
+               self.eclassdb = eclass_cache.cache(porttree_root)
 
                # This is used as sanity check for aux_get(). If there is no
                # root eclass dir, we assume that PORTDIR is invalid or
@@ -163,7 +170,50 @@ class portdbapi(dbapi):
                                # don't want to see a warning every time the portage module is
                                # imported.
                                pass
-               
+
+               self._repo_info = {}
+               eclass_dbs = {porttree_root : self.eclassdb}
+               for path in self.porttrees:
+                       if path in self._repo_info:
+                               continue
+
+                       layout_filename = os.path.join(path, "metadata/layout.conf")
+                       layout_file = KeyValuePairFileLoader(layout_filename, None, None)
+                       layout_data, layout_errors = layout_file.load()
+                       porttrees = []
+                       for master_name in layout_data.get('masters', '').split():
+                               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:
+                               # Make PORTDIR the default master, but only if this
+                               # repo doesn't provide profiles.desc itself.
+                               profiles_desc = os.path.join(path, 'profiles', 'profiles.desc')
+                               if not os.path.exists(profiles_desc):
+                                       porttrees.append(porttree_root)
+
+                       porttrees.append(path)
+
+                       eclass_db = None
+                       for porttree in porttrees:
+                               tree_db = eclass_dbs.get(porttree)
+                               if tree_db is None:
+                                       tree_db = eclass_cache.cache(porttree)
+                                       eclass_dbs[porttree] = tree_db
+                               if eclass_db is None:
+                                       eclass_db = tree_db.copy()
+                               else:
+                                       eclass_db.append(tree_db)
+
+                       self._repo_info[path] = _repo_info(self._repository_map.get(path),
+                               path, eclass_db)
+
                self.auxdbmodule = self.mysettings.load_best_module("portdbapi.auxdbmodule")
                self.auxdb = {}
                self._pregen_auxdb = {}
@@ -183,14 +233,22 @@ class portdbapi(dbapi):
                                        db_ro=db_ro)
                else:
                        for x in self.porttrees:
+                               if x in self.auxdb:
+                                       continue
                                # location, label, auxdbkeys
                                self.auxdb[x] = self.auxdbmodule(
                                        self.depcachedir, x, filtered_auxdbkeys, gid=portage_gid)
                if "metadata-transfer" not in self.mysettings.features:
                        for x in self.porttrees:
+                               if x in self._pregen_auxdb:
+                                       continue
                                if os.path.isdir(os.path.join(x, "metadata", "cache")):
                                        self._pregen_auxdb[x] = self.metadbmodule(
                                                x, "metadata/cache", filtered_auxdbkeys, readonly=True)
+                                       try:
+                                               self._pregen_auxdb[x].ec = self._repo_info[x].eclass_db
+                                       except AttributeError:
+                                               pass
                # Selectively cache metadata in order to optimize dep matching.
                self._aux_cache_keys = set(
                        ["DEPEND", "EAPI", "INHERITED", "IUSE", "KEYWORDS", "LICENSE",
@@ -331,8 +389,8 @@ class portdbapi(dbapi):
                metadata = dict(i)
 
                if metadata.get("INHERITED", False):
-                       metadata["_eclasses_"] = \
-                               self.eclassdb.get_eclass_data(metadata["INHERITED"].split())
+                       metadata["_eclasses_"] = self._repo_info[repo_path
+                               ].eclass_db.get_eclass_data(metadata["INHERITED"].split())
                else:
                        metadata["_eclasses_"] = {}
 
@@ -370,6 +428,7 @@ class portdbapi(dbapi):
                if pregen_auxdb is not None:
                        auxdbs.append(pregen_auxdb)
                auxdbs.append(self.auxdb[repo_path])
+               eclass_db = self._repo_info[repo_path].eclass_db
 
                doregen = True
                for auxdb in auxdbs:
@@ -389,7 +448,7 @@ class portdbapi(dbapi):
                                        eapi = '0'
                                if not (eapi[:1] == '-' and eapi_is_supported(eapi[1:])) and \
                                        emtime == metadata['_mtime_'] and \
-                                       self.eclassdb.is_eclass_data_valid(metadata['_eclasses_']):
+                                       eclass_db.is_eclass_data_valid(metadata['_eclasses_']):
                                        doregen = False
 
                        if not doregen:
@@ -466,8 +525,8 @@ class portdbapi(dbapi):
                                mycpv, myebuild, mylocation, mydata, emtime)
 
                        if mydata.get("INHERITED", False):
-                               mydata["_eclasses_"] = \
-                                       self.eclassdb.get_eclass_data(mydata["INHERITED"].split())
+                               mydata["_eclasses_"] = self._repo_info[mylocation
+                                       ].eclass_db.get_eclass_data(mydata["INHERITED"].split())
                        else:
                                mydata["_eclasses_"] = {}
 
index 670e9fb245201165d2ddb89a7ab1cf0274f9701b..15602fc023d2e402e71d5f2c3a935231bea2e17e 100644 (file)
@@ -5,6 +5,7 @@
 
 __all__ = ["cache"]
 
+import warnings
 from portage.util import normalize_path, writemsg
 import errno, os, sys
 from portage.data import portage_gid
@@ -15,18 +16,47 @@ class cache(object):
        Maintains the cache information about eclasses used in ebuild.
        """
        def __init__(self, porttree_root, overlays=[]):
-               self.porttree_root = porttree_root
 
                self.eclasses = {} # {"Name": ("location","_mtime_")}
                self._eclass_locations = {}
 
                # screw with the porttree ordering, w/out having bash inherit match it, and I'll hurt you.
                # ~harring
-               self.porttrees = [self.porttree_root]+overlays
-               self.porttrees = tuple(map(normalize_path, self.porttrees))
-               self._master_eclass_root = os.path.join(self.porttrees[0],"eclass")
-               self._master_eclasses_overridden = {}
-               self.update_eclasses()
+               if porttree_root:
+                       self.porttree_root = porttree_root
+                       self.porttrees = [self.porttree_root] + overlays
+                       self.porttrees = tuple(map(normalize_path, self.porttrees))
+                       self._master_eclass_root = os.path.join(self.porttrees[0], "eclass")
+                       self.update_eclasses()
+               else:
+                       self.porttree_root = None
+                       self.porttrees = ()
+                       self._master_eclass_root = None
+
+       def copy(self):
+               return self.__copy__()
+
+       def __copy__(self):
+               result = self.__class__(None)
+               result.eclasses = self.eclasses.copy()
+               result._eclass_locations = self._eclass_locations.copy()
+               result.porttree_root = self.porttree_root
+               result.porttrees = self.porttrees
+               result._master_eclass_root = self._master_eclass_root
+               return result
+
+       def append(self, other):
+               """
+               Append another instance to this instance. This will cause eclasses
+               from the other instance to override and eclases from this instance
+               that have the same name.
+               """
+               if not isinstance(other, self.__class__):
+                       raise TypeError(
+                               "expected type %s, got %s" % (self.__class__, type(other)))
+               self.porttrees = self.porttrees + other.porttrees
+               self.eclasses.update(other.eclasses)
+               self._eclass_locations.update(other._eclass_locations)
 
        def close_caches(self):
                import traceback
@@ -77,8 +107,7 @@ class cache(object):
                                                # It appears to be identical to the master,
                                                # so prefer the master entry.
                                                continue
-                                       else:
-                                               self._master_eclasses_overridden[ys] = x
+
                                self.eclasses[ys] = (x, mtime)
                                self._eclass_locations[ys] = x
 
@@ -100,8 +129,10 @@ class cache(object):
                ec_dict = {}
                for x in inherits:
                        ec_dict[x] = self.eclasses[x]
-                       if from_master_only and \
-                               self._eclass_locations[x] != self._master_eclass_root:
-                               return None
+
+               if from_master_only is not False:
+                       warnings.warn("portage.eclass_cache.cache.get_eclass_data(): " + \
+                               "ignoring deprecated 'from_master_only' parameter",
+                               DeprecationWarning)
 
                return ec_dict