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

Side by Side Diff: parallel_emerge

Issue 4555002: Update parallel_emerge to support --force-remote-binary. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crosutils.git
Patch Set: Fix path joining Created 10 years, 1 month 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 [--force-remote-binary=PKGS] [emerge args] package
11 11
12 Basic operation: 12 Basic operation:
13 Runs 'emerge -p --debug' to display dependencies, and stores a 13 Runs 'emerge -p --debug' to display dependencies, and stores a
14 dependency graph. All non-blocked packages are launched in parallel, 14 dependency graph. All non-blocked packages are launched in parallel,
15 as 'emerge --nodeps package' with any blocked packages being emerged 15 as 'emerge --nodeps package' with any blocked packages being emerged
16 immediately upon deps being met. 16 immediately upon deps being met.
17 17
18 For this to work effectively, /usr/lib/portage/pym/portage/locks.py 18 For this to work effectively, /usr/lib/portage/pym/portage/locks.py
19 must be stubbed out, preventing portage from slowing itself with 19 must be stubbed out, preventing portage from slowing itself with
20 unneccesary locking, as this script ensures that emerge is run in such 20 unneccesary locking, as this script ensures that emerge is run in such
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 from _emerge.actions import load_emerge_config 77 from _emerge.actions import load_emerge_config
78 from _emerge.create_depgraph_params import create_depgraph_params 78 from _emerge.create_depgraph_params import create_depgraph_params
79 from _emerge.depgraph import backtrack_depgraph 79 from _emerge.depgraph import backtrack_depgraph
80 from _emerge.main import emerge_main 80 from _emerge.main import emerge_main
81 from _emerge.main import parse_opts 81 from _emerge.main import parse_opts
82 from _emerge.Package import Package 82 from _emerge.Package import Package
83 from _emerge.Scheduler import Scheduler 83 from _emerge.Scheduler import Scheduler
84 from _emerge.stdout_spinner import stdout_spinner 84 from _emerge.stdout_spinner import stdout_spinner
85 import portage 85 import portage
86 import portage.debug 86 import portage.debug
87 import portage.versions
87 88
88 89
89 def Usage(): 90 def Usage():
90 """Print usage.""" 91 """Print usage."""
91 print "Usage:" 92 print "Usage:"
92 print " ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps]" 93 print " ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps]"
93 print " [--rebuild] [emerge args] package" 94 print " [--rebuild] [emerge args] package"
94 print 95 print
95 print "Packages specified as workon packages are always built from source." 96 print "Packages specified as workon packages are always built from source."
96 print "Unless --no-workon-deps is specified, packages that depend on these" 97 print "Unless --no-workon-deps is specified, packages that depend on these"
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 Typical usage: 212 Typical usage:
212 deps = DepGraphGenerator() 213 deps = DepGraphGenerator()
213 deps.Initialize(sys.argv[1:]) 214 deps.Initialize(sys.argv[1:])
214 deps_tree, deps_info = deps.GenDependencyTree() 215 deps_tree, deps_info = deps.GenDependencyTree()
215 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) 216 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info)
216 deps.PrintTree(deps_tree) 217 deps.PrintTree(deps_tree)
217 PrintDepsMap(deps_graph) 218 PrintDepsMap(deps_graph)
218 """ 219 """
219 220
220 __slots__ = ["board", "emerge", "mandatory_source", "no_workon_deps", 221 __slots__ = ["board", "emerge", "mandatory_source", "no_workon_deps",
221 "nomerge", "package_db", "rebuild", "show_output"] 222 "nomerge", "package_db", "rebuild", "show_output",
223 "force_remote_binary", "forced_remote_binary_packages"]
222 224
223 def __init__(self): 225 def __init__(self):
224 self.board = None 226 self.board = None
225 self.emerge = EmergeData() 227 self.emerge = EmergeData()
226 self.mandatory_source = set() 228 self.mandatory_source = set()
227 self.no_workon_deps = False 229 self.no_workon_deps = False
228 self.nomerge = set() 230 self.nomerge = set()
229 self.package_db = {} 231 self.package_db = {}
230 self.rebuild = False 232 self.rebuild = False
231 self.show_output = False 233 self.show_output = False
234 self.force_remote_binary = set()
235 self.forced_remote_binary_packages = set()
232 236
233 def ParseParallelEmergeArgs(self, argv): 237 def ParseParallelEmergeArgs(self, argv):
234 """Read the parallel emerge arguments from the command-line. 238 """Read the parallel emerge arguments from the command-line.
235 239
236 We need to be compatible with emerge arg format. We scrape arguments that 240 We need to be compatible with emerge arg format. We scrape arguments that
237 are specific to parallel_emerge, and pass through the rest directly to 241 are specific to parallel_emerge, and pass through the rest directly to
238 emerge. 242 emerge.
239 Args: 243 Args:
240 argv: arguments list 244 argv: arguments list
241 Returns: 245 Returns:
242 Arguments that don't belong to parallel_emerge 246 Arguments that don't belong to parallel_emerge
243 """ 247 """
244 emerge_args = [] 248 emerge_args = []
245 for arg in argv: 249 for arg in argv:
246 # Specifically match arguments that are specific to parallel_emerge, and 250 # Specifically match arguments that are specific to parallel_emerge, and
247 # pass through the rest. 251 # pass through the rest.
248 if arg.startswith("--board="): 252 if arg.startswith("--board="):
249 self.board = arg.replace("--board=", "") 253 self.board = arg.replace("--board=", "")
250 elif arg.startswith("--workon="): 254 elif arg.startswith("--workon="):
251 workon_str = arg.replace("--workon=", "") 255 workon_str = arg.replace("--workon=", "")
252 package_list = shlex.split(" ".join(shlex.split(workon_str))) 256 package_list = shlex.split(" ".join(shlex.split(workon_str)))
253 self.mandatory_source.update(package_list) 257 self.mandatory_source.update(package_list)
258 elif arg.startswith("--force-remote-binary="):
259 force_remote_binary = arg.replace("--force-remote-binary=", "")
260 force_remote_binary = \
261 shlex.split(" ".join(shlex.split(force_remote_binary)))
262 self.force_remote_binary.update(force_remote_binary)
254 elif arg.startswith("--nomerge="): 263 elif arg.startswith("--nomerge="):
255 nomerge_str = arg.replace("--nomerge=", "") 264 nomerge_str = arg.replace("--nomerge=", "")
256 package_list = shlex.split(" ".join(shlex.split(nomerge_str))) 265 package_list = shlex.split(" ".join(shlex.split(nomerge_str)))
257 self.nomerge.update(package_list) 266 self.nomerge.update(package_list)
258 elif arg == "--no-workon-deps": 267 elif arg == "--no-workon-deps":
259 self.no_workon_deps = True 268 self.no_workon_deps = True
260 elif arg == "--rebuild": 269 elif arg == "--rebuild":
261 self.rebuild = True 270 self.rebuild = True
262 elif arg == "--show-output": 271 elif arg == "--show-output":
263 self.show_output = True 272 self.show_output = True
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 # 462 #
454 # 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.
455 forced_flags = set(pkgsettings.useforce).union(pkgsettings.usemask) 464 forced_flags = set(pkgsettings.useforce).union(pkgsettings.usemask)
456 465
457 depgraph = self.emerge.depgraph 466 depgraph = self.emerge.depgraph
458 467
459 flags = depgraph._reinstall_for_flags(forced_flags, cur_use, 468 flags = depgraph._reinstall_for_flags(forced_flags, cur_use,
460 cur_iuse, now_use, now_iuse) 469 cur_iuse, now_use, now_iuse)
461 return not flags 470 return not flags
462 471
463 def GenDependencyTree(self): 472 def GenDependencyTree(self, remote_pkgs):
464 """Get dependency tree info from emerge. 473 """Get dependency tree info from emerge.
465 474
466 TODO(): Update cros_extract_deps to also use this code. 475 TODO(): Update cros_extract_deps to also use this code.
467 Returns: 476 Returns:
468 Dependency tree 477 Dependency tree
469 """ 478 """
470 start = time.time() 479 start = time.time()
471 480
472 # Setup emerge options. 481 # Setup emerge options.
473 # 482 #
474 # We treat dependency info a bit differently than emerge itself. Unless 483 # We treat dependency info a bit differently than emerge itself. Unless
475 # you're using --usepkgonly, we disable --getbinpkg and --usepkg here so 484 # you're using --usepkgonly, we disable --getbinpkg and --usepkg here so
476 # that emerge will look at the dependencies of the source ebuilds rather 485 # that emerge will look at the dependencies of the source ebuilds rather
477 # than the binary dependencies. This helps ensure that we have the option 486 # than the binary dependencies. This helps ensure that we have the option
478 # of merging a package from source, if we want to switch to it with 487 # of merging a package from source, if we want to switch to it with
479 # --workon and the dependencies have changed. 488 # --workon and the dependencies have changed.
480 emerge = self.emerge 489 emerge = self.emerge
481 emerge_opts = emerge.opts.copy() 490 emerge_opts = emerge.opts.copy()
482 emerge_opts.pop("--getbinpkg", None) 491 if self.mandatory_source or self.rebuild or self.force_remote_binary:
483 if "--usepkgonly" not in emerge_opts:
484 emerge_opts.pop("--usepkg", None)
485 if self.mandatory_source or self.rebuild:
486 # Enable --emptytree so that we get the full tree, which we need for 492 # Enable --emptytree so that we get the full tree, which we need for
487 # dependency analysis. By default, with this option, emerge optimizes 493 # dependency analysis. By default, with this option, emerge optimizes
488 # the graph by removing uninstall instructions from the graph. By 494 # the graph by removing uninstall instructions from the graph. By
489 # specifying --tree as well, we tell emerge that it's not safe to remove 495 # specifying --tree as well, we tell emerge that it's not safe to remove
490 # uninstall instructions because we're planning on analyzing the output. 496 # uninstall instructions because we're planning on analyzing the output.
491 emerge_opts["--tree"] = True 497 emerge_opts["--tree"] = True
492 emerge_opts["--emptytree"] = True 498 emerge_opts["--emptytree"] = True
493 499
500 # Tell emerge not to worry about use flags yet. We handle those inside
501 # parallel_emerge itself. Further, when we use the --force-remote-binary
502 # flag, we don't emerge to reject a package just because it has different
503 # use flags.
504 emerge_opts.pop("--newuse", None)
505 emerge_opts.pop("--reinstall", None)
506
494 # Create a list of packages to merge 507 # Create a list of packages to merge
495 packages = set(emerge.cmdline_packages[:]) 508 packages = set(emerge.cmdline_packages[:])
496 if self.mandatory_source: 509 if self.mandatory_source:
497 packages.update(self.mandatory_source) 510 packages.update(self.mandatory_source)
511 if self.force_remote_binary:
512 forced_pkgs = {}
513 for pkg in remote_pkgs:
514 category, pkgname, _, _ = portage.catpkgsplit(pkg)
515 full_pkgname = "%s/%s" % (category, pkgname)
516 if (pkgname in self.force_remote_binary or
517 full_pkgname in self.force_remote_binary):
518 forced_pkgs.setdefault(full_pkgname, []).append(pkg)
519
520 for pkgs in forced_pkgs.values():
521 forced_package = portage.versions.best(pkgs)
522 packages.add("=%s" % forced_package)
523 self.forced_remote_binary_packages.add(forced_package)
498 524
499 # Tell emerge to be quiet. We print plenty of info ourselves so we don't 525 # Tell emerge to be quiet. We print plenty of info ourselves so we don't
500 # need any extra output from portage. 526 # need any extra output from portage.
501 portage.util.noiselimit = -1 527 portage.util.noiselimit = -1
502 528
503 # My favorite feature: The silent spinner. It doesn't spin. Ever. 529 # My favorite feature: The silent spinner. It doesn't spin. Ever.
504 # I'd disable the colors by default too, but they look kind of cool. 530 # I'd disable the colors by default too, but they look kind of cool.
505 emerge.spinner = stdout_spinner() 531 emerge.spinner = stdout_spinner()
506 emerge.spinner.update = emerge.spinner.update_quiet 532 emerge.spinner.update = emerge.spinner.update_quiet
507 533
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 # If we're not in emptytree mode, and we're going to replace a package 599 # If we're not in emptytree mode, and we're going to replace a package
574 # that is already installed, then this operation is possibly optional. 600 # that is already installed, then this operation is possibly optional.
575 # ("--selective" mode is handled later, in RemoveInstalledPackages()) 601 # ("--selective" mode is handled later, in RemoveInstalledPackages())
576 optional = False 602 optional = False
577 if not emptytree: 603 if not emptytree:
578 for vardb_pkg in vardb.match_pkgs(pkg.cpv): 604 for vardb_pkg in vardb.match_pkgs(pkg.cpv):
579 if self.CheckUseFlags(pkgsettings, vardb_pkg, pkg): 605 if self.CheckUseFlags(pkgsettings, vardb_pkg, pkg):
580 optional = True 606 optional = True
581 break 607 break
582 608
583 # Add the package to our database.
584 self.package_db[str(pkg.cpv)] = pkg
585
586 # Save off info about the package 609 # Save off info about the package
587 deps_info[str(pkg.cpv)] = {"idx": len(deps_info), 610 deps_info[str(pkg.cpv)] = {"idx": len(deps_info),
588 "optional": optional} 611 "optional": optional}
589 612
590 # Delete the --tree option, because we don't really want to display a 613 # Delete the --tree option, because we don't really want to display a
591 # tree. We just wanted to get emerge to leave uninstall instructions on 614 # tree. We just wanted to get emerge to leave uninstall instructions on
592 # the graph. Later, when we display the graph, we'll want standard-looking 615 # the graph. Later, when we display the graph, we'll want standard-looking
593 # output, so removing the --tree option is important. 616 # output, so removing the --tree option is important.
594 frozen_config.myopts.pop("--tree", None) 617 frozen_config.myopts.pop("--tree", None)
595 618
596 seconds = time.time() - start 619 seconds = time.time() - start
597 if "--quiet" not in emerge.opts: 620 if "--quiet" not in emerge.opts:
598 print "Deps calculated in %dm%.1fs" % (seconds / 60, seconds % 60) 621 print "Deps calculated in %dm%.1fs" % (seconds / 60, seconds % 60)
599 622
600 return deps_tree, deps_info 623 return deps_tree, deps_info
601 624
602 def PrintTree(self, deps, depth=""): 625 def PrintTree(self, deps, depth=""):
603 """Print the deps we have seen in the emerge output. 626 """Print the deps we have seen in the emerge output.
604 627
605 Args: 628 Args:
606 deps: Dependency tree structure. 629 deps: Dependency tree structure.
607 depth: Allows printing the tree recursively, with indentation. 630 depth: Allows printing the tree recursively, with indentation.
608 """ 631 """
609 for entry in sorted(deps): 632 for entry in sorted(deps):
610 action = deps[entry]["action"] 633 action = deps[entry]["action"]
611 print "%s %s (%s)" % (depth, entry, action) 634 print "%s %s (%s)" % (depth, entry, action)
612 self.PrintTree(deps[entry]["deps"], depth=depth + " ") 635 self.PrintTree(deps[entry]["deps"], depth=depth + " ")
613 636
614 def GenDependencyGraph(self, deps_tree, deps_info): 637 def RemotePackageDatabase(self, binhost_url):
638 """Grab the latest binary package database from the prebuilt server.
639
640 We need to know the modification times of the prebuilt packages so that we
641 know when it is OK to use these packages and when we should rebuild them
642 instead.
643
644 Args:
645 binhost_url: Base URL of remote packages (PORTAGE_BINHOST).
646
647 Returns:
648 A dict mapping package identifiers to modification times.
649 """
650
651 if not binhost_url:
652 return {}
653
654 def retry_urlopen(url, tries=3):
655 """Open the specified url, retrying if we run into network errors.
656
657 We do not retry for HTTP errors.
658
659 Args:
660 url: The specified url.
661 tries: The number of times to try.
662
663 Returns:
664 The result of urllib2.urlopen(url).
665 """
666 for i in range(tries):
667 try:
668 return urllib2.urlopen(url)
669 except urllib2.HTTPError as e:
670 raise
671 except urllib2.URLError as e:
672 if i + 1 == tries:
673 raise
674 else:
675 print "Cannot GET %s: %s" % (url, e)
676
677 url = os.path.join(binhost_url, "Packages")
678 try:
679 f = retry_urlopen(url)
680 except urllib2.HTTPError as e:
681 if e.code == 404:
682 return {}
683 else:
684 raise
685 prebuilt_pkgs = {}
686 for line in f:
687 if line.startswith("CPV: "):
688 pkg = line.replace("CPV: ", "").rstrip()
689 elif line.startswith("MTIME: "):
690 prebuilt_pkgs[pkg] = int(line[:-1].replace("MTIME: ", ""))
691 f.close()
692
693 return prebuilt_pkgs
694
695 def GenDependencyGraph(self, deps_tree, deps_info, remote_pkgs):
615 """Generate a doubly linked dependency graph. 696 """Generate a doubly linked dependency graph.
616 697
617 Args: 698 Args:
618 deps_tree: Dependency tree structure. 699 deps_tree: Dependency tree structure.
619 deps_info: More details on the dependencies. 700 deps_info: More details on the dependencies.
620 Returns: 701 Returns:
621 Deps graph in the form of a dict of packages, with each package 702 Deps graph in the form of a dict of packages, with each package
622 specifying a "needs" list and "provides" list. 703 specifying a "needs" list and "provides" list.
623 """ 704 """
624 emerge = self.emerge 705 emerge = self.emerge
(...skipping 28 matching lines...) Expand all
653 # - action: What we're planning on doing with this package. Generally, 734 # - action: What we're planning on doing with this package. Generally,
654 # "merge", "nomerge", or "uninstall" 735 # "merge", "nomerge", or "uninstall"
655 # - mandatory_source: 736 # - mandatory_source:
656 # If true, indicates that this package must be compiled from source. 737 # If true, indicates that this package must be compiled from source.
657 # We set this for "workon" packages, and for packages where the 738 # We set this for "workon" packages, and for packages where the
658 # binaries are known to be out of date. 739 # binaries are known to be out of date.
659 # - mandatory: 740 # - mandatory:
660 # If true, indicates that this package must be installed. We don't care 741 # If true, indicates that this package must be installed. We don't care
661 # whether it's binary or source, unless the mandatory_source flag is 742 # whether it's binary or source, unless the mandatory_source flag is
662 # also set. 743 # also set.
744 # - force_remote_binary:
745 # If true, indicates that we want to update to the latest remote prebuilt
746 # of this package. Packages that depend on this package should be built
747 # from source.
663 # 748 #
664 deps_map = {} 749 deps_map = {}
665 750
666 def ReverseTree(packages): 751 def ReverseTree(packages):
667 """Convert tree to digraph. 752 """Convert tree to digraph.
668 753
669 Take the tree of package -> requirements and reverse it to a digraph of 754 Take the tree of package -> requirements and reverse it to a digraph of
670 buildable packages -> packages they unblock. 755 buildable packages -> packages they unblock.
671 Args: 756 Args:
672 packages: Tree(s) of dependencies. 757 packages: Tree(s) of dependencies.
673 Returns: 758 Returns:
674 Unsanitized digraph. 759 Unsanitized digraph.
675 """ 760 """
676 for pkg in packages: 761 for pkg in packages:
677 762
678 # Create an entry for the package 763 # Create an entry for the package
679 action = packages[pkg]["action"] 764 action = packages[pkg]["action"]
680 default_pkg = {"needs": {}, "provides": set(), "action": action, 765 default_pkg = {"needs": {}, "provides": set(), "action": action,
681 "mandatory_source": False, "mandatory": False} 766 "mandatory_source": False, "mandatory": False,
767 "force_remote_binary": False}
682 this_pkg = deps_map.setdefault(pkg, default_pkg) 768 this_pkg = deps_map.setdefault(pkg, default_pkg)
683 769
684 # Create entries for dependencies of this package first. 770 # Create entries for dependencies of this package first.
685 ReverseTree(packages[pkg]["deps"]) 771 ReverseTree(packages[pkg]["deps"])
686 772
687 # Add dependencies to this package. 773 # Add dependencies to this package.
688 for dep, dep_item in packages[pkg]["deps"].iteritems(): 774 for dep, dep_item in packages[pkg]["deps"].iteritems():
689 dep_pkg = deps_map[dep] 775 dep_pkg = deps_map[dep]
690 dep_type = dep_item["deptype"] 776 dep_type = dep_item["deptype"]
691 if dep_type != "runtime_post": 777 if dep_type != "runtime_post":
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 988
903 # Mark this package as non-optional 989 # Mark this package as non-optional
904 deps_info[pkg]["optional"] = False 990 deps_info[pkg]["optional"] = False
905 this_pkg[merge_type] = True 991 this_pkg[merge_type] = True
906 for w in this_pkg["provides"].difference(rebuild_blacklist): 992 for w in this_pkg["provides"].difference(rebuild_blacklist):
907 MergeChildren(w, merge_type) 993 MergeChildren(w, merge_type)
908 994
909 if this_pkg["action"] == "nomerge": 995 if this_pkg["action"] == "nomerge":
910 this_pkg["action"] = "merge" 996 this_pkg["action"] = "merge"
911 997
912 def RemotePackageDatabase(binhost_url):
913 """Grab the latest binary package database from the prebuilt server.
914
915 We need to know the modification times of the prebuilt packages so that we
916 know when it is OK to use these packages and when we should rebuild them
917 instead.
918
919 Args:
920 binhost_url: Base URL of remote packages (PORTAGE_BINHOST).
921
922 Returns:
923 A dict mapping package identifiers to modification times.
924 """
925
926 if not binhost_url:
927 return {}
928
929 def retry_urlopen(url, tries=3):
930 """Open the specified url, retrying if we run into network errors.
931
932 We do not retry for HTTP errors.
933
934 Args:
935 url: The specified url.
936 tries: The number of times to try.
937
938 Returns:
939 The result of urllib2.urlopen(url).
940 """
941 for i in range(tries):
942 try:
943 return urllib2.urlopen(url)
944 except urllib2.HTTPError as e:
945 raise
946 except urllib2.URLError as e:
947 if i + 1 == tries:
948 raise
949 else:
950 print "Cannot GET %s: %s" % (url, e)
951
952 url = binhost_url + "/Packages"
953 try:
954 f = retry_urlopen(url)
955 except urllib2.HTTPError as e:
956 if e.code == 404:
957 return {}
958 else:
959 raise
960 prebuilt_pkgs = {}
961 for line in f:
962 if line.startswith("CPV: "):
963 pkg = line.replace("CPV: ", "").rstrip()
964 elif line.startswith("MTIME: "):
965 prebuilt_pkgs[pkg] = int(line[:-1].replace("MTIME: ", ""))
966 f.close()
967
968 return prebuilt_pkgs
969
970 def LocalPackageDatabase(): 998 def LocalPackageDatabase():
971 """Get the modification times of the packages in the local database. 999 """Get the modification times of the packages in the local database.
972 1000
973 We need to know the modification times of the local packages so that we 1001 We need to know the modification times of the local packages so that we
974 know when they need to be rebuilt. 1002 know when they need to be rebuilt.
975 1003
976 Returns: 1004 Returns:
977 A dict mapping package identifiers to modification times. 1005 A dict mapping package identifiers to modification times.
978 """ 1006 """
979 if self.board: 1007 if self.board:
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 Args: 1040 Args:
1013 pkg: The specified package. 1041 pkg: The specified package.
1014 pkg_db: The package DB to use. 1042 pkg_db: The package DB to use.
1015 cache: A dict, where the results are stored. 1043 cache: A dict, where the results are stored.
1016 1044
1017 Returns: 1045 Returns:
1018 True iff the prebuilts are ready for pkg and all deps. 1046 True iff the prebuilts are ready for pkg and all deps.
1019 """ 1047 """
1020 if pkg in cache: 1048 if pkg in cache:
1021 return cache[pkg] 1049 return cache[pkg]
1022 if pkg not in pkg_db: 1050 if pkg not in pkg_db and pkg not in self.forced_remote_binary_packages:
1023 cache[pkg] = False 1051 cache[pkg] = False
1024 else: 1052 else:
1025 cache[pkg] = True 1053 cache[pkg] = True
1026 for dep in deps_map[pkg]["needs"]: 1054 for dep in deps_map[pkg]["needs"]:
1027 if not PrebuiltsReady(dep, pkg_db, cache): 1055 if not PrebuiltsReady(dep, pkg_db, cache):
1028 cache[pkg] = False 1056 cache[pkg] = False
1029 break 1057 break
1030 return cache[pkg] 1058 return cache[pkg]
1031 1059
1032 def LastModifiedWithDeps(pkg, pkg_db, cache): 1060 def LastModifiedWithDeps(pkg, pkg_db, cache):
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1074 # least as new as our local packages, we can install them. 1102 # least as new as our local packages, we can install them.
1075 # Otherwise, we need to build from source. 1103 # Otherwise, we need to build from source.
1076 remote_mtime = LastModifiedWithDeps(pkg, remote_pkgs, 1104 remote_mtime = LastModifiedWithDeps(pkg, remote_pkgs,
1077 remote_mtime_cache) 1105 remote_mtime_cache)
1078 remote_ready = PrebuiltsReady(pkg, remote_pkgs, remote_ready_cache) 1106 remote_ready = PrebuiltsReady(pkg, remote_pkgs, remote_ready_cache)
1079 if remote_ready and (local_mtime <= remote_mtime or pkg in cycles): 1107 if remote_ready and (local_mtime <= remote_mtime or pkg in cycles):
1080 MergeChildren(pkg, "mandatory") 1108 MergeChildren(pkg, "mandatory")
1081 else: 1109 else:
1082 MergeChildren(pkg, "mandatory_source") 1110 MergeChildren(pkg, "mandatory_source")
1083 1111
1084 def UsePrebuiltPackages(): 1112 def UsePrebuiltPackages(remote_pkgs):
1085 """Update packages that can use prebuilts to do so.""" 1113 """Update packages that can use prebuilts to do so."""
1086 start = time.time() 1114 start = time.time()
1087 1115
1088 # The bintree is the database of binary packages. By default, it's 1116 # The bintree is the database of binary packages. By default, it's
1089 # empty. 1117 # empty.
1090 bintree = emerge.trees[root]["bintree"] 1118 bintree = emerge.trees[root]["bintree"]
1091 bindb = bintree.dbapi 1119 bindb = bintree.dbapi
1092 root_config = emerge.root_config 1120 root_config = emerge.root_config
1093 pkgsettings = emerge.depgraph._frozen_config.pkgsettings[root] 1121 pkgsettings = emerge.depgraph._frozen_config.pkgsettings[root]
1094 prebuilt_pkgs = {} 1122 prebuilt_pkgs = {}
1095 1123
1096 # Populate the DB with packages 1124 # Populate the DB with packages
1097 bintree.populate("--getbinpkg" in emerge.opts, 1125 bintree.populate("--getbinpkg" in emerge.opts,
1098 "--getbinpkgonly" in emerge.opts) 1126 "--getbinpkgonly" in emerge.opts)
1099 1127
1100 # Build list of prebuilt packages 1128 # Build list of prebuilt packages
1101 for pkg, info in deps_map.iteritems(): 1129 for pkg, info in deps_map.iteritems():
1102 if info and not info["mandatory_source"] and info["action"] == "merge": 1130 if info and info["action"] == "merge":
1131 if (not info["force_remote_binary"] and info["mandatory_source"] or
1132 "--usepkgonly" not in emerge.opts and pkg not in remote_pkgs):
1133 continue
1134
1103 db_keys = list(bindb._aux_cache_keys) 1135 db_keys = list(bindb._aux_cache_keys)
1104 try: 1136 try:
1105 db_vals = bindb.aux_get(pkg, db_keys + ["MTIME"]) 1137 db_vals = bindb.aux_get(pkg, db_keys + ["MTIME"])
1106 except KeyError: 1138 except KeyError:
1107 # No binary package 1139 # No binary package
1108 continue 1140 continue
1141
1109 mtime = int(db_vals.pop() or 0) 1142 mtime = int(db_vals.pop() or 0)
1110 metadata = zip(db_keys, db_vals) 1143 metadata = zip(db_keys, db_vals)
1111 db_pkg = Package(built=True, cpv=pkg, installed=False, 1144 db_pkg = Package(built=True, cpv=pkg, installed=False,
1112 metadata=metadata, onlydeps=False, mtime=mtime, 1145 metadata=metadata, onlydeps=False, mtime=mtime,
1113 operation="merge", root_config=root_config, 1146 operation="merge", root_config=root_config,
1114 type_name="binary") 1147 type_name="binary")
1115 prebuilt_pkgs[pkg] = db_pkg 1148 prebuilt_pkgs[pkg] = db_pkg
1116 1149
1117 # Calculate what packages need to be rebuilt due to changes in use flags. 1150 # Calculate what packages need to be rebuilt due to changes in use flags.
1118 for pkg, db_pkg in prebuilt_pkgs.iteritems(): 1151 for pkg, db_pkg in prebuilt_pkgs.iteritems():
1119 db_pkg_src = self.package_db[pkg] 1152 db_pkg_src = self.package_db.get(pkg)
1120 if not self.CheckUseFlags(pkgsettings, db_pkg, db_pkg_src): 1153 if db_pkg_src and not self.CheckUseFlags(pkgsettings, db_pkg,
1154 db_pkg_src):
1121 MergeChildren(pkg, "mandatory_source") 1155 MergeChildren(pkg, "mandatory_source")
1122 1156
1123 # Convert eligible packages to binaries. 1157 # Convert eligible packages to binaries.
1124 for pkg, info in deps_map.iteritems(): 1158 for pkg, info in deps_map.iteritems():
1125 if (info and not info["mandatory_source"] and 1159 if info and info["action"] == "merge" and pkg in prebuilt_pkgs:
1126 info["action"] == "merge" and pkg in prebuilt_pkgs): 1160 if not info["mandatory_source"] or info["force_remote_binary"]:
1127 self.package_db[pkg] = prebuilt_pkgs[pkg] 1161 self.package_db[pkg] = prebuilt_pkgs[pkg]
1128 1162
1129 seconds = time.time() - start 1163 seconds = time.time() - start
1130 if "--quiet" not in emerge.opts: 1164 if "--quiet" not in emerge.opts:
1131 print "Prebuilt DB populated in %dm%.1fs" % (seconds / 60, seconds % 60) 1165 print "Prebuilt DB populated in %dm%.1fs" % (seconds / 60, seconds % 60)
1132 1166
1133 return prebuilt_pkgs 1167 return prebuilt_pkgs
1134 1168
1135 def AddRemainingPackages(): 1169 def AddRemainingPackages():
1136 """Fill in packages that don't have entries in the package db. 1170 """Fill in packages that don't have entries in the package db.
1137 1171
1138 Every package we are installing needs an entry in the package db. 1172 Every package we are installing needs an entry in the package db.
1139 This function should only be called after we have removed the 1173 This function should only be called after we have removed the
1140 packages that are not being merged from our deps_map. 1174 packages that are not being merged from our deps_map.
1141 """ 1175 """
1142 for pkg in deps_map: 1176 for pkg in deps_map:
1143 if pkg not in self.package_db: 1177 if pkg not in self.package_db:
1144 if deps_map[pkg]["action"] != "merge": 1178 if deps_map[pkg]["action"] != "merge":
1145 # We should only fill in packages that are being merged. If 1179 # We should only fill in packages that are being merged. If
1146 # there's any other packages here, something funny is going on. 1180 # there's any other packages here, something funny is going on.
1147 print "Missing entry for %s in package db" % pkg 1181 print "Missing entry for %s in package db" % pkg
1148 sys.exit(1) 1182 sys.exit(1)
1149 1183
1150 db_pkg = emerge.depgraph._pkg(pkg, "ebuild", emerge.root_config) 1184 db_pkg = emerge.depgraph._pkg(pkg, "ebuild", emerge.root_config)
1151 self.package_db[pkg] = db_pkg 1185 self.package_db[pkg] = db_pkg
1152 1186
1153 ReverseTree(deps_tree) 1187 ReverseTree(deps_tree)
1154 BuildFinalPackageSet() 1188 BuildFinalPackageSet()
1155 AddSecretDeps() 1189 AddSecretDeps()
1156 1190
1191 # Mark that we want to use remote binaries only for a particular package.
1192 vardb = emerge.depgraph._frozen_config.trees[root]["vartree"].dbapi
1193 for pkg in self.force_remote_binary:
1194 for db_pkg in final_db.match_pkgs(pkg):
1195 match = deps_map.get(str(db_pkg.cpv))
1196 if match:
1197 match["force_remote_binary"] = True
1198
1199 rebuild_blacklist.add(str(db_pkg.cpv))
1200 if not vardb.match_pkgs(db_pkg.cpv):
1201 MergeChildren(str(db_pkg.cpv), "mandatory")
1202
1157 if self.no_workon_deps: 1203 if self.no_workon_deps:
1158 for pkg in self.mandatory_source.copy(): 1204 for pkg in self.mandatory_source.copy():
1159 for db_pkg in final_db.match_pkgs(pkg): 1205 for db_pkg in final_db.match_pkgs(pkg):
1160 deps_map[str(db_pkg.cpv)]["mandatory_source"] = True 1206 deps_map[str(db_pkg.cpv)]["mandatory_source"] = True
1161 else: 1207 else:
1162 for pkg in self.mandatory_source.copy(): 1208 for pkg in self.mandatory_source.copy():
1163 for db_pkg in final_db.match_pkgs(pkg): 1209 for db_pkg in final_db.match_pkgs(pkg):
1164 MergeChildren(str(db_pkg.cpv), "mandatory_source") 1210 MergeChildren(str(db_pkg.cpv), "mandatory_source")
1165 1211
1166 cycles = FindCycles() 1212 cycles = FindCycles()
1167 if self.rebuild: 1213 if self.rebuild:
1168 local_pkgs = LocalPackageDatabase() 1214 local_pkgs = LocalPackageDatabase()
1169 remote_pkgs = {}
1170 if "--getbinpkg" in emerge.opts:
1171 binhost = emerge.settings["PORTAGE_BINHOST"]
1172 remote_pkgs = RemotePackageDatabase(binhost)
1173 AutoRebuildDeps(local_pkgs, remote_pkgs, cycles) 1215 AutoRebuildDeps(local_pkgs, remote_pkgs, cycles)
1174 1216
1175 # We need to remove installed packages so that we can use the dependency 1217 # We need to remove installed packages so that we can use the dependency
1176 # ordering of the install process to show us what cycles to crack. Once 1218 # ordering of the install process to show us what cycles to crack. Once
1177 # we've done that, we also need to recalculate our list of cycles so that 1219 # we've done that, we also need to recalculate our list of cycles so that
1178 # we don't include the installed packages in our cycles. 1220 # we don't include the installed packages in our cycles.
1179 RemoveInstalledPackages() 1221 RemoveInstalledPackages()
1180 SanitizeTree() 1222 SanitizeTree()
1181 if deps_map: 1223 if deps_map:
1182 if "--usepkg" in emerge.opts: 1224 if "--usepkg" in emerge.opts:
1183 UsePrebuiltPackages() 1225 UsePrebuiltPackages(remote_pkgs)
1184 AddRemainingPackages() 1226 AddRemainingPackages()
1185 return deps_map 1227 return deps_map
1186 1228
1187 def PrintInstallPlan(self, deps_map): 1229 def PrintInstallPlan(self, deps_map):
1188 """Print an emerge-style install plan. 1230 """Print an emerge-style install plan.
1189 1231
1190 The install plan lists what packages we're installing, in order. 1232 The install plan lists what packages we're installing, in order.
1191 It's useful for understanding what parallel_emerge is doing. 1233 It's useful for understanding what parallel_emerge is doing.
1192 1234
1193 Args: 1235 Args:
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after
1727 if "--quiet" not in emerge.opts: 1769 if "--quiet" not in emerge.opts:
1728 cmdline_packages = " ".join(emerge.cmdline_packages) 1770 cmdline_packages = " ".join(emerge.cmdline_packages)
1729 nomerge_packages = " ".join(deps.nomerge) 1771 nomerge_packages = " ".join(deps.nomerge)
1730 print "Starting fast-emerge." 1772 print "Starting fast-emerge."
1731 print " Building package %s on %s" % (cmdline_packages, 1773 print " Building package %s on %s" % (cmdline_packages,
1732 deps.board or "root") 1774 deps.board or "root")
1733 if nomerge_packages: 1775 if nomerge_packages:
1734 print " Skipping package %s on %s" % (nomerge_packages, 1776 print " Skipping package %s on %s" % (nomerge_packages,
1735 deps.board or "root") 1777 deps.board or "root")
1736 1778
1737 deps_tree, deps_info = deps.GenDependencyTree() 1779 remote_pkgs = {}
1780 if "--getbinpkg" in emerge.opts:
1781 binhost = emerge.settings["PORTAGE_BINHOST"]
1782 remote_pkgs = deps.RemotePackageDatabase(binhost)
1783
1784 deps_tree, deps_info = deps.GenDependencyTree(remote_pkgs)
1738 1785
1739 # You want me to be verbose? I'll give you two trees! Twice as much value. 1786 # You want me to be verbose? I'll give you two trees! Twice as much value.
1740 if "--tree" in emerge.opts and "--verbose" in emerge.opts: 1787 if "--tree" in emerge.opts and "--verbose" in emerge.opts:
1741 deps.PrintTree(deps_tree) 1788 deps.PrintTree(deps_tree)
1742 1789
1743 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) 1790 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info, remote_pkgs)
1744 1791
1745 # OK, time to print out our progress so far. 1792 # OK, time to print out our progress so far.
1746 deps.PrintInstallPlan(deps_graph) 1793 deps.PrintInstallPlan(deps_graph)
1747 if "--tree" in emerge.opts: 1794 if "--tree" in emerge.opts:
1748 PrintDepsMap(deps_graph) 1795 PrintDepsMap(deps_graph)
1749 1796
1750 # Are we upgrading portage? If so, and there are more packages to merge, 1797 # Are we upgrading portage? If so, and there are more packages to merge,
1751 # schedule a restart of parallel_emerge to merge the rest. This ensures that 1798 # schedule a restart of parallel_emerge to merge the rest. This ensures that
1752 # we pick up all updates to portage settings before merging any more 1799 # we pick up all updates to portage settings before merging any more
1753 # packages. 1800 # packages.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1789 # need to upgrade the rest of the packages. So we'll go ahead and do that. 1836 # need to upgrade the rest of the packages. So we'll go ahead and do that.
1790 if portage_upgrade: 1837 if portage_upgrade:
1791 args = sys.argv[1:] + ["--nomerge=sys-apps/portage"] 1838 args = sys.argv[1:] + ["--nomerge=sys-apps/portage"]
1792 os.execvp(os.path.realpath(sys.argv[0]), args) 1839 os.execvp(os.path.realpath(sys.argv[0]), args)
1793 1840
1794 print "Done" 1841 print "Done"
1795 sys.exit(0) 1842 sys.exit(0)
1796 1843
1797 if __name__ == "__main__": 1844 if __name__ == "__main__":
1798 main() 1845 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