Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(575)

Side by Side Diff: parallel_emerge

Issue 3361002: Update parallel_emerge to rebuild packages when use flags change. (Closed) Base URL: http://git.chromium.org/git/crosutils.git
Patch Set: Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698