OLD | NEW |
1 #!/usr/bin/python2.6 | 1 #!/usr/bin/python2.6 |
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Program to run emerge in parallel, for significant speedup. | 6 """Program to run emerge in parallel, for significant speedup. |
7 | 7 |
8 Usage: | 8 Usage: |
9 ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps] | 9 ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps] |
10 [--force-remote-binary=PKGS] [emerge args] package | 10 [--force-remote-binary=PKGS] [emerge args] package |
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 | 457 |
458 # Grab the set of flags that are requested for the given package. | 458 # Grab the set of flags that are requested for the given package. |
459 # This includes flags that don't affect the package, and includes | 459 # This includes flags that don't affect the package, and includes |
460 # all sources of flags (e.g. USE environment variable, make.conf, | 460 # all sources of flags (e.g. USE environment variable, make.conf, |
461 # make.defaults, package.use.{mask,force}, etc.). | 461 # make.defaults, package.use.{mask,force}, etc.). |
462 # | 462 # |
463 # This is used by portage in the _reinstall_for_flags function below. | 463 # This is used by portage in the _reinstall_for_flags function below. |
464 forced_flags = set(pkgsettings.useforce).union(pkgsettings.usemask) | 464 forced_flags = set(pkgsettings.useforce).union(pkgsettings.usemask) |
465 | 465 |
466 depgraph = self.emerge.depgraph | 466 depgraph = self.emerge.depgraph |
467 | |
468 flags = depgraph._reinstall_for_flags(forced_flags, cur_use, | 467 flags = depgraph._reinstall_for_flags(forced_flags, cur_use, |
469 cur_iuse, now_use, now_iuse) | 468 cur_iuse, now_use, now_iuse) |
470 return not flags | 469 return not flags |
471 | 470 |
472 def GenDependencyTree(self, remote_pkgs): | 471 def GenDependencyTree(self, remote_pkgs): |
473 """Get dependency tree info from emerge. | 472 """Get dependency tree info from emerge. |
474 | 473 |
475 TODO(): Update cros_extract_deps to also use this code. | 474 TODO(): Update cros_extract_deps to also use this code. |
476 Returns: | 475 Returns: |
477 Dependency tree | 476 Dependency tree |
478 """ | 477 """ |
479 start = time.time() | 478 start = time.time() |
480 | 479 |
481 # Setup emerge options. | 480 # Setup emerge options. |
482 # | 481 # |
483 # We treat dependency info a bit differently than emerge itself. Unless | 482 # We treat dependency info a bit differently than emerge itself. Unless |
484 # you're using --usepkgonly, we disable --getbinpkg and --usepkg here so | 483 # you're using --usepkgonly, we disable --getbinpkg and --usepkg here so |
485 # that emerge will look at the dependencies of the source ebuilds rather | 484 # that emerge will look at the dependencies of the source ebuilds rather |
486 # than the binary dependencies. This helps ensure that we have the option | 485 # than the binary dependencies. This helps ensure that we have the option |
487 # of merging a package from source, if we want to switch to it with | 486 # of merging a package from source, if we want to switch to it with |
488 # --workon and the dependencies have changed. | 487 # --workon and the dependencies have changed. |
489 emerge = self.emerge | 488 emerge = self.emerge |
490 emerge_opts = emerge.opts.copy() | 489 emerge_opts = emerge.opts.copy() |
491 if self.mandatory_source or self.rebuild or self.force_remote_binary: | |
492 # Enable --emptytree so that we get the full tree, which we need for | |
493 # dependency analysis. By default, with this option, emerge optimizes | |
494 # the graph by removing uninstall instructions from the graph. By | |
495 # specifying --tree as well, we tell emerge that it's not safe to remove | |
496 # uninstall instructions because we're planning on analyzing the output. | |
497 emerge_opts["--tree"] = True | |
498 emerge_opts["--emptytree"] = True | |
499 | 490 |
500 # Tell emerge not to worry about use flags yet. We handle those inside | 491 # Enable --emptytree so that we get the full tree, which we need for |
501 # parallel_emerge itself. Further, when we use the --force-remote-binary | 492 # dependency analysis. By default, with this option, emerge optimizes |
502 # flag, we don't emerge to reject a package just because it has different | 493 # the graph by removing uninstall instructions from the graph. By |
503 # use flags. | 494 # specifying --tree as well, we tell emerge that it's not safe to remove |
504 emerge_opts.pop("--newuse", None) | 495 # uninstall instructions because we're planning on analyzing the output. |
505 emerge_opts.pop("--reinstall", None) | 496 emerge_opts["--tree"] = True |
| 497 emerge_opts["--emptytree"] = True |
| 498 |
| 499 # Tell emerge not to worry about use flags yet. We handle those inside |
| 500 # parallel_emerge itself. Further, when we use the --force-remote-binary |
| 501 # flag, we don't emerge to reject a package just because it has different |
| 502 # use flags. |
| 503 emerge_opts.pop("--newuse", None) |
| 504 emerge_opts.pop("--reinstall", None) |
506 | 505 |
507 # Create a list of packages to merge | 506 # Create a list of packages to merge |
508 packages = set(emerge.cmdline_packages[:]) | 507 packages = set(emerge.cmdline_packages[:]) |
509 if self.mandatory_source: | 508 if self.mandatory_source: |
510 packages.update(self.mandatory_source) | 509 packages.update(self.mandatory_source) |
511 if self.force_remote_binary: | 510 if self.force_remote_binary: |
512 forced_pkgs = {} | 511 forced_pkgs = {} |
513 for pkg in remote_pkgs: | 512 for pkg in remote_pkgs: |
514 category, pkgname, _, _ = portage.catpkgsplit(pkg) | 513 category, pkgname, _, _ = portage.catpkgsplit(pkg) |
515 full_pkgname = "%s/%s" % (category, pkgname) | 514 full_pkgname = "%s/%s" % (category, pkgname) |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 | 585 |
587 # Ask portage for its install plan, so that we can only throw out | 586 # Ask portage for its install plan, so that we can only throw out |
588 # dependencies that portage throws out. Also, keep track of the old | 587 # dependencies that portage throws out. Also, keep track of the old |
589 # versions of packages that we're either upgrading or replacing. | 588 # versions of packages that we're either upgrading or replacing. |
590 # | 589 # |
591 # The "vardb" is the database of installed packages. | 590 # The "vardb" is the database of installed packages. |
592 root = emerge.settings["ROOT"] | 591 root = emerge.settings["ROOT"] |
593 frozen_config = depgraph._frozen_config | 592 frozen_config = depgraph._frozen_config |
594 vardb = frozen_config.trees[root]["vartree"].dbapi | 593 vardb = frozen_config.trees[root]["vartree"].dbapi |
595 pkgsettings = frozen_config.pkgsettings[root] | 594 pkgsettings = frozen_config.pkgsettings[root] |
| 595 |
| 596 # It's time to start worrying about use flags, if necessary. |
| 597 for flag in ("--newuse", "--reinstall"): |
| 598 if flag in emerge.opts: |
| 599 emerge_opts[flag] = emerge.opts[flag] |
| 600 |
596 deps_info = {} | 601 deps_info = {} |
597 for pkg in depgraph.altlist(): | 602 for pkg in depgraph.altlist(): |
598 if isinstance(pkg, Package): | 603 if isinstance(pkg, Package): |
| 604 # If we're not using --force-remote-binary, check what flags are being |
| 605 # used by the real package. |
| 606 if "--usepkgonly" not in emerge.opts: |
| 607 try: |
| 608 pkg = emerge.depgraph._pkg(pkg.cpv, "ebuild", emerge.root_config) |
| 609 except portage.exception.PackageNotFound: |
| 610 # This is a --force-remote-binary package. |
| 611 pass |
| 612 self.package_db[pkg.cpv] = pkg |
| 613 |
599 # If we're not in emptytree mode, and we're going to replace a package | 614 # If we're not in emptytree mode, and we're going to replace a package |
600 # that is already installed, then this operation is possibly optional. | 615 # that is already installed, then this operation is possibly optional. |
601 # ("--selective" mode is handled later, in RemoveInstalledPackages()) | 616 # ("--selective" mode is handled later, in RemoveInstalledPackages()) |
602 optional = False | 617 optional = False |
603 if not emptytree: | 618 if not emptytree: |
604 for vardb_pkg in vardb.match_pkgs(pkg.cpv): | 619 for vardb_pkg in vardb.match_pkgs(pkg.cpv): |
605 if self.CheckUseFlags(pkgsettings, vardb_pkg, pkg): | 620 if self.CheckUseFlags(pkgsettings, vardb_pkg, pkg): |
606 optional = True | 621 optional = True |
607 break | 622 break |
608 | 623 |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1142 mtime = int(db_vals.pop() or 0) | 1157 mtime = int(db_vals.pop() or 0) |
1143 metadata = zip(db_keys, db_vals) | 1158 metadata = zip(db_keys, db_vals) |
1144 db_pkg = Package(built=True, cpv=pkg, installed=False, | 1159 db_pkg = Package(built=True, cpv=pkg, installed=False, |
1145 metadata=metadata, onlydeps=False, mtime=mtime, | 1160 metadata=metadata, onlydeps=False, mtime=mtime, |
1146 operation="merge", root_config=root_config, | 1161 operation="merge", root_config=root_config, |
1147 type_name="binary") | 1162 type_name="binary") |
1148 prebuilt_pkgs[pkg] = db_pkg | 1163 prebuilt_pkgs[pkg] = db_pkg |
1149 | 1164 |
1150 # Calculate what packages need to be rebuilt due to changes in use flags. | 1165 # Calculate what packages need to be rebuilt due to changes in use flags. |
1151 for pkg, db_pkg in prebuilt_pkgs.iteritems(): | 1166 for pkg, db_pkg in prebuilt_pkgs.iteritems(): |
1152 db_pkg_src = self.package_db.get(pkg) | 1167 if not self.CheckUseFlags(pkgsettings, db_pkg, self.package_db[pkg]): |
1153 if db_pkg_src and not self.CheckUseFlags(pkgsettings, db_pkg, | |
1154 db_pkg_src): | |
1155 MergeChildren(pkg, "mandatory_source") | 1168 MergeChildren(pkg, "mandatory_source") |
1156 | 1169 |
1157 # Convert eligible packages to binaries. | 1170 # Convert eligible packages to binaries. |
1158 for pkg, info in deps_map.iteritems(): | 1171 for pkg, info in deps_map.iteritems(): |
1159 if info and info["action"] == "merge" and pkg in prebuilt_pkgs: | 1172 if info and info["action"] == "merge" and pkg in prebuilt_pkgs: |
1160 if not info["mandatory_source"] or info["force_remote_binary"]: | 1173 if not info["mandatory_source"] or info["force_remote_binary"]: |
1161 self.package_db[pkg] = prebuilt_pkgs[pkg] | 1174 self.package_db[pkg] = prebuilt_pkgs[pkg] |
1162 | 1175 |
1163 seconds = time.time() - start | 1176 seconds = time.time() - start |
1164 if "--quiet" not in emerge.opts: | 1177 if "--quiet" not in emerge.opts: |
1165 print "Prebuilt DB populated in %dm%.1fs" % (seconds / 60, seconds % 60) | 1178 print "Prebuilt DB populated in %dm%.1fs" % (seconds / 60, seconds % 60) |
1166 | 1179 |
1167 return prebuilt_pkgs | 1180 return prebuilt_pkgs |
1168 | 1181 |
1169 def AddRemainingPackages(): | |
1170 """Fill in packages that don't have entries in the package db. | |
1171 | |
1172 Every package we are installing needs an entry in the package db. | |
1173 This function should only be called after we have removed the | |
1174 packages that are not being merged from our deps_map. | |
1175 """ | |
1176 for pkg in deps_map: | |
1177 if pkg not in self.package_db: | |
1178 if deps_map[pkg]["action"] != "merge": | |
1179 # We should only fill in packages that are being merged. If | |
1180 # there's any other packages here, something funny is going on. | |
1181 print "Missing entry for %s in package db" % pkg | |
1182 sys.exit(1) | |
1183 | |
1184 db_pkg = emerge.depgraph._pkg(pkg, "ebuild", emerge.root_config) | |
1185 self.package_db[pkg] = db_pkg | |
1186 | |
1187 ReverseTree(deps_tree) | 1182 ReverseTree(deps_tree) |
1188 BuildFinalPackageSet() | 1183 BuildFinalPackageSet() |
1189 AddSecretDeps() | 1184 AddSecretDeps() |
1190 | 1185 |
1191 # Mark that we want to use remote binaries only for a particular package. | 1186 # Mark that we want to use remote binaries only for a particular package. |
1192 vardb = emerge.depgraph._frozen_config.trees[root]["vartree"].dbapi | 1187 vardb = emerge.depgraph._frozen_config.trees[root]["vartree"].dbapi |
1193 for pkg in self.force_remote_binary: | 1188 for pkg in self.force_remote_binary: |
1194 for db_pkg in final_db.match_pkgs(pkg): | 1189 for db_pkg in final_db.match_pkgs(pkg): |
1195 match = deps_map.get(str(db_pkg.cpv)) | 1190 match = deps_map.get(str(db_pkg.cpv)) |
1196 if match: | 1191 if match: |
(...skipping 19 matching lines...) Expand all Loading... |
1216 | 1211 |
1217 # We need to remove installed packages so that we can use the dependency | 1212 # We need to remove installed packages so that we can use the dependency |
1218 # ordering of the install process to show us what cycles to crack. Once | 1213 # ordering of the install process to show us what cycles to crack. Once |
1219 # we've done that, we also need to recalculate our list of cycles so that | 1214 # we've done that, we also need to recalculate our list of cycles so that |
1220 # we don't include the installed packages in our cycles. | 1215 # we don't include the installed packages in our cycles. |
1221 RemoveInstalledPackages() | 1216 RemoveInstalledPackages() |
1222 SanitizeTree() | 1217 SanitizeTree() |
1223 if deps_map: | 1218 if deps_map: |
1224 if "--usepkg" in emerge.opts: | 1219 if "--usepkg" in emerge.opts: |
1225 UsePrebuiltPackages(remote_pkgs) | 1220 UsePrebuiltPackages(remote_pkgs) |
1226 AddRemainingPackages() | |
1227 return deps_map | 1221 return deps_map |
1228 | 1222 |
1229 def PrintInstallPlan(self, deps_map): | 1223 def PrintInstallPlan(self, deps_map): |
1230 """Print an emerge-style install plan. | 1224 """Print an emerge-style install plan. |
1231 | 1225 |
1232 The install plan lists what packages we're installing, in order. | 1226 The install plan lists what packages we're installing, in order. |
1233 It's useful for understanding what parallel_emerge is doing. | 1227 It's useful for understanding what parallel_emerge is doing. |
1234 | 1228 |
1235 Args: | 1229 Args: |
1236 deps_map: The dependency graph. | 1230 deps_map: The dependency graph. |
(...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1836 # need to upgrade the rest of the packages. So we'll go ahead and do that. | 1830 # need to upgrade the rest of the packages. So we'll go ahead and do that. |
1837 if portage_upgrade: | 1831 if portage_upgrade: |
1838 args = sys.argv[1:] + ["--nomerge=sys-apps/portage"] | 1832 args = sys.argv[1:] + ["--nomerge=sys-apps/portage"] |
1839 os.execvp(os.path.realpath(sys.argv[0]), args) | 1833 os.execvp(os.path.realpath(sys.argv[0]), args) |
1840 | 1834 |
1841 print "Done" | 1835 print "Done" |
1842 sys.exit(0) | 1836 sys.exit(0) |
1843 | 1837 |
1844 if __name__ == "__main__": | 1838 if __name__ == "__main__": |
1845 main() | 1839 main() |
OLD | NEW |