From e15214564896d3cee7739a1a0c23e7263f41f96c Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Wed, 18 Oct 2006 16:51:39 +0000 Subject: [PATCH] Merged from trunk 4740:4753 Filter empty elements in cumulative env-update variables. Thanks to Brian Harring for this patch from bug #151694. Fix CONFIG_PROTECT so that is works with symlinked directories for bug #151502. Make empty digest-* files 0 bytes instead of 1 byte. Thanks to Sven Wegener for reporting this. Eliminate an unnecessary string concatenation. Add more dependency priority levels for merge order calculations. Previously, all installed deps were categorized at the same level with other soft deps. Now there are 3 priority levels for soft deps: satisfied buildtime, satisfied runtime, and other. Remove the unused system slot from DepPriority. Fix --usepkg --newuse logic so that it doesn't throw a KeyError if there's no matching ebuild in the tree. Add __weakref__ to __slots__ so that weakref support isn't disabled. Don't initialize __weakref__ in the DepPriority constructor. All packages to be added to the world favorites via --noreplace, even when --ask is enabled. Thanks to leio for reporting this issue. Explicitly set the priority when a node is added to enforce merge order for blocker avoidance. Handle unresolvable blockers properly for bug #151822. svn path=/main/branches/prefix/; revision=4754 --- bin/emerge | 135 ++++++++++++++++++++++++++++++++++------ pym/portage.py | 32 ++++------ pym/portage_manifest.py | 8 ++- pym/portage_util.py | 10 +++ 4 files changed, 142 insertions(+), 43 deletions(-) diff --git a/bin/emerge b/bin/emerge index 9cbeec6f9..9d18770c0 100755 --- a/bin/emerge +++ b/bin/emerge @@ -630,6 +630,76 @@ def filter_iuse_defaults(iuse): else: yield flag +class DepPriority(object): + """ + This class generates an integer priority level based of various + attributes of the dependency relationship. Attributes can be assigned + at any time and the new integer value will be generated on calls to the + __int__() method. Rich comparison operators are supported. + + The boolean attributes that affect the integer value are "satisfied", + "buildtime", "runtime", and "system". Various combinations of + attributes lead to the following priority levels: + + Combination of properties Priority level + + not satisfied and buildtime 0 + not satisfied and runtime -1 + satisfied and buildtime -2 + satisfied and runtime -3 + (none of the above) -4 + + Several integer constants are defined for categorization of priority + levels: + + MEDIUM The upper boundary for medium dependencies. + SOFT The upper boundary for soft dependencies. + MIN The lower boundary for soft dependencies. + """ + __slots__ = ["__weakref__", "satisfied", "buildtime", "runtime"] + MEDIUM = -1 + SOFT = -2 + MIN = -4 + def __init__(self, **kwargs): + for myattr in self.__slots__: + if myattr == "__weakref__": + continue + myvalue = kwargs.get(myattr, False) + setattr(self, myattr, myvalue) + def __int__(self): + if not self.satisfied: + if self.buildtime: + return 0 + if self.runtime: + return -1 + if self.buildtime: + return -2 + if self.runtime: + return -3 + return -4 + def __lt__(self, other): + return int(self) < other + def __le__(self, other): + return int(self) <= other + def __eq__(self, other): + return int(self) == other + def __ne__(self, other): + return int(self) != other + def __gt__(self, other): + return int(self) > other + def __ge__(self, other): + return int(self) >= other + def copy(self): + import copy + return copy.copy(self) + def __str__(self): + myvalue = int(self) + if myvalue > self.MEDIUM: + return "hard" + if myvalue > self.SOFT: + return "medium" + return "soft" + class depgraph: pkg_tree_map = { @@ -692,7 +762,7 @@ class depgraph: self.blocker_parents = {} def create(self, mybigkey, myparent=None, addme=1, myuse=None, - priority=digraph.HARD, rev_dep=False, arg=None): + priority=DepPriority(), rev_dep=False, arg=None): """ Fills the digraph with nodes comprised of packages to merge. mybigkey is the package spec of the package to merge. @@ -735,7 +805,7 @@ class depgraph: if addme and "--buildpkgonly" not in self.myopts and myparent: mybigkey[1] = myparent.split()[1] self.digraph.addnode(" ".join(mybigkey), myparent, - priority=digraph.SOFT) + priority=DepPriority()) return 1 if not arg: arg = portage.best_match_to_list(mykey, self.args_keys) @@ -846,7 +916,8 @@ class depgraph: try: if not self.select_dep("/", edepend["DEPEND"], myparent=mp, - myuse=myuse, parent_arg=arg): + myuse=myuse, priority=DepPriority(buildtime=True), + parent_arg=arg): return 0 """RDEPEND is soft by definition. However, in order to ensure correct merge order, we make it a hard dependency. Otherwise, a @@ -854,13 +925,15 @@ class depgraph: dependencies not being installed yet. """ if not self.select_dep(myroot,edepend["RDEPEND"], myparent=mp, - myuse=myuse, priority=digraph.MEDIUM, parent_arg=arg): + myuse=myuse, priority=DepPriority(runtime=True), + parent_arg=arg): return 0 if edepend.has_key("PDEPEND") and edepend["PDEPEND"]: # Post Depend -- Add to the list without a parent, as it depends # on a package being present AND must be built after that package. if not self.select_dep(myroot, edepend["PDEPEND"], myparent=mp, - myuse=myuse, priority=digraph.SOFT, rev_deps=True, parent_arg=arg): + myuse=myuse, priority=DepPriority(), rev_deps=True, + parent_arg=arg): return 0 except ValueError, e: pkgs = e.args[0] @@ -1056,8 +1129,8 @@ class depgraph: return match def select_dep(self, myroot, depstring, myparent=None, arg=None, - myuse=None, raise_on_missing=False, priority=digraph.HARD, rev_deps=False, - parent_arg=None): + myuse=None, raise_on_missing=False, priority=DepPriority(), + rev_deps=False, parent_arg=None): """ Given a depstring, create the depgraph such that all dependencies are satisfied. myroot = $ROOT from environment, where {R,P}DEPENDs are merged to. myparent = the node whose depstring is being passed in @@ -1176,7 +1249,10 @@ class depgraph: iuses = set(filter_iuse_defaults( bindb.aux_get(myeb_pkg, ["IUSE"])[0].split())) old_use = bindb.aux_get(myeb_pkg, ["USE"])[0].split() - pkgsettings.setcpv(myeb_pkg, mydb=portdb) + mydb = None + if "--usepkgonly" not in self.myopts and myeb: + mydb = portdb + pkgsettings.setcpv(myeb, mydb=mydb) now_use = pkgsettings["USE"].split() forced_flags = set() forced_flags.update(pkgsettings.useforce) @@ -1302,9 +1378,9 @@ class depgraph: if myparent: #we are a dependency, so we want to be unconditionally added - mypriority = priority - if mypriority > digraph.SOFT and vardb.match(x): - mypriority = digraph.SOFT + mypriority = priority.copy() + if vardb.match(x): + mypriority.satisfied = True if not self.create(selected_pkg[0:3], myparent, myuse=selected_pkg[-1], priority=mypriority, rev_dep=rev_deps, arg=arg): @@ -1357,11 +1433,22 @@ class depgraph: enforce correct merge order.""" fakedb = self.mydbapi[myroot] new_pkgs = [] + unresolveable = False for cpv in blocked_pkgs: myslot = vardb.aux_get(cpv, ["SLOT"])[0] myslot_atom = "%s:%s" % (portage.dep_getkey(cpv), myslot) - new_pkgs.append( - (myslot_atom, fakedb.match(myslot_atom)[0])) + mymatches = fakedb.match(myslot_atom) + if mymatches: + new_pkgs.append((myslot_atom, mymatches[0])) + else: + """There's an installed package that's blocked and + there's no upgrade found to invalidate it, so leave + this blocker in the digraph.""" + unresolveable = True + break + if unresolveable: + continue + for parent in self.digraph.parent_nodes(blocker): ptype, proot, pcpv, pstatus = parent.split() pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi @@ -1374,7 +1461,8 @@ class depgraph: continue # Enforce correct merge order with a hard dep. node = self.pkg_node_map[pkg] - self.digraph.addnode(node, parent) + self.digraph.addnode(node, parent, + priority=DepPriority(buildtime=True)) """Count references to this blocker so that it can be invalidated after nodes referencing it have been merged.""" self.blocker_digraph.addnode(node, blocker) @@ -1399,15 +1487,17 @@ class depgraph: get_nodes = mygraph.root_nodes else: get_nodes = mygraph.leaf_nodes + ignore_priority_range = [None] + ignore_priority_range.extend( + xrange(DepPriority.MIN, DepPriority.MEDIUM + 1)) while not mygraph.empty(): - for ignore_priority in \ - (digraph.NONE, digraph.SOFT, digraph.MEDIUM): + for ignore_priority in ignore_priority_range: nodes = get_nodes(ignore_priority=ignore_priority) if nodes: break selected_nodes = None if nodes: - if ignore_priority <= digraph.SOFT: + if ignore_priority <= DepPriority.SOFT: selected_nodes = [nodes[0]] else: """Recursively gather a group of nodes that RDEPEND on @@ -1420,7 +1510,7 @@ class depgraph: return False selected_nodes.add(node) for child in mygraph.child_nodes(node, - ignore_priority=digraph.SOFT): + ignore_priority=DepPriority.SOFT): if not gather_deps( mergeable_nodes, selected_nodes, child): return False @@ -1477,7 +1567,7 @@ class depgraph: for node in myblockers.root_nodes(): retlist.append(node.split()) for parent in self.blocker_parents[node]: - self.digraph.add(node, parent, priority=digraph.SOFT) + self.digraph.add(node, parent, priority=DepPriority()) return retlist @@ -3826,7 +3916,12 @@ def action_build(settings, trees, mtimedb, show_blocker_docs_link() sys.exit(1) if mergecount==0: - if settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]: + if "--noreplace" in myopts and favorites: + print + for x in favorites: + print " %s %s" % (good("*"), x) + prompt="Would you like to add these packages to your world favorites?" + elif settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]: prompt="Nothing to merge; would you like to auto-clean packages?" else: print diff --git a/pym/portage.py b/pym/portage.py index 8b0c9d7a3..21b2b4442 100644 --- a/pym/portage.py +++ b/pym/portage.py @@ -312,10 +312,6 @@ def flatten(mytokens): #beautiful directed graph object class digraph: - NONE = -1 - SOFT = 0 - MEDIUM = 1 - HARD = 2 def __init__(self): """Create an empty digraph""" @@ -323,7 +319,7 @@ class digraph: self.nodes = {} self.order = [] - def add(self, node, parent, priority=2): + def add(self, node, parent, priority=0): """Adds the specified node with the specified parent. If the dep is a soft-dep and the node already has a hard @@ -376,9 +372,9 @@ class digraph: """Return a list of all nodes in the graph""" return self.order[:] - def child_nodes(self, node, ignore_priority=-1): + def child_nodes(self, node, ignore_priority=None): """Return all children of the specified node""" - if ignore_priority == -1: + if ignore_priority is None: return self.nodes[node][0].keys() children = [] for child, priority in self.nodes[node][0].iteritems(): @@ -390,7 +386,7 @@ class digraph: """Return all parents of the specified node""" return self.nodes[node][1].keys() - def leaf_nodes(self, ignore_priority=-1): + def leaf_nodes(self, ignore_priority=None): """Return all nodes that have no children If ignore_soft_deps is True, soft deps are not counted as @@ -407,7 +403,7 @@ class digraph: leaf_nodes.append(node) return leaf_nodes - def root_nodes(self, ignore_priority=-1): + def root_nodes(self, ignore_priority=None): """Return all nodes that have no parents. If ignore_soft_deps is True, soft deps are not counted as @@ -454,7 +450,7 @@ class digraph: return leaf_nodes[0] return None - def hasallzeros(self, ignore_priority=-1): + def hasallzeros(self, ignore_priority=None): return len(self.leaf_nodes(ignore_priority=ignore_priority)) == \ len(self.order) @@ -467,12 +463,7 @@ class digraph: print "(no children)" for child in self.nodes[node][0]: print " ",child, - if self.nodes[node][0][child] == self.HARD: - print "(hard)" - elif self.nodes[node][0][child] == self.MEDIUM: - print "(medium)" - else: - print "(soft)" + print "(%s)" % self.nodes[node][0][child] @@ -593,7 +584,7 @@ def env_update(makelinks=1, target_root=None, prev_mtimes=None, contents=None): mylist = [] for myconfig in config_list: if var in myconfig: - mylist.extend(myconfig[var].split()) + mylist.extend(filter(None, myconfig[var].split())) del myconfig[var] # prepare for env.update(myconfig) if mylist: env[var] = " ".join(mylist) @@ -603,7 +594,7 @@ def env_update(makelinks=1, target_root=None, prev_mtimes=None, contents=None): mylist = [] for myconfig in config_list: if var in myconfig: - mylist.extend(myconfig[var].split(":")) + mylist.extend(filter(None, myconfig[var].split(":"))) del myconfig[var] # prepare for env.update(myconfig) if mylist: env[var] = ":".join(mylist) @@ -1530,13 +1521,12 @@ class config: self.configdict["pkginternal"]["USE"] = pkginternaluse defaults = [] for i in xrange(len(self.profiles)): - profile_use = self.make_defaults_use[i] + defaults.append(self.make_defaults_use[i]) cpdict = self.pkgprofileuse[i].get(cp, None) if cpdict: best_match = best_match_to_list(self.mycpv, cpdict.keys()) if best_match: - profile_use += " " + cpdict[best_match] - defaults.append(profile_use) + defaults.append(cpdict[best_match]) self.configdict["defaults"]["USE"] = " ".join(defaults) useforce = [] for i in xrange(len(self.profiles)): diff --git a/pym/portage_manifest.py b/pym/portage_manifest.py index aa6f0c015..1266e33df 100644 --- a/pym/portage_manifest.py +++ b/pym/portage_manifest.py @@ -252,8 +252,12 @@ class Manifest(object): else: raise if update_digest: - write_atomic(dname, - "\n".join(self._createDigestLines1(distlist, self.fhashdict))+"\n") + mylines = self._createDigestLines1(distlist, self.fhashdict) + if mylines: + mylines = "\n".join(mylines) + "\n" + else: + mylines = "" + write_atomic(dname, mylines) rval.append(dname) return rval diff --git a/pym/portage_util.py b/pym/portage_util.py index 81f842044..bfa0554e8 100644 --- a/pym/portage_util.py +++ b/pym/portage_util.py @@ -848,9 +848,14 @@ class ConfigProtect(object): os.path.join(self.myroot, x.lstrip(os.path.sep))) mystat = None try: + """Use lstat so that anything, even a broken symlink can be + protected.""" if stat.S_ISDIR(os.lstat(ppath).st_mode): self._dirs.add(ppath) self.protect.append(ppath) + """Now use stat in case this is a symlink to a directory.""" + if stat.S_ISDIR(os.stat(ppath).st_mode): + self._dirs.add(ppath) except OSError: # If it doesn't exist, there's no need to protect it. pass @@ -861,9 +866,14 @@ class ConfigProtect(object): os.path.join(self.myroot, x.lstrip(os.path.sep))) mystat = None try: + """Use lstat so that anything, even a broken symlink can be + protected.""" if stat.S_ISDIR(os.lstat(ppath).st_mode): self._dirs.add(ppath) self.protectmask.append(ppath) + """Now use stat in case this is a symlink to a directory.""" + if stat.S_ISDIR(os.stat(ppath).st_mode): + self._dirs.add(ppath) except OSError: # If it doesn't exist, there's no need to mask it. pass -- 2.26.2