From: Fabian Groffen Date: Sat, 27 Jun 2009 14:32:58 +0000 (-0000) Subject: Merged from trunk -r13677:13688 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=1f3eb4a78c792c2283b7977fc57c64b7b9190652;p=portage.git Merged from trunk -r13677:13688 | 13678 | Fix imports for _emerge submodules. | | zmedico | | | 13679 | Bug #275237 - If a directory exists in a location where a | | zmedico | normal file is to be merged, generate a config-protect | | | filename for the file and merge it that way. Thanks to Jonas | | | Bernoulli for this patch. | | 13680 | In binarytree.inject(), when a symlink is created for the | | zmedico | current package and it overwrites another package, delete | | | the corresponding metadata from the Packages file. Thanks to | | | Eitan Mosenkis for reporting. | | 13681 | Add support to `portageq owners` for querying paths matching | | zmedico | a given basename. It is natural to support this since the | | | vartree already maintains a basename -> owner index anyway. | | | There are plans for the packagekit backend is to support | | | this type of search. | | 13685 | Bug #275217 - Part 3 - Splits depgraph.select_files into | | zmedico | select_files and _resolve. Thanks to Sebastian Mingramm | | | (few) for this patch. | | 13686 | * Make Package.metadata['USE'] access trigger USE | | zmedico | calculation for unbuilt ebuilds. * Make | | | Package.metadata['LICENSE'] access trigger USE conditional | | | evaluation. * Make Package.metadata['PROVIDE'] access | | | trigger USE conditional evaluation. * Initialize | | | Package.metadata['CHOST'] in the Package constructor for | | | unbuilt ebuilds. | | 13687 | Remove obsolete Package.metadata['CHOST'] initialization. | | zmedico | | | 13688 | Use depgraph._pkg() to construct Package instances inside | | zmedico | _select_pkg_highest_available_imp(). | svn path=/main/branches/prefix/; revision=13714 --- diff --git a/bin/portageq b/bin/portageq index 2c87ac704..38d797639 100755 --- a/bin/portageq +++ b/bin/portageq @@ -161,8 +161,8 @@ def owners(argv): Given a list of files, print the packages that own the files and which files belong to each package. Files owned by a package are listed on the lines below it, indented by a single tab character (\\t). All file - paths must start with . Returns 1 if no owners could be found, - and 0 otherwise. + paths must either start with or be a basename alone. + Returns 1 if no owners could be found, and 0 otherwise. """ if len(argv) < 2: sys.stderr.write("ERROR: insufficient parameters!\n") @@ -183,18 +183,22 @@ def owners(argv): files = [] for f in argv[1:]: f = portage.normalize_path(f) - if not f.startswith(os.path.sep): + is_basename = os.sep not in f + if not is_basename and f[:1] != os.sep: if cwd is None: sys.stderr.write("ERROR: cwd does not exist!\n") sys.stderr.flush() return 2 f = os.path.join(cwd, f) f = portage.normalize_path(f) - if not f.startswith(root): + if not is_basename and not f.startswith(root): sys.stderr.write("ERROR: file paths must begin with !\n") sys.stderr.flush() return 2 - files.append(f[len(root):]) + if is_basename: + files.append(f) + else: + files.append(f[len(root):]) owners = vardb._owners.get_owners(files) diff --git a/bin/repoman b/bin/repoman index bcde969de..213da7e6f 100755 --- a/bin/repoman +++ b/bin/repoman @@ -48,7 +48,8 @@ portage._disable_legacy_globals() from repoman.checks import run_checks from repoman import utilities -from _emerge import Package, RootConfig +from _emerge.Package import Package +from _emerge.RootConfig import RootConfig from portage.sets import load_default_config import portage.checksum diff --git a/pym/_emerge/Package.py b/pym/_emerge/Package.py index 66ba5bc6c..e1283bbf4 100644 --- a/pym/_emerge/Package.py +++ b/pym/_emerge/Package.py @@ -11,7 +11,8 @@ else: import portage from portage.cache.mappings import slot_dict_class - +from portage.dep import paren_reduce, use_reduce, \ + paren_normalize, paren_enclose from _emerge.Task import Task class Package(Task): @@ -22,7 +23,8 @@ class Package(Task): "root_config", "type_name", "category", "counter", "cp", "cpv_split", "inherited", "iuse", "mtime", - "pf", "pv_split", "root", "slot", "slot_atom", "use") + "pf", "pv_split", "root", "slot", "slot_atom",) + \ + ("_use",) metadata_keys = [ "CHOST", "COUNTER", "DEPEND", "EAPI", @@ -35,6 +37,8 @@ class Package(Task): Task.__init__(self, **kwargs) self.root = self.root_config.root self.metadata = _PackageMetadataWrapper(self, self.metadata) + if not self.built: + self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '') self.cp = portage.cpv_getkey(self.cpv) slot = self.slot if not slot: @@ -46,13 +50,19 @@ class Package(Task): self.cpv_split = portage.catpkgsplit(self.cpv) self.pv_split = self.cpv_split[1:] - class _use(object): + class _use_class(object): __slots__ = ("__weakref__", "enabled") def __init__(self, use): self.enabled = frozenset(use) + @property + def use(self): + if self._use is None: + self._use = self._use_class(self.metadata['USE'].split()) + return self._use + class _iuse(object): __slots__ = ("__weakref__", "all", "enabled", "disabled", "iuse_implicit", "regex", "tokens") @@ -143,13 +153,38 @@ class _PackageMetadataWrapper(_PackageMetadataWrapperBase): __slots__ = ("_pkg",) _wrapped_keys = frozenset( - ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"]) + ["COUNTER", "INHERITED", "IUSE", "SLOT", "_mtime_"]) def __init__(self, pkg, metadata): _PackageMetadataWrapperBase.__init__(self) self._pkg = pkg + """LICENSE with USE conditionals evaluated.""" + + if not pkg.built: + # USE is lazy, but we want it to show up in self.keys(). + self['USE'] = '' + self.update(metadata) + def __getitem__(self, k): + v = _PackageMetadataWrapperBase.__getitem__(self, k) + if k in ('PROVIDE', 'LICENSE',): + if '?' in v: + v = paren_enclose(paren_normalize(use_reduce( + paren_reduce(v), uselist=self._pkg.use.enabled))) + self[k] = v + + elif k == 'USE' and not self._pkg.built: + if not v: + # This is lazy because it's expensive. + pkgsettings = self._pkg.root_config.trees[ + 'porttree'].dbapi.doebuild_settings + pkgsettings.setcpv(self._pkg) + v = pkgsettings["PORTAGE_USE"] + self['USE'] = v + + return v + def __setitem__(self, k, v): _PackageMetadataWrapperBase.__setitem__(self, k, v) if k in self._wrapped_keys: @@ -167,9 +202,6 @@ class _PackageMetadataWrapper(_PackageMetadataWrapperBase): def _set_slot(self, k, v): self._pkg.slot = v - def _set_use(self, k, v): - self._pkg.use = self._pkg._use(v.split()) - def _set_counter(self, k, v): if isinstance(v, basestring): try: diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py index 800e81cdc..d10336337 100644 --- a/pym/_emerge/Scheduler.py +++ b/pym/_emerge/Scheduler.py @@ -1627,12 +1627,6 @@ class Scheduler(PollScheduler): db_keys = list(self.trees[root_config.root][ tree_type].dbapi._aux_cache_keys) metadata = izip(db_keys, db.aux_get(cpv, db_keys)) - pkg = Package(cpv=cpv, metadata=metadata, + return Package(built=(type_name != 'ebuild'), + cpv=cpv, metadata=metadata, root_config=root_config, installed=installed) - if type_name == "ebuild": - settings = self.pkgsettings[root_config.root] - settings.setcpv(pkg) - pkg.metadata["USE"] = settings["PORTAGE_USE"] - pkg.metadata['CHOST'] = settings.get('CHOST', '') - - return pkg diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 14e0552eb..a7d324370 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -176,6 +176,8 @@ class depgraph(object): "--getbinpkgonly" in self.myopts) del trees + #contains the args created by select_files + self._initial_arg_list = [] self.digraph=portage.digraph() # contains all sets added to the graph self._sets = {} @@ -1067,7 +1069,8 @@ class depgraph(object): yield arg, atom def select_files(self, myfiles): - """Given a list of .tbz2s, .ebuilds sets, and deps, create the + """Given a list of .tbz2s, .ebuilds sets, and deps, populate + self._initial_arg_list and call self._resolve to create the appropriate depgraph and return a favorite list.""" debug = "--debug" in self.myopts root_config = self.roots[self.target_root] @@ -1146,9 +1149,6 @@ class depgraph(object): metadata = izip(db_keys, portdb.aux_get(mykey, db_keys)) pkg = Package(type_name="ebuild", root_config=root_config, cpv=mykey, metadata=metadata, onlydeps=onlydeps) - pkgsettings.setcpv(pkg) - pkg.metadata["USE"] = pkgsettings["PORTAGE_USE"] - pkg.metadata['CHOST'] = pkgsettings.get('CHOST', '') self._pkg_cache[pkg] = pkg args.append(PackageArg(arg=x, package=pkg, root_config=root_config)) @@ -1325,14 +1325,25 @@ class depgraph(object): myfavorites.add(arg.arg) myfavorites = list(myfavorites) - pprovideddict = pkgsettings.pprovideddict if debug: portage.writemsg("\n", noiselevel=-1) # Order needs to be preserved since a feature of --nodeps # is to allow the user to force a specific merge order. args.reverse() - while args: - arg = args.pop() + self._initial_arg_list = args[:] + + return self._resolve(myfavorites) + + def _resolve(self, myfavorites): + """Given self._initial_arg_list, pull in the root nodes, + call self._creategraph to process theier deps and return + a favorite list.""" + debug = "--debug" in self.myopts + onlydeps = "--onlydeps" in self.myopts + myroot = self.target_root + pkgsettings = self.pkgsettings[myroot] + pprovideddict = pkgsettings.pprovideddict + for arg in self._initial_arg_list: for atom in arg.set: self.spinner.update() dep = Dependency(atom=atom, onlydeps=onlydeps, @@ -1866,9 +1877,7 @@ class depgraph(object): if not cpv_list: continue - pkg_status = "merge" - if installed or onlydeps: - pkg_status = "nomerge" + # descending order cpv_list.reverse() for cpv in cpv_list: @@ -1880,31 +1889,11 @@ class depgraph(object): # in case there is a visible downgrade. continue reinstall_for_flags = None - cache_key = (pkg_type, root, cpv, pkg_status) - calculated_use = True - pkg = self._pkg_cache.get(cache_key) - if pkg is None: - calculated_use = False - try: - metadata = izip(db_keys, db.aux_get(cpv, db_keys)) - except KeyError: - continue - pkg = Package(built=built, cpv=cpv, - installed=installed, metadata=metadata, - onlydeps=onlydeps, root_config=root_config, - type_name=pkg_type) - metadata = pkg.metadata - if not built: - metadata['CHOST'] = pkgsettings.get('CHOST', '') - if not built and ("?" in metadata["LICENSE"] or \ - "?" in metadata["PROVIDE"]): - # This is avoided whenever possible because - # it's expensive. It only needs to be done here - # if it has an effect on visibility. - pkgsettings.setcpv(pkg) - metadata["USE"] = pkgsettings["PORTAGE_USE"] - calculated_use = True - self._pkg_cache[pkg] = pkg + try: + pkg = self._pkg(cpv, pkg_type, root_config, + installed=installed, onlydeps=onlydeps) + except portage.exception.PackageNotFound: + continue if not installed or (built and matched_packages): # Only enforce visibility on installed packages @@ -1955,11 +1944,9 @@ class depgraph(object): if not visible(pkgsettings, pkg_eb): continue - if not pkg.built and not calculated_use: - # This is avoided whenever possible because - # it's expensive. - pkgsettings.setcpv(pkg) - pkg.metadata["USE"] = pkgsettings["PORTAGE_USE"] + # Calculation of USE for unbuilt ebuilds is relatively + # expensive, so it is only performed lazily, after the + # above visibility checks are complete. if pkg.cp != atom.cp: # A cpv can be returned from dbapi.match() as an @@ -1972,8 +1959,6 @@ class depgraph(object): myarg = None if root == self.target_root: try: - # Ebuild USE must have been calculated prior - # to this point, in case atoms have USE deps. myarg = self._iter_atoms_for_pkg(pkg).next() except StopIteration: pass @@ -2202,18 +2187,24 @@ class depgraph(object): return 0 return 1 - def _pkg(self, cpv, type_name, root_config, installed=False): + def _pkg(self, cpv, type_name, root_config, installed=False, + onlydeps=False): """ Get a package instance from the cache, or create a new - one if necessary. Raises KeyError from aux_get if it + one if necessary. Raises PackageNotFound from aux_get if it failures for some reason (package does not exist or is corrupt). """ operation = "merge" - if installed: + if installed or onlydeps: operation = "nomerge" pkg = self._pkg_cache.get( (type_name, root_config.root, cpv, operation)) + if pkg is None and onlydeps and not installed: + # Maybe it already got pulled in as a "merge" node. + pkg = self.mydbapi[root_config.root].get( + (type_name, root_config.root, cpv, 'merge')) + if pkg is None: tree_type = self.pkg_tree_map[type_name] db = root_config.trees[tree_type].dbapi @@ -2223,13 +2214,9 @@ class depgraph(object): metadata = izip(db_keys, db.aux_get(cpv, db_keys)) except KeyError: raise portage.exception.PackageNotFound(cpv) - pkg = Package(cpv=cpv, metadata=metadata, - root_config=root_config, installed=installed) - if type_name == "ebuild": - settings = self.pkgsettings[root_config.root] - settings.setcpv(pkg) - pkg.metadata["USE"] = settings["PORTAGE_USE"] - pkg.metadata['CHOST'] = settings.get('CHOST', '') + pkg = Package(built=(type_name != "ebuild"), cpv=cpv, + installed=installed, metadata=metadata, + root_config=root_config, type_name=type_name) self._pkg_cache[pkg] = pkg return pkg @@ -4369,11 +4356,6 @@ class depgraph(object): installed=installed, metadata=metadata, operation=action, root_config=root_config, type_name=pkg_type) - if pkg_type == "ebuild": - pkgsettings = self.pkgsettings[myroot] - pkgsettings.setcpv(pkg) - pkg.metadata["USE"] = pkgsettings["PORTAGE_USE"] - pkg.metadata['CHOST'] = pkgsettings.get('CHOST', '') self._pkg_cache[pkg] = pkg root_config = self.roots[pkg.root] @@ -4815,10 +4797,7 @@ def get_mask_info(root_config, cpv, pkgsettings, db.aux_get(cpv, db_keys))) except KeyError: metadata = None - if metadata and not built: - pkgsettings.setcpv(cpv, mydb=metadata) - metadata["USE"] = pkgsettings["PORTAGE_USE"] - metadata['CHOST'] = pkgsettings.get('CHOST', '') + if metadata is None: mreasons = ["corruption"] else: diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py index a9abaf309..071cc4a63 100644 --- a/pym/portage/dbapi/bintree.py +++ b/pym/portage/dbapi/bintree.py @@ -836,6 +836,7 @@ class binarytree(object): # process) and then updated it, all while holding a lock. from portage.locks import lockfile, unlockfile pkgindex_lock = None + created_symlink = False try: pkgindex_lock = lockfile(self._pkgindex_file, wantnewlockfile=1) @@ -846,6 +847,7 @@ class binarytree(object): if self._all_directory and \ self.getname(cpv).split(os.path.sep)[-2] == "All": self._create_symlink(cpv) + created_symlink = True pkgindex = self._new_pkgindex() try: f = open(self._pkgindex_file) @@ -877,8 +879,14 @@ class binarytree(object): # Handle path collisions in $PKGDIR/All # when CPV is not identical. del pkgindex.packages[i] - elif cpv == d2.get("CPV") and path == d2.get("PATH", ""): - del pkgindex.packages[i] + elif cpv == d2.get("CPV"): + if path == d2.get("PATH", ""): + del pkgindex.packages[i] + elif created_symlink and not d2.get("PATH", ""): + # Delete entry for the package that was just + # overwritten by a symlink to this package. + del pkgindex.packages[i] + pkgindex.packages.append(d) self._update_pkgindex_header(pkgindex.header) diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index b1c6c086e..76d2b5d8a 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -2053,7 +2053,12 @@ class vardbapi(dbapi): return x for path in path_iter: - name = os.path.basename(path.rstrip(os.path.sep)) + is_basename = os.sep != path[:1] + if is_basename: + name = path + else: + name = os.path.basename(path.rstrip(os.path.sep)) + if not name: continue @@ -2074,8 +2079,14 @@ class vardbapi(dbapi): if current_hash != hash_value: continue - if dblink(cpv).isowner(path, root): - yield dblink(cpv), path + + if is_basename: + for p in dblink(cpv).getcontents(): + if os.path.basename(p) == name: + yield dblink(cpv), p[len(root):] + else: + if dblink(cpv).isowner(path, root): + yield dblink(cpv), path class vartree(object): "this tree will scan a var/db/pkg database located at root (passed to init)" @@ -4357,7 +4368,7 @@ class dblink(object): # destination file exists if stat.S_ISDIR(mydmode): # install of destination is blocked by an existing directory with the same name - moveme = 0 + cfgprot = 1 showMessage("!!! %s\n" % mydest, level=logging.ERROR, noiselevel=-1) elif stat.S_ISREG(mydmode) or (stat.S_ISLNK(mydmode) and os.path.exists(mydest) and stat.S_ISREG(os.stat(mydest)[stat.ST_MODE])): @@ -4392,8 +4403,8 @@ class dblink(object): """A previously remembered update has been accepted, so it is removed from confmem.""" del cfgfiledict[myrealdest] - if cfgprot: - mydest = new_protect_filename(mydest, newmd5=mymd5) + if cfgprot: + mydest = new_protect_filename(mydest, newmd5=mymd5) # whether config protection or not, we merge the new file the # same way. Unless moveme=0 (blocking directory)