mirror of
				https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
				synced 2025-11-04 10:34:05 +00:00 
			
		
		
		
	Rewrite the main run to use the solver and allow combined migrations
Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
		
							parent
							
								
									65f74c226d
								
							
						
					
					
						commit
						326cc0d98b
					
				
							
								
								
									
										130
									
								
								britney.py
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								britney.py
									
									
									
									
									
								
							@ -2233,7 +2233,7 @@ class Britney(object):
 | 
			
		||||
        if len(actions) == 1:
 | 
			
		||||
            item = actions[0]
 | 
			
		||||
            # apply the changes
 | 
			
		||||
            affected, undo = self.doop_source(item, lundo)
 | 
			
		||||
            affected, undo = self.doop_source(item, hint_undo=lundo)
 | 
			
		||||
            undo_list = [(undo, item)]
 | 
			
		||||
            if item.architecture == 'source':
 | 
			
		||||
                affected_architectures = set(self.options.architectures)
 | 
			
		||||
@ -2256,6 +2256,7 @@ class Britney(object):
 | 
			
		||||
 | 
			
		||||
            for item in actions:
 | 
			
		||||
                item_affected, undo = self.doop_source(item,
 | 
			
		||||
                                                       hint_undo=lundo,
 | 
			
		||||
                                                       removals=removals)
 | 
			
		||||
                affected.update(item_affected)
 | 
			
		||||
                undo_list.append((undo, item))
 | 
			
		||||
@ -2301,82 +2302,66 @@ class Britney(object):
 | 
			
		||||
        final result is successful, otherwise (None, None).
 | 
			
		||||
        """
 | 
			
		||||
        extra = []
 | 
			
		||||
        deferred = []
 | 
			
		||||
        skipped = []
 | 
			
		||||
        mark_passed = False
 | 
			
		||||
        position = len(packages)
 | 
			
		||||
        groups = set()
 | 
			
		||||
        for y in sorted((y for y in packages), key=attrgetter('uvname')):
 | 
			
		||||
            updates, rms, _ = self._compute_groups(y.package, y.suite, y.architecture, y.is_removal)
 | 
			
		||||
            groups.add((y, frozenset(updates), frozenset(rms)))
 | 
			
		||||
 | 
			
		||||
        if selected is None:
 | 
			
		||||
            selected = []
 | 
			
		||||
        if nuninst:
 | 
			
		||||
            nuninst_comp = nuninst
 | 
			
		||||
            nuninst_orig = nuninst
 | 
			
		||||
        else:
 | 
			
		||||
            nuninst_comp = self.nuninst_orig
 | 
			
		||||
 | 
			
		||||
        # local copies for better performance
 | 
			
		||||
        dependencies = self.dependencies
 | 
			
		||||
 | 
			
		||||
            nuninst_orig = self.nuninst_orig
 | 
			
		||||
        nuninst_last_accepted = nuninst_orig
 | 
			
		||||
        maybe_reschuled = []
 | 
			
		||||
        worklist = self._inst_tester.solve_groups(groups)
 | 
			
		||||
        worklist.reverse()
 | 
			
		||||
        self.output_write("recur: [] %s %d/%d\n" % (",".join(x.uvname for x in selected), len(packages), len(extra)))
 | 
			
		||||
 | 
			
		||||
        # loop on the packages (or better, actions)
 | 
			
		||||
        while packages:
 | 
			
		||||
            item = packages.pop(0)
 | 
			
		||||
 | 
			
		||||
            # this is the marker for the first loop
 | 
			
		||||
            if not mark_passed and position < 0:
 | 
			
		||||
                mark_passed = True
 | 
			
		||||
                packages.extend(deferred)
 | 
			
		||||
                del deferred
 | 
			
		||||
            else: position -= 1
 | 
			
		||||
 | 
			
		||||
            # defer packages if their dependency has been already skipped
 | 
			
		||||
            if not mark_passed:
 | 
			
		||||
                defer = False
 | 
			
		||||
                for p in dependencies.get(item, []):
 | 
			
		||||
                    if p in skipped:
 | 
			
		||||
                        deferred.append(item)
 | 
			
		||||
                        skipped.append(item)
 | 
			
		||||
                        defer = True
 | 
			
		||||
                        break
 | 
			
		||||
                if defer: continue
 | 
			
		||||
 | 
			
		||||
            self.output_write("trying: %s\n" % (item.uvname))
 | 
			
		||||
 | 
			
		||||
            (better, nuninst, undo_list, arch) = self.try_migration([item], nuninst_comp, lundo=lundo)
 | 
			
		||||
 | 
			
		||||
            # check if the action improved the uninstallability counters
 | 
			
		||||
            if better:
 | 
			
		||||
        while worklist:
 | 
			
		||||
            comp = worklist.pop()
 | 
			
		||||
            comp_name = ' '.join(item.uvname for item in comp)
 | 
			
		||||
            self.output_write("trying: %s\n" % comp_name)
 | 
			
		||||
            accepted, nuninst_after, comp_undo, failed_arch = self.try_migration(comp, nuninst_last_accepted, lundo)
 | 
			
		||||
            if accepted:
 | 
			
		||||
                nuninst_last_accepted = nuninst_after
 | 
			
		||||
                selected.extend(comp)
 | 
			
		||||
                if lundo is not None:
 | 
			
		||||
                    lundo.extend(undo_list)
 | 
			
		||||
                selected.append(item)
 | 
			
		||||
                packages.extend(extra)
 | 
			
		||||
                extra = []
 | 
			
		||||
                self.output_write("accepted: %s\n" % (item.uvname))
 | 
			
		||||
                self.output_write("   ori: %s\n" % (self.eval_nuninst(self.nuninst_orig)))
 | 
			
		||||
                self.output_write("   pre: %s\n" % (self.eval_nuninst(nuninst_comp)))
 | 
			
		||||
                self.output_write("   now: %s\n" % (self.eval_nuninst(nuninst, nuninst_comp)))
 | 
			
		||||
                    lundo.extend(comp_undo)
 | 
			
		||||
                self.output_write("accepted: %s\n" % comp_name)
 | 
			
		||||
                self.output_write("   ori: %s\n" % (self.eval_nuninst(nuninst_orig)))
 | 
			
		||||
                self.output_write("   pre: %s\n" % (self.eval_nuninst(nuninst_last_accepted)))
 | 
			
		||||
                self.output_write("   now: %s\n" % (self.eval_nuninst(nuninst_after)))
 | 
			
		||||
                if len(selected) <= 20:
 | 
			
		||||
                    self.output_write("   all: %s\n" % (" ".join( x.uvname for x in selected )))
 | 
			
		||||
                    self.output_write("   all: %s\n" % (" ".join(x.uvname for x in selected)))
 | 
			
		||||
                else:
 | 
			
		||||
                    self.output_write("  most: (%d) .. %s\n" % (len(selected), " ".join(x.uvname for x in selected[-20:])))
 | 
			
		||||
                nuninst_comp = nuninst
 | 
			
		||||
            else:
 | 
			
		||||
                broken = sorted(b for b in nuninst_after[failed_arch]
 | 
			
		||||
                                if b not in nuninst_last_accepted[failed_arch])
 | 
			
		||||
                compare_nuninst = None
 | 
			
		||||
                if any(item for item in comp if item.architecture != 'source'):
 | 
			
		||||
                    compare_nuninst = nuninst_last_accepted
 | 
			
		||||
                # NB: try_migration already reverted this for us, so just print the results and move on
 | 
			
		||||
                self.output_write("skipped: %s (%d <- %d)\n" % (item.uvname, len(extra), len(packages)))
 | 
			
		||||
                self.output_write("    got: %s\n" % (self.eval_nuninst(nuninst, item.architecture != 'source' and nuninst_comp or None)))
 | 
			
		||||
                self.output_write("    * %s: %s\n" % (arch, ", ".join(sorted(b for b in nuninst[arch] if b not in nuninst_comp[arch]))))
 | 
			
		||||
 | 
			
		||||
                extra.append(item)
 | 
			
		||||
                if not mark_passed:
 | 
			
		||||
                    skipped.append(item)
 | 
			
		||||
                self.output_write("skipped: %s (%d, %d)\n" % (comp_name, len(maybe_reschuled), len(worklist)))
 | 
			
		||||
                self.output_write("    got: %s\n" % (self.eval_nuninst(nuninst_after, compare_nuninst)))
 | 
			
		||||
                self.output_write("    * %s: %s\n" % (failed_arch, ", ".join(broken)))
 | 
			
		||||
 | 
			
		||||
                if len(comp) > 1:
 | 
			
		||||
                    self.output_write("    - splitting the component into single items and retrying them\n")
 | 
			
		||||
                    worklist.extend([item] for item in comp)
 | 
			
		||||
                else:
 | 
			
		||||
                    extra.extend(comp)
 | 
			
		||||
 | 
			
		||||
        self.output_write(" finish: [%s]\n" % ",".join( x.uvname for x in selected ))
 | 
			
		||||
        self.output_write("endloop: %s\n" % (self.eval_nuninst(self.nuninst_orig)))
 | 
			
		||||
        self.output_write("    now: %s\n" % (self.eval_nuninst(nuninst_comp)))
 | 
			
		||||
        self.output_write("    now: %s\n" % (self.eval_nuninst(nuninst_last_accepted)))
 | 
			
		||||
        self.output_write(eval_uninst(self.options.architectures,
 | 
			
		||||
                                      newly_uninst(self.nuninst_orig, nuninst_comp)))
 | 
			
		||||
                                      newly_uninst(self.nuninst_orig, nuninst_last_accepted)))
 | 
			
		||||
        self.output_write("\n")
 | 
			
		||||
 | 
			
		||||
        return (nuninst_comp, extra)
 | 
			
		||||
        return (nuninst_last_accepted, extra)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def do_all(self, hinttype=None, init=None, actions=None):
 | 
			
		||||
@ -2807,11 +2792,10 @@ class Britney(object):
 | 
			
		||||
        self.upgrade_me = [ make_migrationitem(x, self.sources) for x in upgrade_me ]
 | 
			
		||||
        self.upgrade_me.extend(make_migrationitem(x, self.sources) for x in removals)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def auto_hinter(self):
 | 
			
		||||
        """Auto-generate "easy" hints.
 | 
			
		||||
 | 
			
		||||
        This method attempts to generate "easy" hints for sets of packages which    
 | 
			
		||||
        This method attempts to generate "easy" hints for sets of packages which
 | 
			
		||||
        must migrate together. Beginning with a package which does not depend on
 | 
			
		||||
        any other package (in terms of excuses), a list of dependencies and
 | 
			
		||||
        reverse dependencies is recursively created.
 | 
			
		||||
@ -2824,7 +2808,7 @@ class Britney(object):
 | 
			
		||||
        excuses relationships. If they build a circular dependency, which we already
 | 
			
		||||
        know as not-working with the standard do_all algorithm, try to `easy` them.
 | 
			
		||||
        """
 | 
			
		||||
        self.__log("> Processing hints from the auto hinter [Partial-ordering]",
 | 
			
		||||
        self.__log("> Processing hints from the auto hinter",
 | 
			
		||||
                   type="I")
 | 
			
		||||
 | 
			
		||||
        # consider only excuses which are valid candidates
 | 
			
		||||
@ -2833,28 +2817,6 @@ class Britney(object):
 | 
			
		||||
        excuses_deps = dict((name, set(excuse.deps)) for name, excuse in excuses.items())
 | 
			
		||||
        sources_t = self.sources['testing']
 | 
			
		||||
 | 
			
		||||
        groups = set()
 | 
			
		||||
        for y in sorted((y for y in self.upgrade_me if y.uvname in excuses), key=attrgetter('uvname')):
 | 
			
		||||
            if y.is_removal and y.package not in sources_t:
 | 
			
		||||
                # Already removed
 | 
			
		||||
                continue
 | 
			
		||||
            if not y.is_removal:
 | 
			
		||||
                excuse = excuses[y.uvname]
 | 
			
		||||
                if y.architecture == 'source' and y.uvname in sources_t and sources_t[y.uvname][VERSION] == excuse.ver[1]:
 | 
			
		||||
                    # Already migrated
 | 
			
		||||
                    continue
 | 
			
		||||
            adds, rms, _ = self._compute_groups(y.package, y.suite,
 | 
			
		||||
                                                y.architecture, y.is_removal,
 | 
			
		||||
                                                include_hijacked=True)
 | 
			
		||||
            groups.add((y, frozenset(adds), frozenset(rms)))
 | 
			
		||||
 | 
			
		||||
        for comp in self._inst_tester.solve_groups(groups):
 | 
			
		||||
            if len(comp) > 1:
 | 
			
		||||
                self.do_hint("easy", "autohinter", comp)
 | 
			
		||||
 | 
			
		||||
        self.__log("> Processing hints from the auto hinter [Original]",
 | 
			
		||||
                   type="I")
 | 
			
		||||
 | 
			
		||||
        def find_related(e, hint, circular_first=False):
 | 
			
		||||
            if e not in excuses:
 | 
			
		||||
                return False
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user