| 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 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 Typical usage: | 210 Typical usage: |
| 211 deps = DepGraphGenerator() | 211 deps = DepGraphGenerator() |
| 212 deps.Initialize(sys.argv[1:]) | 212 deps.Initialize(sys.argv[1:]) |
| 213 deps_tree, deps_info = deps.GenDependencyTree() | 213 deps_tree, deps_info = deps.GenDependencyTree() |
| 214 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) | 214 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) |
| 215 deps.PrintTree(deps_tree) | 215 deps.PrintTree(deps_tree) |
| 216 PrintDepsMap(deps_graph) | 216 PrintDepsMap(deps_graph) |
| 217 """ | 217 """ |
| 218 | 218 |
| 219 __slots__ = ["board", "emerge", "mandatory_source", "no_workon_deps", | 219 __slots__ = ["board", "emerge", "mandatory_source", "no_workon_deps", |
| 220 "package_db", "rebuild", "show_output"] | 220 "nomerge", "package_db", "rebuild", "show_output"] |
| 221 | 221 |
| 222 def __init__(self): | 222 def __init__(self): |
| 223 self.board = None | 223 self.board = None |
| 224 self.emerge = EmergeData() | 224 self.emerge = EmergeData() |
| 225 self.mandatory_source = set() | 225 self.mandatory_source = set() |
| 226 self.no_workon_deps = False | 226 self.no_workon_deps = False |
| 227 self.nomerge = set() |
| 227 self.package_db = {} | 228 self.package_db = {} |
| 228 self.rebuild = False | 229 self.rebuild = False |
| 229 self.show_output = False | 230 self.show_output = False |
| 230 | 231 |
| 231 def ParseParallelEmergeArgs(self, argv): | 232 def ParseParallelEmergeArgs(self, argv): |
| 232 """Read the parallel emerge arguments from the command-line. | 233 """Read the parallel emerge arguments from the command-line. |
| 233 | 234 |
| 234 We need to be compatible with emerge arg format. We scrape arguments that | 235 We need to be compatible with emerge arg format. We scrape arguments that |
| 235 are specific to parallel_emerge, and pass through the rest directly to | 236 are specific to parallel_emerge, and pass through the rest directly to |
| 236 emerge. | 237 emerge. |
| 237 Args: | 238 Args: |
| 238 argv: arguments list | 239 argv: arguments list |
| 239 Returns: | 240 Returns: |
| 240 Arguments that don't belong to parallel_emerge | 241 Arguments that don't belong to parallel_emerge |
| 241 """ | 242 """ |
| 242 emerge_args = [] | 243 emerge_args = [] |
| 243 for arg in argv: | 244 for arg in argv: |
| 244 # Specifically match arguments that are specific to parallel_emerge, and | 245 # Specifically match arguments that are specific to parallel_emerge, and |
| 245 # pass through the rest. | 246 # pass through the rest. |
| 246 if arg.startswith("--board="): | 247 if arg.startswith("--board="): |
| 247 self.board = arg.replace("--board=", "") | 248 self.board = arg.replace("--board=", "") |
| 248 elif arg.startswith("--workon="): | 249 elif arg.startswith("--workon="): |
| 249 workon_str = arg.replace("--workon=", "") | 250 workon_str = arg.replace("--workon=", "") |
| 250 package_list = shlex.split(" ".join(shlex.split(workon_str))) | 251 package_list = shlex.split(" ".join(shlex.split(workon_str))) |
| 251 self.mandatory_source.update(package_list) | 252 self.mandatory_source.update(package_list) |
| 253 elif arg.startswith("--nomerge="): |
| 254 nomerge_str = arg.replace("--nomerge=", "") |
| 255 package_list = shlex.split(" ".join(shlex.split(nomerge_str))) |
| 256 self.nomerge.update(package_list) |
| 252 elif arg == "--no-workon-deps": | 257 elif arg == "--no-workon-deps": |
| 253 self.no_workon_deps = True | 258 self.no_workon_deps = True |
| 254 elif arg == "--rebuild": | 259 elif arg == "--rebuild": |
| 255 self.rebuild = True | 260 self.rebuild = True |
| 256 elif arg == "--show-output": | 261 elif arg == "--show-output": |
| 257 self.show_output = True | 262 self.show_output = True |
| 258 else: | 263 else: |
| 259 # Not one of our options, so pass through to emerge. | 264 # Not one of our options, so pass through to emerge. |
| 260 emerge_args.append(arg) | 265 emerge_args.append(arg) |
| 261 | 266 |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 print "Skipping %s (is it in package.provided?)" % pkg | 773 print "Skipping %s (is it in package.provided?)" % pkg |
| 769 | 774 |
| 770 # Schedule packages that aren't on the install list for removal | 775 # Schedule packages that aren't on the install list for removal |
| 771 rm_pkgs = set(deps_map.keys()) - set(deps_info.keys()) | 776 rm_pkgs = set(deps_map.keys()) - set(deps_info.keys()) |
| 772 | 777 |
| 773 # Schedule optional packages for removal | 778 # Schedule optional packages for removal |
| 774 for pkg, info in deps_info.items(): | 779 for pkg, info in deps_info.items(): |
| 775 if info["optional"]: | 780 if info["optional"]: |
| 776 rm_pkgs.add(pkg) | 781 rm_pkgs.add(pkg) |
| 777 | 782 |
| 783 # Schedule nomerge packages for removal |
| 784 for pkg in self.nomerge: |
| 785 for db_pkg in final_db.match_pkgs(pkg): |
| 786 if db_pkg.cpv in deps_map: |
| 787 rm_pkgs.add(str(db_pkg.cpv)) |
| 788 |
| 778 # Remove the packages we don't want, simplifying the graph and making | 789 # Remove the packages we don't want, simplifying the graph and making |
| 779 # it easier for us to crack cycles. | 790 # it easier for us to crack cycles. |
| 780 for pkg in sorted(rm_pkgs): | 791 for pkg in sorted(rm_pkgs): |
| 781 this_pkg = deps_map[pkg] | 792 this_pkg = deps_map[pkg] |
| 782 needs = this_pkg["needs"] | 793 needs = this_pkg["needs"] |
| 783 provides = this_pkg["provides"] | 794 provides = this_pkg["provides"] |
| 784 for dep in needs: | 795 for dep in needs: |
| 785 dep_provides = deps_map[dep]["provides"] | 796 dep_provides = deps_map[dep]["provides"] |
| 786 dep_provides.update(provides) | 797 dep_provides.update(provides) |
| 787 dep_provides.discard(pkg) | 798 dep_provides.discard(pkg) |
| (...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1604 # | 1615 # |
| 1605 # NOTE: Even if you're running --pretend, it's a good idea to run | 1616 # NOTE: Even if you're running --pretend, it's a good idea to run |
| 1606 # parallel_emerge with root access so that portage can write to the | 1617 # parallel_emerge with root access so that portage can write to the |
| 1607 # dependency cache. This is important for performance. | 1618 # dependency cache. This is important for performance. |
| 1608 if "--pretend" not in emerge.opts and portage.secpass < 2: | 1619 if "--pretend" not in emerge.opts and portage.secpass < 2: |
| 1609 print "parallel_emerge: superuser access is required." | 1620 print "parallel_emerge: superuser access is required." |
| 1610 sys.exit(1) | 1621 sys.exit(1) |
| 1611 | 1622 |
| 1612 if "--quiet" not in emerge.opts: | 1623 if "--quiet" not in emerge.opts: |
| 1613 cmdline_packages = " ".join(emerge.cmdline_packages) | 1624 cmdline_packages = " ".join(emerge.cmdline_packages) |
| 1625 nomerge_packages = " ".join(deps.nomerge) |
| 1614 print "Starting fast-emerge." | 1626 print "Starting fast-emerge." |
| 1615 print " Building package %s on %s" % (cmdline_packages, | 1627 print " Building package %s on %s" % (cmdline_packages, |
| 1616 deps.board or "root") | 1628 deps.board or "root") |
| 1629 if nomerge_packages: |
| 1630 print " Skipping package %s on %s" % (nomerge_packages, |
| 1631 deps.board or "root") |
| 1617 | 1632 |
| 1618 deps_tree, deps_info = deps.GenDependencyTree() | 1633 deps_tree, deps_info = deps.GenDependencyTree() |
| 1619 | 1634 |
| 1620 # You want me to be verbose? I'll give you two trees! Twice as much value. | 1635 # You want me to be verbose? I'll give you two trees! Twice as much value. |
| 1621 if "--tree" in emerge.opts and "--verbose" in emerge.opts: | 1636 if "--tree" in emerge.opts and "--verbose" in emerge.opts: |
| 1622 deps.PrintTree(deps_tree) | 1637 deps.PrintTree(deps_tree) |
| 1623 | 1638 |
| 1624 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) | 1639 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) |
| 1625 | 1640 |
| 1626 # OK, time to print out our progress so far. | 1641 # OK, time to print out our progress so far. |
| 1627 deps.PrintInstallPlan(deps_graph) | 1642 deps.PrintInstallPlan(deps_graph) |
| 1628 if "--tree" in emerge.opts: | 1643 if "--tree" in emerge.opts: |
| 1629 PrintDepsMap(deps_graph) | 1644 PrintDepsMap(deps_graph) |
| 1630 | 1645 |
| 1646 # Are we upgrading portage? If so, and there are more packages to merge, |
| 1647 # schedule a restart of parallel_emerge to merge the rest. This ensures that |
| 1648 # we pick up all updates to portage settings before merging any more |
| 1649 # packages. |
| 1650 portage_upgrade = False |
| 1651 root = emerge.settings["ROOT"] |
| 1652 final_db = emerge.depgraph._dynamic_config.mydbapi[root] |
| 1653 if root == "/": |
| 1654 for db_pkg in final_db.match_pkgs("sys-apps/portage"): |
| 1655 portage_pkg = deps_graph.get(db_pkg.cpv) |
| 1656 if portage and len(deps_graph) > 1: |
| 1657 deps_graph = { str(db_pkg.cpv): portage_pkg } |
| 1658 portage_upgrade = True |
| 1659 if "--quiet" not in emerge.opts: |
| 1660 print "Upgrading portage first, then restarting..." |
| 1661 |
| 1631 # Run the queued emerges. | 1662 # Run the queued emerges. |
| 1632 scheduler = EmergeQueue(deps_graph, emerge, deps.package_db, deps.show_output) | 1663 scheduler = EmergeQueue(deps_graph, emerge, deps.package_db, deps.show_output) |
| 1633 scheduler.Run() | 1664 scheduler.Run() |
| 1634 | 1665 |
| 1635 # Update world. | 1666 # Update world. |
| 1636 if ("--oneshot" not in emerge.opts and | 1667 if ("--oneshot" not in emerge.opts and |
| 1637 "--pretend" not in emerge.opts): | 1668 "--pretend" not in emerge.opts): |
| 1638 world_set = emerge.root_config.sets["selected"] | 1669 world_set = emerge.root_config.sets["selected"] |
| 1639 new_world_pkgs = [] | 1670 new_world_pkgs = [] |
| 1640 root = emerge.settings["ROOT"] | |
| 1641 final_db = emerge.depgraph._dynamic_config.mydbapi[root] | |
| 1642 for pkg in emerge.cmdline_packages: | 1671 for pkg in emerge.cmdline_packages: |
| 1643 for db_pkg in final_db.match_pkgs(pkg): | 1672 for db_pkg in final_db.match_pkgs(pkg): |
| 1644 print "Adding %s to world" % db_pkg.cp | 1673 print "Adding %s to world" % db_pkg.cp |
| 1645 new_world_pkgs.append(db_pkg.cp) | 1674 new_world_pkgs.append(db_pkg.cp) |
| 1646 if new_world_pkgs: | 1675 if new_world_pkgs: |
| 1647 world_set.update(new_world_pkgs) | 1676 world_set.update(new_world_pkgs) |
| 1648 | 1677 |
| 1649 # Update environment (library cache, symlinks, etc.) | 1678 # Update environment (library cache, symlinks, etc.) |
| 1650 if deps.board and "--pretend" not in emerge.opts: | 1679 if deps.board and "--pretend" not in emerge.opts: |
| 1651 portage.env_update() | 1680 portage.env_update() |
| 1652 | 1681 |
| 1682 # If we already upgraded portage, we don't need to do so again. But we do |
| 1683 # need to upgrade the rest of the packages. So we'll go ahead and do that. |
| 1684 if portage_upgrade: |
| 1685 args = sys.argv[1:] + ["--nomerge=sys-apps/portage"] |
| 1686 os.execvp(os.path.realpath(sys.argv[0]), args) |
| 1687 |
| 1653 print "Done" | 1688 print "Done" |
| 1654 | 1689 |
| 1655 if __name__ == "__main__": | 1690 if __name__ == "__main__": |
| 1656 main() | 1691 main() |
| OLD | NEW |