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 [emerge args] package" | 10 [emerge args] package" |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 adjust_configs(opts, trees) | 399 adjust_configs(opts, trees) |
400 | 400 |
401 # Save our configuration so far in the emerge object | 401 # Save our configuration so far in the emerge object |
402 emerge = self.emerge | 402 emerge = self.emerge |
403 emerge.action, emerge.opts = action, opts | 403 emerge.action, emerge.opts = action, opts |
404 emerge.settings, emerge.trees, emerge.mtimedb = settings, trees, mtimedb | 404 emerge.settings, emerge.trees, emerge.mtimedb = settings, trees, mtimedb |
405 emerge.cmdline_packages = cmdline_packages | 405 emerge.cmdline_packages = cmdline_packages |
406 root = settings["ROOT"] | 406 root = settings["ROOT"] |
407 emerge.root_config = trees[root]["root_config"] | 407 emerge.root_config = trees[root]["root_config"] |
408 | 408 |
| 409 def CheckUseFlags(self, pkgsettings, cur_pkg, new_pkg): |
| 410 """Are the use flags in cur_pkg up to date? |
| 411 |
| 412 Return True if use flags are up to date; return false otherwise.""" |
| 413 |
| 414 # cur_use: The set of flags that were enabled when the package was |
| 415 # first installed. |
| 416 # cur_iuse: The set of flags that affected the specified package |
| 417 # when it was first installed. |
| 418 # |
| 419 # The intersection of cur_use and cur_iuse provides the set of |
| 420 # flags that were enabled and affected the specified package. |
| 421 cur_use = cur_pkg.use.enabled |
| 422 cur_iuse = cur_pkg.iuse.all |
| 423 |
| 424 # Check whether this package is already installed with the right use |
| 425 # flags. |
| 426 # |
| 427 # now_use: The set of flags (special and non-special) that are now |
| 428 # enabled for the specified package. |
| 429 # now_iuse: The set of non-special flags that affect the specified |
| 430 # package. |
| 431 now_use = new_pkg.use.enabled |
| 432 now_iuse = new_pkg.iuse.all |
| 433 |
| 434 # Tell portage we want to lookup the flags for the specified package |
| 435 # in package.use.{mask,force} |
| 436 pkgsettings.setcpv(new_pkg.cpv) |
| 437 |
| 438 # Grab the set of flags that are requested for the given package. |
| 439 # This includes flags that don't affect the package, and includes |
| 440 # all sources of flags (e.g. USE environment variable, make.conf, |
| 441 # make.defaults, package.use.{mask,force}, etc.). |
| 442 # |
| 443 # This is used by portage in the _reinstall_for_flags function below. |
| 444 forced_flags = set(pkgsettings.useforce).union(pkgsettings.usemask) |
| 445 |
| 446 depgraph = self.emerge.depgraph |
| 447 |
| 448 flags = depgraph._reinstall_for_flags(forced_flags, cur_use, |
| 449 cur_iuse, now_use, now_iuse) |
| 450 return not flags |
| 451 |
409 def GenDependencyTree(self): | 452 def GenDependencyTree(self): |
410 """Get dependency tree info from emerge. | 453 """Get dependency tree info from emerge. |
411 | 454 |
412 TODO(): Update cros_extract_deps to also use this code. | 455 TODO(): Update cros_extract_deps to also use this code. |
413 Returns: | 456 Returns: |
414 Dependency tree | 457 Dependency tree |
415 """ | 458 """ |
416 start = time.time() | 459 start = time.time() |
417 | 460 |
418 # Setup emerge options. | 461 # Setup emerge options. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 deps_tree[str(node.cpv)] = dict(action=str(node.operation), | 545 deps_tree[str(node.cpv)] = dict(action=str(node.operation), |
503 deps=deps) | 546 deps=deps) |
504 | 547 |
505 emptytree = "--emptytree" in emerge.opts | 548 emptytree = "--emptytree" in emerge.opts |
506 | 549 |
507 # Ask portage for its install plan, so that we can only throw out | 550 # Ask portage for its install plan, so that we can only throw out |
508 # dependencies that portage throws out. Also, keep track of the old | 551 # dependencies that portage throws out. Also, keep track of the old |
509 # versions of packages that we're either upgrading or replacing. | 552 # versions of packages that we're either upgrading or replacing. |
510 # | 553 # |
511 # The "vardb" is the database of installed packages. | 554 # The "vardb" is the database of installed packages. |
512 vardb = emerge.trees[emerge.settings["ROOT"]]["vartree"].dbapi | 555 root = emerge.settings["ROOT"] |
| 556 frozen_config = depgraph._frozen_config |
| 557 vardb = frozen_config.trees[root]["vartree"].dbapi |
| 558 pkgsettings = frozen_config.pkgsettings[root] |
513 deps_info = {} | 559 deps_info = {} |
514 for pkg in depgraph.altlist(): | 560 for pkg in depgraph.altlist(): |
515 if isinstance(pkg, Package): | 561 if isinstance(pkg, Package): |
516 # If we're not in emptytree mode, and we're going to replace a package | 562 # If we're not in emptytree mode, and we're going to replace a package |
517 # that is already installed, then this operation is possibly optional. | 563 # that is already installed, then this operation is possibly optional. |
518 # ("--selective" mode is handled later, in RemoveInstalledPackages()) | 564 # ("--selective" mode is handled later, in RemoveInstalledPackages()) |
519 optional = False | 565 optional = False |
520 if not emptytree and vardb.cpv_exists(pkg.cpv): | 566 if not emptytree: |
521 optional = True | 567 for vardb_pkg in vardb.match_pkgs(pkg.cpv): |
| 568 if self.CheckUseFlags(pkgsettings, vardb_pkg, pkg): |
| 569 optional = True |
| 570 break |
522 | 571 |
523 # Add the package to our database. | 572 # Add the package to our database. |
524 self.package_db[str(pkg.cpv)] = pkg | 573 self.package_db[str(pkg.cpv)] = pkg |
525 | 574 |
526 # Save off info about the package | 575 # Save off info about the package |
527 deps_info[str(pkg.cpv)] = {"idx": len(deps_info), | 576 deps_info[str(pkg.cpv)] = {"idx": len(deps_info), |
528 "optional": optional} | 577 "optional": optional} |
529 | 578 |
530 # Delete the --tree option, because we don't really want to display a | 579 # Delete the --tree option, because we don't really want to display a |
531 # tree. We just wanted to get emerge to leave uninstall instructions on | 580 # tree. We just wanted to get emerge to leave uninstall instructions on |
532 # the graph. Later, when we display the graph, we'll want standard-looking | 581 # the graph. Later, when we display the graph, we'll want standard-looking |
533 # output, so removing the --tree option is important. | 582 # output, so removing the --tree option is important. |
534 depgraph._frozen_config.myopts.pop("--tree", None) | 583 frozen_config.myopts.pop("--tree", None) |
535 | 584 |
536 seconds = time.time() - start | 585 seconds = time.time() - start |
537 if "--quiet" not in emerge.opts: | 586 if "--quiet" not in emerge.opts: |
538 print "Deps calculated in %dm%.1fs" % (seconds / 60, seconds % 60) | 587 print "Deps calculated in %dm%.1fs" % (seconds / 60, seconds % 60) |
539 | 588 |
540 return deps_tree, deps_info | 589 return deps_tree, deps_info |
541 | 590 |
542 def PrintTree(self, deps, depth=""): | 591 def PrintTree(self, deps, depth=""): |
543 """Print the deps we have seen in the emerge output. | 592 """Print the deps we have seen in the emerge output. |
544 | 593 |
(...skipping 23 matching lines...) Expand all Loading... |
568 # system at some point. Packages in final_db are either already | 617 # system at some point. Packages in final_db are either already |
569 # installed, or will be installed by the time we're done. | 618 # installed, or will be installed by the time we're done. |
570 final_db = emerge.depgraph._dynamic_config.mydbapi[root] | 619 final_db = emerge.depgraph._dynamic_config.mydbapi[root] |
571 | 620 |
572 # final_pkgs is a set of the packages we found in the final_db. These | 621 # final_pkgs is a set of the packages we found in the final_db. These |
573 # packages are either already installed, or will be installed by the time | 622 # packages are either already installed, or will be installed by the time |
574 # we're done. It's populated in BuildFinalPackageSet() | 623 # we're done. It's populated in BuildFinalPackageSet() |
575 final_pkgs = set() | 624 final_pkgs = set() |
576 | 625 |
577 # These packages take a really long time to build, so, for expediency, we | 626 # These packages take a really long time to build, so, for expediency, we |
578 # are blacklisting them from automatic rebuilds. Instead, these packages | 627 # are blacklisting them from automatic rebuilds because one of their |
579 # will only be rebuilt when they are explicitly rev'd. | 628 # dependencies needs to be recompiled. |
580 rebuild_blacklist = set() | 629 rebuild_blacklist = set() |
581 for pkg in ("media-plugins/o3d", "dev-java/icedtea"): | 630 for pkg in ("media-plugins/o3d", "dev-java/icedtea"): |
582 for match in final_db.match_pkgs(pkg): | 631 for match in final_db.match_pkgs(pkg): |
583 rebuild_blacklist.add(str(match.cpv)) | 632 rebuild_blacklist.add(str(match.cpv)) |
584 | 633 |
585 # deps_map is the actual dependency graph. | 634 # deps_map is the actual dependency graph. |
586 # | 635 # |
587 # Each package specifies a "needs" list and a "provides" list. The "needs" | 636 # Each package specifies a "needs" list and a "provides" list. The "needs" |
588 # list indicates which packages we depend on. The "provides" list | 637 # list indicates which packages we depend on. The "provides" list |
589 # indicates the reverse dependencies -- what packages need us. | 638 # indicates the reverse dependencies -- what packages need us. |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 # line are generally mandatory. | 738 # line are generally mandatory. |
690 # | 739 # |
691 # There are a few exceptions to this rule: | 740 # There are a few exceptions to this rule: |
692 # 1. If the package isn't getting installed because it's in | 741 # 1. If the package isn't getting installed because it's in |
693 # package.provided, it's not mandatory. | 742 # package.provided, it's not mandatory. |
694 # 2. If the package isn't getting installed because we're in --onlydeps | 743 # 2. If the package isn't getting installed because we're in --onlydeps |
695 # mode, it's not mandatory either. | 744 # mode, it's not mandatory either. |
696 if "--selective" in emerge.opts: | 745 if "--selective" in emerge.opts: |
697 selective = emerge.opts["--selective"] != "n" | 746 selective = emerge.opts["--selective"] != "n" |
698 else: | 747 else: |
699 selective = "--noreplace" in emerge.opts or "--update" in emerge.opts | 748 selective = ("--noreplace" in emerge.opts or |
| 749 "--update" in emerge.opts or |
| 750 "--newuse" in emerge.opts or |
| 751 "--reinstall" in emerge.opts) |
700 onlydeps = "--onlydeps" in emerge.opts | 752 onlydeps = "--onlydeps" in emerge.opts |
701 if not selective: | 753 if not selective: |
702 for pkg in emerge.cmdline_packages: | 754 for pkg in emerge.cmdline_packages: |
703 # If the package specified on the command-line is in our install | 755 # If the package specified on the command-line is in our install |
704 # list, mark it as non-optional. | 756 # list, mark it as non-optional. |
705 found = False | 757 found = False |
706 for db_pkg in final_db.match_pkgs(pkg): | 758 for db_pkg in final_db.match_pkgs(pkg): |
707 this_pkg = deps_info.get(db_pkg.cpv) | 759 this_pkg = deps_info.get(db_pkg.cpv) |
708 if this_pkg: | 760 if this_pkg: |
709 found = True | 761 found = True |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
804 if dep.find(needed) != -1: | 856 if dep.find(needed) != -1: |
805 needed_pkg = dep | 857 needed_pkg = dep |
806 if bad_pkg and needed_pkg: | 858 if bad_pkg and needed_pkg: |
807 deps_map[needed_pkg]["provides"].add(bad_pkg) | 859 deps_map[needed_pkg]["provides"].add(bad_pkg) |
808 deps_map[bad_pkg]["needs"][needed_pkg] = "secret" | 860 deps_map[bad_pkg]["needs"][needed_pkg] = "secret" |
809 | 861 |
810 def MergeChildren(pkg, merge_type): | 862 def MergeChildren(pkg, merge_type): |
811 """Merge this package and all packages it provides.""" | 863 """Merge this package and all packages it provides.""" |
812 | 864 |
813 this_pkg = deps_map[pkg] | 865 this_pkg = deps_map[pkg] |
814 if (this_pkg[merge_type] or pkg not in final_pkgs or | 866 if (this_pkg[merge_type] or pkg not in final_pkgs): |
815 pkg in rebuild_blacklist): | |
816 return | 867 return |
817 | 868 |
818 # Mark this package as non-optional | 869 # Mark this package as non-optional |
819 deps_info[pkg]["optional"] = False | 870 deps_info[pkg]["optional"] = False |
820 this_pkg[merge_type] = True | 871 this_pkg[merge_type] = True |
821 for w in this_pkg["provides"]: | 872 for w in this_pkg["provides"].difference(rebuild_blacklist): |
822 MergeChildren(w, merge_type) | 873 MergeChildren(w, merge_type) |
823 | 874 |
824 if this_pkg["action"] == "nomerge": | 875 if this_pkg["action"] == "nomerge": |
825 this_pkg["action"] = "merge" | 876 this_pkg["action"] = "merge" |
826 | 877 |
827 def RemotePackageDatabase(binhost_url): | 878 def RemotePackageDatabase(binhost_url): |
828 """Grab the latest binary package database from the prebuilt server. | 879 """Grab the latest binary package database from the prebuilt server. |
829 | 880 |
830 We need to know the modification times of the prebuilt packages so that we | 881 We need to know the modification times of the prebuilt packages so that we |
831 know when it is OK to use these packages and when we should rebuild them | 882 know when it is OK to use these packages and when we should rebuild them |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
951 # or source), make sure we also update the children. If a package is | 1002 # or source), make sure we also update the children. If a package is |
952 # built from source, all children must also be built from source. | 1003 # built from source, all children must also be built from source. |
953 local_ready_cache, remote_ready_cache = {}, {} | 1004 local_ready_cache, remote_ready_cache = {}, {} |
954 local_mtime_cache, remote_mtime_cache = {}, {} | 1005 local_mtime_cache, remote_mtime_cache = {}, {} |
955 for pkg in final_pkgs: | 1006 for pkg in final_pkgs: |
956 # If all the necessary local packages are ready, and their | 1007 # If all the necessary local packages are ready, and their |
957 # modification times are in sync, we don't need to do anything here. | 1008 # modification times are in sync, we don't need to do anything here. |
958 local_mtime = LastModifiedWithDeps(pkg, local_pkgs, local_mtime_cache) | 1009 local_mtime = LastModifiedWithDeps(pkg, local_pkgs, local_mtime_cache) |
959 local_ready = PrebuiltsReady(pkg, local_pkgs, local_ready_cache) | 1010 local_ready = PrebuiltsReady(pkg, local_pkgs, local_ready_cache) |
960 if (not local_ready or local_pkgs.get(pkg, 0) < local_mtime and | 1011 if (not local_ready or local_pkgs.get(pkg, 0) < local_mtime and |
961 pkg not in cycles): | 1012 pkg not in cycles and pkg not in rebuild_blacklist): |
962 # OK, at least one package is missing from the local cache or is | 1013 # OK, at least one package is missing from the local cache or is |
963 # outdated. This means we're going to have to install the package | 1014 # outdated. This means we're going to have to install the package |
964 # and all dependencies. | 1015 # and all dependencies. |
965 # | 1016 # |
966 # If all the necessary remote packages are ready, and they're at | 1017 # If all the necessary remote packages are ready, and they're at |
967 # least as new as our local packages, we can install them. | 1018 # least as new as our local packages, we can install them. |
968 # Otherwise, we need to build from source. | 1019 # Otherwise, we need to build from source. |
969 remote_mtime = LastModifiedWithDeps(pkg, remote_pkgs, | 1020 remote_mtime = LastModifiedWithDeps(pkg, remote_pkgs, |
970 remote_mtime_cache) | 1021 remote_mtime_cache) |
971 remote_ready = PrebuiltsReady(pkg, remote_pkgs, remote_ready_cache) | 1022 remote_ready = PrebuiltsReady(pkg, remote_pkgs, remote_ready_cache) |
972 if remote_ready and (local_mtime <= remote_mtime or pkg in cycles): | 1023 if remote_ready and (local_mtime <= remote_mtime or pkg in cycles): |
973 MergeChildren(pkg, "mandatory") | 1024 MergeChildren(pkg, "mandatory") |
974 else: | 1025 else: |
975 MergeChildren(pkg, "mandatory_source") | 1026 MergeChildren(pkg, "mandatory_source") |
976 | 1027 |
977 def UsePrebuiltPackages(): | 1028 def UsePrebuiltPackages(): |
978 """Update packages that can use prebuilts to do so.""" | 1029 """Update packages that can use prebuilts to do so.""" |
979 start = time.time() | 1030 start = time.time() |
980 | 1031 |
981 # The bintree is the database of binary packages. By default, it's | 1032 # The bintree is the database of binary packages. By default, it's |
982 # empty. | 1033 # empty. |
983 bintree = emerge.trees[root]["bintree"] | 1034 bintree = emerge.trees[root]["bintree"] |
984 bindb = bintree.dbapi | 1035 bindb = bintree.dbapi |
985 root_config = emerge.root_config | 1036 root_config = emerge.root_config |
| 1037 pkgsettings = emerge.depgraph._frozen_config.pkgsettings[root] |
986 prebuilt_pkgs = {} | 1038 prebuilt_pkgs = {} |
987 | 1039 |
988 # Populate the DB with packages | 1040 # Populate the DB with packages |
989 bintree.populate("--getbinpkg" in emerge.opts, | 1041 bintree.populate("--getbinpkg" in emerge.opts, |
990 "--getbinpkgonly" in emerge.opts) | 1042 "--getbinpkgonly" in emerge.opts) |
991 | 1043 |
992 # Update packages that can use prebuilts to do so. | 1044 # Build list of prebuilt packages |
993 for pkg, info in deps_map.iteritems(): | 1045 for pkg, info in deps_map.iteritems(): |
994 if info and not info["mandatory_source"] and info["action"] == "merge": | 1046 if info and not info["mandatory_source"] and info["action"] == "merge": |
995 db_keys = list(bindb._aux_cache_keys) | 1047 db_keys = list(bindb._aux_cache_keys) |
996 try: | 1048 try: |
997 db_vals = bindb.aux_get(pkg, db_keys + ["MTIME"]) | 1049 db_vals = bindb.aux_get(pkg, db_keys + ["MTIME"]) |
998 except KeyError: | 1050 except KeyError: |
999 # No binary package | 1051 # No binary package |
1000 continue | 1052 continue |
1001 mtime = int(db_vals.pop() or 0) | 1053 mtime = int(db_vals.pop() or 0) |
1002 metadata = zip(db_keys, db_vals) | 1054 metadata = zip(db_keys, db_vals) |
1003 db_pkg = Package(built=True, cpv=pkg, installed=False, | 1055 db_pkg = Package(built=True, cpv=pkg, installed=False, |
1004 metadata=metadata, onlydeps=False, mtime=mtime, | 1056 metadata=metadata, onlydeps=False, mtime=mtime, |
1005 operation="merge", root_config=root_config, | 1057 operation="merge", root_config=root_config, |
1006 type_name="binary") | 1058 type_name="binary") |
1007 self.package_db[pkg] = db_pkg | 1059 prebuilt_pkgs[pkg] = db_pkg |
| 1060 |
| 1061 # Calculate what packages need to be rebuilt due to changes in use flags. |
| 1062 for pkg, db_pkg in prebuilt_pkgs.iteritems(): |
| 1063 db_pkg_src = self.package_db[pkg] |
| 1064 if not self.CheckUseFlags(pkgsettings, db_pkg, db_pkg_src): |
| 1065 MergeChildren(pkg, "mandatory_source") |
| 1066 |
| 1067 # Convert eligible packages to binaries. |
| 1068 for pkg, info in deps_map.iteritems(): |
| 1069 if (info and not info["mandatory_source"] and |
| 1070 info["action"] == "merge" and pkg in prebuilt_pkgs): |
| 1071 self.package_db[pkg] = prebuilt_pkgs[pkg] |
1008 | 1072 |
1009 seconds = time.time() - start | 1073 seconds = time.time() - start |
1010 if "--quiet" not in emerge.opts: | 1074 if "--quiet" not in emerge.opts: |
1011 print "Prebuilt DB populated in %dm%.1fs" % (seconds / 60, seconds % 60) | 1075 print "Prebuilt DB populated in %dm%.1fs" % (seconds / 60, seconds % 60) |
1012 | 1076 |
1013 return prebuilt_pkgs | 1077 return prebuilt_pkgs |
1014 | 1078 |
1015 def AddRemainingPackages(): | 1079 def AddRemainingPackages(): |
1016 """Fill in packages that don't have entries in the package db. | 1080 """Fill in packages that don't have entries in the package db. |
1017 | 1081 |
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1583 world_set.update(new_world_pkgs) | 1647 world_set.update(new_world_pkgs) |
1584 | 1648 |
1585 # Update environment (library cache, symlinks, etc.) | 1649 # Update environment (library cache, symlinks, etc.) |
1586 if deps.board and "--pretend" not in emerge.opts: | 1650 if deps.board and "--pretend" not in emerge.opts: |
1587 portage.env_update() | 1651 portage.env_update() |
1588 | 1652 |
1589 print "Done" | 1653 print "Done" |
1590 | 1654 |
1591 if __name__ == "__main__": | 1655 if __name__ == "__main__": |
1592 main() | 1656 main() |
OLD | NEW |