From ce75e33817ec9f3021c1eee434eb10060373e5c5 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Tue, 15 Apr 2008 18:14:49 +0000 Subject: [PATCH] Merged from trunk 9894:9906 | 9895 | Fix issues with an empty string being passed into | | zmedico | PreservedLibsRegistry.register() now that COUNTER is not | | | loaded via config.load_infodir(). Thanks to grobian for | | | reporting. | | 9896 | In config.setcpv() and regenerate(), replace | | zmedico | str.startswith() calls with slice comparison. It's not | | | pretty but performance is critical in this section of code | | | and there is a measurable performance difference. | | 9898 | Bug #217664 - Fix emerge 'by path' package argument handling | | zmedico | so that Package instances are properly cached (avoiding a | | | KeyError later). | | 9900 | Revert part of atom selection consistency improvement from | | zmedico | r9873 since it in some cases it triggers unresolvable direct | | | circular dependencies. For example, this happens with | | | gwydion-dylan which depends on either itself or | | | gwydion-dylan-bin. In case gwydion-dylan is not yet | | | installed, gwydion-dylan-bin needs to be selected in order | | | to avoid a an unresolvable direct circular dependency. | | 9901 | Add support to depgraph._select_atoms() to take a "parent" | | zmedico | parameter and use that to try and avoid unresolvable direct | | | circular dependencies when necessary. Also, make atom | | | selection more consistent with the graph to solve some cases | | | of bug #1343. This improves the fix from bug #141118 to work | | | in cases when a virtual is not yet installed but it has been | | | pulled into the graph. For example, see the case of in Bug | | | #163801#c17, where we want kaffe to satisfy virtual/jdk-1.4 | | | without an extra jvm being pulled in unnecessarily. | | 9904 | Comment some more on the significance of passing the | | zmedico | graph_db and parent into depgraph._select_atoms() to solve | | | some cases of bug #1343 while avoiding unresolvable direct | | | circular dependencies. | | 9906 | The dependency resolver now has a feedback mechanism that | | zmedico | helps make atom selections more consistent with previous | | | selections that have been added to the graph. This solves | | | some common cases of bug #1343. | svn path=/main/branches/prefix/; revision=9909 --- NEWS | 7 +++++ pym/_emerge/__init__.py | 31 +++++++++++++++++++-- pym/portage/__init__.py | 53 ++++++++++++++++++++++++++++++++---- pym/portage/dbapi/vartree.py | 7 ++++- 4 files changed, 88 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 243ef7ecc..520f2c732 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,13 @@ portage-2.2 * Add support for news items (GLEP 42) * Add support for generic package sets (also see RELEASE-NOTES) +portage-2.1.5 +================================== + +* The dependency resolver now has a feedback mechanism that helps make atom + selections more consistent with previous selections that have been added to + the graph. This solves some common cases of bug #1343. + portage-2.1.4 ------------- diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 522115ddf..c8c8d0168 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -1626,11 +1626,30 @@ class depgraph(object): # have already been made. self._graph_trees[myroot]["porttree"] = graph_tree self._graph_trees[myroot]["vartree"] = graph_tree - self._filtered_trees[myroot]["vartree"] = graph_tree def filtered_tree(): pass filtered_tree.dbapi = self._dep_check_composite_db(self, myroot) self._filtered_trees[myroot]["porttree"] = filtered_tree + + # Passing in graph_tree as the vartree here could lead to better + # atom selections in some cases by causing atoms for packages that + # have been added to the graph to be preferred over other choices. + # However, it can trigger atom selections that result in + # unresolvable direct circular dependencies. For example, this + # happens with gwydion-dylan which depends on either itself or + # gwydion-dylan-bin. In case gwydion-dylan is not yet installed, + # gwydion-dylan-bin needs to be selected in order to avoid a + # an unresolvable direct circular dependency. + # + # To solve the problem described above, pass in "graph_db" so that + # packages that have been added to the graph are distinguishable + # from other available packages and installed packages. Also, pass + # the parent package into self._select_atoms() calls so that + # unresolvable direct circular dependencies can be detected and + # avoided when possible. + self._filtered_trees[myroot]["graph_db"] = graph_tree.dbapi + self._filtered_trees[myroot]["vartree"] = self.trees[myroot]["vartree"] + dbs = [] portdb = self.trees[myroot]["porttree"].dbapi bindb = self.trees[myroot]["bintree"].dbapi @@ -2080,7 +2099,7 @@ class depgraph(object): vardb = self.roots[dep_root].trees["vartree"].dbapi try: selected_atoms = self._select_atoms(dep_root, - dep_string, myuse=myuse, strict=strict) + dep_string, myuse=myuse, parent=pkg, strict=strict) except portage.exception.InvalidDependString, e: show_invalid_depstring_notice(jbigkey, dep_string, str(e)) return 0 @@ -2219,6 +2238,7 @@ class depgraph(object): pkg = Package(type_name="binary", root=myroot, cpv=mykey, built=True, metadata=metadata, onlydeps=onlydeps) + self._pkg_cache[pkg] = pkg args.append(PackageArg(arg=x, package=pkg, root_config=root_config)) elif ext==".ebuild": @@ -2257,6 +2277,7 @@ class depgraph(object): metadata["USE"] = pkgsettings["PORTAGE_USE"] pkg = Package(type_name="ebuild", root=myroot, cpv=mykey, metadata=metadata, onlydeps=onlydeps) + self._pkg_cache[pkg] = pkg args.append(PackageArg(arg=x, package=pkg, root_config=root_config)) elif x.startswith(os.path.sep): @@ -2536,7 +2557,7 @@ class depgraph(object): return self._select_atoms_highest_available(*pargs, **kwargs) def _select_atoms_highest_available(self, root, depstring, - myuse=None, strict=True, trees=None): + myuse=None, parent=None, strict=True, trees=None): """This will raise InvalidDependString if necessary. If trees is None then self._filtered_trees is used.""" pkgsettings = self.pkgsettings[root] @@ -2544,12 +2565,16 @@ class depgraph(object): trees = self._filtered_trees if True: try: + if parent is not None: + trees[root]["parent"] = parent if not strict: portage.dep._dep_check_strict = False mycheck = portage.dep_check(depstring, None, pkgsettings, myuse=myuse, myroot=root, trees=trees) finally: + if parent is not None: + trees[root].pop("parent") portage.dep._dep_check_strict = True if not mycheck[0]: raise portage.exception.InvalidDependString(mycheck[1]) diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 7554b8159..7cc2e9963 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -2052,13 +2052,14 @@ class config(object): self.usemask.discard("test") # Use the calculated USE flags to regenerate the USE_EXPAND flags so - # that they are consistent. + # that they are consistent. For optimal performance, use slice + # comparison instead of startswith(). use_expand = self.get("USE_EXPAND", "").split() for var in use_expand: prefix = var.lower() + "_" prefix_len = len(prefix) expand_flags = set([ x[prefix_len:] for x in use \ - if x.startswith(prefix) ]) + if x[:prefix_len] == prefix ]) var_split = self.get(var, "").split() # Preserve the order of var_split because it can matter for things # like LINGUAS. @@ -2069,13 +2070,13 @@ class config(object): var_split = [ x for x in var_split if x != "*" ] has_iuse = set() for x in iuse_implicit: - if x.startswith(prefix): + if x[:prefix_len] == prefix: has_iuse.add(x[prefix_len:]) if has_wildcard: # * means to enable everything in IUSE that's not masked if has_iuse: for x in iuse_implicit: - if x.startswith(prefix) and x not in self.usemask: + if x[:prefix_len] == prefix and x not in self.usemask: suffix = x[prefix_len:] var_split.append(suffix) use.add(x) @@ -2469,6 +2470,8 @@ class config(object): self.uvlist.append(self.configdict[x]) self.uvlist.reverse() + # For optimal performance, use slice + # comparison instead of startswith(). myflags = set() for curdb in self.uvlist: cur_use_expand = [x for x in use_expand if x in curdb] @@ -2498,8 +2501,9 @@ class config(object): is_not_incremental = var not in myincrementals if is_not_incremental: prefix = var_lower + "_" + prefix_len = len(prefix) for x in list(myflags): - if x.startswith(prefix): + if x[:prefix_len] == prefix: myflags.remove(x) for x in curdb[var].split(): if x[0] == "+": @@ -5514,6 +5518,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): other = [] # Alias the trees we'll be checking availability against + parent = trees[myroot].get("parent") + graph_db = trees[myroot].get("graph_db") vardb = None if "vartree" in trees[myroot]: vardb = trees[myroot]["vartree"].dbapi @@ -5575,8 +5581,43 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): preferred.append(this_choice) else: preferred_any_slot.append(this_choice) - else: + elif graph_db is None: possible_upgrades.append(this_choice) + else: + all_in_graph = True + for slot_atom in versions: + # New-style virtuals have zero cost to install. + if not graph_db.match(slot_atom) and \ + not slot_atom.startswith("virtual/"): + all_in_graph = False + break + if all_in_graph: + if parent is None: + preferred.append(this_choice) + else: + # Check if the atom would result in a direct circular + # dependency and try to avoid that if it seems likely + # to be unresolvable. + cpv_slot_list = [parent.cpv_slot] + circular_atom = None + for atom in atoms: + if "!" == atom[:1]: + continue + if vardb.match(atom): + # If the atom is satisfied by an installed + # version then it's not a circular dep. + continue + if dep_getkey(atom) != parent.cp: + continue + if match_from_list(atom, cpv_slot_list): + circular_atom = atom + break + if circular_atom is None: + preferred.append(this_choice) + else: + other.append(this_choice) + else: + possible_upgrades.append(this_choice) else: other.append(this_choice) diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 269468224..ec88a921a 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -1186,7 +1186,8 @@ class dblink(object): # Remove the registration of preserved libs for this pkg instance plib_registry = self.vartree.dbapi.plib_registry - plib_registry.unregister(self.mycpv, self.settings["SLOT"], self.settings["COUNTER"]) + plib_registry.unregister(self.mycpv, self.settings["SLOT"], + self.vartree.dbapi.cpv_counter(self.mycpv)) if myebuildpath: ebuild_phase = "postrm" @@ -1919,6 +1920,10 @@ class dblink(object): # has to be before the counter is written) - genone counter = self.vartree.dbapi.counter_tick(self.myroot, mycpv=self.mycpv) + # Save this for unregistering preserved-libs if the merge fails. + self.settings["COUNTER"] = str(counter) + self.settings.backup_changes("COUNTER") + myfilelist = [] mylinklist = [] def onerror(e): -- 2.26.2