From e1449bd5d22765866a8ccf1a56ebf272184ab990 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Sat, 11 Apr 2009 11:26:37 +0000 Subject: [PATCH] Merged from trunk -r13290:13296 |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 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 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 | 18 ++++++-- bin/repoman | 59 +++++++++++++----------- man/egencache.1 | 10 +++-- man/portage.5 | 22 +++++++++ pym/_emerge/__init__.py | 34 ++------------ pym/portage/__init__.py | 39 +++++++++------- pym/portage/cache/metadata.py | 6 ++- pym/portage/cache/util.py | 3 +- pym/portage/dbapi/porttree.py | 85 +++++++++++++++++++++++++++++------ pym/portage/eclass_cache.py | 53 +++++++++++++++++----- 10 files changed, 224 insertions(+), 105 deletions(-) diff --git a/bin/egencache b/bin/egencache index 487901cf0..47e4ea2c7 100755 --- a/bin/egencache +++ b/bin/egencache @@ -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: diff --git a/bin/repoman b/bin/repoman index 058994440..b943cd27b 100755 --- a/bin/repoman +++ b/bin/repoman @@ -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 diff --git a/man/egencache.1 b/man/egencache.1 index 67b166f9d..dbcc44e4b 100644 --- a/man/egencache.1 +++ b/man/egencache.1 @@ -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 diff --git a/man/portage.5 b/man/portage.5 index fac8c90eb..0ab4ec344 100644 --- a/man/portage.5 +++ b/man/portage.5 @@ -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. diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 500a2a5df..41beb32f3 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -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 """ diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 88ec62c4b..0e0cefb1b 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -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"]) diff --git a/pym/portage/cache/metadata.py b/pym/portage/cache/metadata.py index a8be01095..e3f6fc571 100644 --- a/pym/portage/cache/metadata.py +++ b/pym/portage/cache/metadata.py @@ -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) diff --git a/pym/portage/cache/util.py b/pym/portage/cache/util.py index 0f2685c0a..bdee52ddc 100644 --- a/pym/portage/cache/util.py +++ b/pym/portage/cache/util.py @@ -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) diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py index 9d4b1523d..3cd8b2acb 100644 --- a/pym/portage/dbapi/porttree.py +++ b/pym/portage/dbapi/porttree.py @@ -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_"] = {} diff --git a/pym/portage/eclass_cache.py b/pym/portage/eclass_cache.py index 670e9fb24..15602fc02 100644 --- a/pym/portage/eclass_cache.py +++ b/pym/portage/eclass_cache.py @@ -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 -- 2.26.2