| 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 |