Index: parallel_emerge |
diff --git a/parallel_emerge b/parallel_emerge |
index 6516c29f5ece1a7080a582825fa30f4e59a6c2fc..930f53dcd6f1982d92000cb2a74421378182ecb8 100755 |
--- a/parallel_emerge |
+++ b/parallel_emerge |
@@ -76,7 +76,8 @@ if "PORTAGE_USERNAME" not in os.environ: |
from _emerge.actions import adjust_configs |
from _emerge.actions import load_emerge_config |
from _emerge.create_depgraph_params import create_depgraph_params |
-from _emerge.depgraph import backtrack_depgraph |
+from _emerge.depgraph import depgraph as emerge_depgraph |
+from _emerge.depgraph import _frozen_depgraph_config |
from _emerge.main import emerge_main |
from _emerge.main import parse_opts |
from _emerge.Package import Package |
@@ -479,24 +480,9 @@ class DepGraphGenerator(object): |
cur_iuse, now_use, now_iuse) |
return not flags |
- def GenDependencyTree(self, remote_pkgs): |
- """Get dependency tree info from emerge. |
- |
- TODO(): Update cros_extract_deps to also use this code. |
- Returns: |
- Dependency tree |
- """ |
- start = time.time() |
- |
+ def CreateDepgraph(self, emerge, packages): |
+ """Create an emerge depgraph object.""" |
# Setup emerge options. |
- # |
- # We treat dependency info a bit differently than emerge itself. Unless |
- # you're using --usepkgonly, we disable --getbinpkg and --usepkg here so |
- # that emerge will look at the dependencies of the source ebuilds rather |
- # than the binary dependencies. This helps ensure that we have the option |
- # of merging a package from source, if we want to switch to it with |
- # --workon and the dependencies have changed. |
- emerge = self.emerge |
emerge_opts = emerge.opts.copy() |
# Enable --emptytree so that we get the full tree, which we need for |
@@ -507,12 +493,86 @@ class DepGraphGenerator(object): |
emerge_opts["--tree"] = True |
emerge_opts["--emptytree"] = True |
- # Tell emerge not to worry about use flags yet. We handle those inside |
- # parallel_emerge itself. Further, when we use the --force-remote-binary |
- # flag, we don't emerge to reject a package just because it has different |
- # use flags. |
- emerge_opts.pop("--newuse", None) |
- emerge_opts.pop("--reinstall", None) |
+ # Set up parameters. |
+ params = create_depgraph_params(emerge_opts, emerge.action) |
+ frozen_config = _frozen_depgraph_config(emerge.settings, emerge.trees, |
+ emerge_opts, emerge.spinner) |
+ backtrack_max = emerge_opts.get('--backtrack', 5) |
+ runtime_pkg_mask = None |
+ allow_backtracking = backtrack_max > 0 |
+ |
+ # Try up to backtrack_max times to create a working depgraph. Each time we |
+ # run into a conflict, mask the offending package and try again. |
+ # TODO(davidjames): When Portage supports --force-remote-binary directly, |
+ # switch back to using the backtrack_depgraph function. |
+ for i in range(backtrack_max + 1): |
+ if i == backtrack_max: |
+ # Looks like we hit the backtracking limit. Run the dependency |
+ # calculation one more time (from scratch) to show the original error |
+ # message. |
+ runtime_pkg_mask = None |
+ allow_backtracking = False |
+ |
+ # Create a depgraph object. |
+ depgraph = emerge_depgraph(emerge.settings, emerge.trees, emerge_opts, |
+ params, emerge.spinner, frozen_config=frozen_config, |
+ allow_backtracking=allow_backtracking, |
+ runtime_pkg_mask=runtime_pkg_mask) |
+ |
+ if i == 0: |
+ for cpv in self.forced_remote_binary_packages: |
+ # If --force-remote-binary was specified, we want to use this package |
+ # regardless of its use flags. Unfortunately, Portage doesn't support |
+ # ignoring use flags for just one package. To convince Portage to |
+ # install the package, we trick Portage into thinking the package has |
+ # the right use flags. |
+ # TODO(davidjames): Update Portage to support --force-remote-binary |
+ # directly, so that this hack isn't necessary. |
+ pkg = depgraph._pkg(cpv, "binary", emerge.root_config) |
+ pkgsettings = frozen_config.pkgsettings[pkg.root] |
+ pkgsettings.setcpv(pkg) |
+ pkg.use.enabled = pkgsettings["PORTAGE_USE"].split() |
+ |
+ # Select the packages we want. |
+ success, favorites = depgraph.select_files(packages) |
+ if success: |
+ break |
+ elif depgraph.need_restart(): |
+ # Looks like we found some packages that can't be installed due to |
+ # conflicts. Try again, masking out the conflicting packages. |
+ runtime_pkg_mask = depgraph.get_runtime_pkg_mask() |
+ elif allow_backtracking and i > 0: |
+ # Looks like we tried all the possible combinations, and we still can't |
+ # solve the graph. Stop backtracking, so that we can report an error |
+ # message. |
+ runtime_pkg_mask = None |
+ allow_backtracking = False |
+ else: |
+ break |
+ |
+ # Delete the --tree option, because we don't really want to display a |
+ # tree. We just wanted to get emerge to leave uninstall instructions on |
+ # the graph. Later, when we display the graph, we'll want standard-looking |
+ # output, so removing the --tree option is important. |
+ frozen_config.myopts.pop("--tree", None) |
+ |
+ emerge.depgraph = depgraph |
+ |
+ # Is it impossible to honor the user's request? Bail! |
+ if not success: |
+ depgraph.display_problems() |
+ sys.exit(1) |
+ |
+ def GenDependencyTree(self, remote_pkgs): |
+ """Get dependency tree info from emerge. |
+ |
+ TODO(): Update cros_extract_deps to also use this code. |
+ Returns: |
+ Dependency tree |
+ """ |
+ start = time.time() |
+ |
+ emerge = self.emerge |
# Create a list of packages to merge |
packages = set(emerge.cmdline_packages[:]) |
@@ -527,9 +587,17 @@ class DepGraphGenerator(object): |
full_pkgname in self.force_remote_binary): |
forced_pkgs.setdefault(full_pkgname, []).append(pkg) |
+ # Add forced binary packages to the dependency list. This is necessary |
+ # to ensure that the install plan contains the right package. |
+ # |
+ # Putting the forced binary package at the beginning of the list is an |
+ # optimization that helps avoid unnecessary backtracking (e.g., if |
+ # Portage first selects the wrong version, and then backtracks later, it |
+ # takes a bit longer and uses up an unnecessary backtrack iteration.) |
+ packages = list(packages) |
for pkgs in forced_pkgs.values(): |
forced_package = portage.versions.best(pkgs) |
- packages.add("=%s" % forced_package) |
+ packages.insert(0, "=%s" % forced_package) |
self.forced_remote_binary_packages.add(forced_package) |
# Tell emerge to be quiet. We print plenty of info ourselves so we don't |
@@ -544,18 +612,8 @@ class DepGraphGenerator(object): |
if "--quiet" not in emerge.opts: |
print "Calculating deps..." |
- # Ask portage to build a dependency graph. with the options we specified |
- # above. |
- params = create_depgraph_params(emerge_opts, emerge.action) |
- success, depgraph, _ = backtrack_depgraph( |
- emerge.settings, emerge.trees, emerge_opts, params, emerge.action, |
- packages, emerge.spinner) |
- emerge.depgraph = depgraph |
- |
- # Is it impossible to honor the user's request? Bail! |
- if not success: |
- depgraph.display_problems() |
- sys.exit(1) |
+ self.CreateDepgraph(emerge, packages) |
+ depgraph = emerge.depgraph |
# Build our own tree from the emerge digraph. |
deps_tree = {} |
@@ -604,11 +662,6 @@ class DepGraphGenerator(object): |
vardb = frozen_config.trees[root]["vartree"].dbapi |
pkgsettings = frozen_config.pkgsettings[root] |
- # It's time to start worrying about use flags, if necessary. |
- for flag in ("--newuse", "--reinstall"): |
- if flag in emerge.opts: |
- emerge_opts[flag] = emerge.opts[flag] |
- |
deps_info = {} |
for pkg in depgraph.altlist(): |
if isinstance(pkg, Package): |
@@ -636,12 +689,6 @@ class DepGraphGenerator(object): |
deps_info[str(pkg.cpv)] = {"idx": len(deps_info), |
"optional": optional} |
- # Delete the --tree option, because we don't really want to display a |
- # tree. We just wanted to get emerge to leave uninstall instructions on |
- # the graph. Later, when we display the graph, we'll want standard-looking |
- # output, so removing the --tree option is important. |
- frozen_config.myopts.pop("--tree", None) |
- |
seconds = time.time() - start |
if "--quiet" not in emerge.opts: |
print "Deps calculated in %dm%.1fs" % (seconds / 60, seconds % 60) |