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 |