| 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 [--force-remote-binary=PKGS] [emerge args] package | 10 [--force-remote-binary=PKGS] [emerge args] package |
| (...skipping 697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 | 708 |
| 709 Args: | 709 Args: |
| 710 deps: Dependency tree structure. | 710 deps: Dependency tree structure. |
| 711 depth: Allows printing the tree recursively, with indentation. | 711 depth: Allows printing the tree recursively, with indentation. |
| 712 """ | 712 """ |
| 713 for entry in sorted(deps): | 713 for entry in sorted(deps): |
| 714 action = deps[entry]["action"] | 714 action = deps[entry]["action"] |
| 715 print "%s %s (%s)" % (depth, entry, action) | 715 print "%s %s (%s)" % (depth, entry, action) |
| 716 self.PrintTree(deps[entry]["deps"], depth=depth + " ") | 716 self.PrintTree(deps[entry]["deps"], depth=depth + " ") |
| 717 | 717 |
| 718 def RemotePackageDatabase(self, binhost_url, settings): | 718 def RemotePackageDatabase(self): |
| 719 """Grab the latest binary package database from the prebuilt server. | 719 """Grab the latest binary package database from the prebuilt server. |
| 720 | 720 |
| 721 We need to know the modification times of the prebuilt packages so that we | 721 We need to know the modification times of the prebuilt packages so that we |
| 722 know when it is OK to use these packages and when we should rebuild them | 722 know when it is OK to use these packages and when we should rebuild them |
| 723 instead. | 723 instead. |
| 724 | 724 |
| 725 Args: | |
| 726 binhost_url: Base URL of remote packages (PORTAGE_BINHOST). | |
| 727 | |
| 728 Returns: | 725 Returns: |
| 729 A dict mapping package identifiers to modification times. | 726 A dict mapping package identifiers to modification times. |
| 730 """ | 727 """ |
| 731 | 728 root = self.emerge.settings["ROOT"] |
| 732 if not binhost_url: | 729 bindb = self.emerge.trees[root]["bintree"].dbapi |
| 733 return {} | |
| 734 | |
| 735 def retry_urlopen(url, tries=3): | |
| 736 """Open the specified url, retrying if we run into temporary errors. | |
| 737 | |
| 738 We retry for both network errors and 5xx Server Errors. We do not retry | |
| 739 for HTTP errors with a non-5xx code. | |
| 740 | |
| 741 Args: | |
| 742 url: The specified url. | |
| 743 tries: The number of times to try. | |
| 744 | |
| 745 Returns: | |
| 746 The result of urllib2.urlopen(url). | |
| 747 """ | |
| 748 for i in range(tries): | |
| 749 try: | |
| 750 return urllib2.urlopen(url) | |
| 751 except urllib2.HTTPError as e: | |
| 752 print "Cannot GET %s: %s" % (url, str(e)) | |
| 753 if i + 1 >= tries or e.code < 500: | |
| 754 raise | |
| 755 except urllib2.URLError as e: | |
| 756 print "Cannot GET %s: %s" % (url, str(e)) | |
| 757 if i + 1 >= tries: | |
| 758 raise | |
| 759 print "Sleeping for 10 seconds before retrying..." | |
| 760 time.sleep(10) | |
| 761 | |
| 762 url = os.path.join(binhost_url, "Packages") | |
| 763 tmp_filename = None | |
| 764 if url.startswith("http://"): | |
| 765 try: | |
| 766 f = retry_urlopen(url) | |
| 767 except urllib2.HTTPError as e: | |
| 768 if e.code == 404: | |
| 769 return {} | |
| 770 else: | |
| 771 raise | |
| 772 else: | |
| 773 parsed_url = urlparse.urlparse(url) | |
| 774 setting = 'FETCHCOMMAND_' + parsed_url.scheme.upper() | |
| 775 fcmd = settings.get(setting) | |
| 776 if not fcmd: | |
| 777 print >>sys.stderr, "Unrecognized URL:", url | |
| 778 sys.exit(1) | |
| 779 fd, tmp_filename = tempfile.mkstemp() | |
| 780 tmp_dirname, tmp_basename = os.path.split(tmp_filename) | |
| 781 os.close(fd) | |
| 782 success = portage.getbinpkg.file_get(url, tmp_dirname, fcmd=fcmd, | |
| 783 filename=tmp_basename) | |
| 784 if not success: | |
| 785 os.unlink(tmp_filename) | |
| 786 return {} | |
| 787 f = open(tmp_filename) | |
| 788 | |
| 789 prebuilt_pkgs = {} | 730 prebuilt_pkgs = {} |
| 790 for line in f: | 731 for pkg in bindb.cpv_all(): |
| 791 if line.startswith("CPV: "): | 732 prebuilt_pkgs[pkg] = bindb.aux_get(pkg, ["BUILD_TIME"])[0] |
| 792 pkg = line.replace("CPV: ", "").rstrip() | |
| 793 elif line.startswith("MTIME: "): | |
| 794 prebuilt_pkgs[pkg] = int(line[:-1].replace("MTIME: ", "")) | |
| 795 f.close() | |
| 796 | |
| 797 if tmp_filename: | |
| 798 os.unlink(tmp_filename) | |
| 799 | |
| 800 return prebuilt_pkgs | 733 return prebuilt_pkgs |
| 801 | 734 |
| 802 def GenDependencyGraph(self, deps_tree, deps_info, remote_pkgs): | 735 def GenDependencyGraph(self, deps_tree, deps_info, remote_pkgs): |
| 803 """Generate a doubly linked dependency graph. | 736 """Generate a doubly linked dependency graph. |
| 804 | 737 |
| 805 Args: | 738 Args: |
| 806 deps_tree: Dependency tree structure. | 739 deps_tree: Dependency tree structure. |
| 807 deps_info: More details on the dependencies. | 740 deps_info: More details on the dependencies. |
| 808 Returns: | 741 Returns: |
| 809 Deps graph in the form of a dict of packages, with each package | 742 Deps graph in the form of a dict of packages, with each package |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1104 | 1037 |
| 1105 def LocalPackageDatabase(): | 1038 def LocalPackageDatabase(): |
| 1106 """Get the modification times of the packages in the local database. | 1039 """Get the modification times of the packages in the local database. |
| 1107 | 1040 |
| 1108 We need to know the modification times of the local packages so that we | 1041 We need to know the modification times of the local packages so that we |
| 1109 know when they need to be rebuilt. | 1042 know when they need to be rebuilt. |
| 1110 | 1043 |
| 1111 Returns: | 1044 Returns: |
| 1112 A dict mapping package identifiers to modification times. | 1045 A dict mapping package identifiers to modification times. |
| 1113 """ | 1046 """ |
| 1114 if self.board: | 1047 vardb = emerge.trees[root]["vartree"].dbapi |
| 1115 path = "/build/%s/packages/Packages" % self.board | |
| 1116 else: | |
| 1117 path = "/var/lib/portage/pkgs/Packages" | |
| 1118 local_pkgs = {} | 1048 local_pkgs = {} |
| 1119 for line in file(path): | 1049 for pkg in vardb.cpv_all(): |
| 1120 if line.startswith("CPV: "): | 1050 local_pkgs[pkg] = vardb.aux_get(pkg, ["BUILD_TIME"])[0] |
| 1121 pkg = line.replace("CPV: ", "").rstrip() | |
| 1122 elif line.startswith("MTIME: "): | |
| 1123 local_pkgs[pkg] = int(line[:-1].replace("MTIME: ", "")) | |
| 1124 | |
| 1125 return local_pkgs | 1051 return local_pkgs |
| 1126 | 1052 |
| 1127 def AutoRebuildDeps(local_pkgs, remote_pkgs, cycles): | 1053 def AutoRebuildDeps(local_pkgs, remote_pkgs, cycles): |
| 1128 """Recursively rebuild packages when necessary using modification times. | 1054 """Recursively rebuild packages when necessary using modification times. |
| 1129 | 1055 |
| 1130 If you've modified a package, it's a good idea to rebuild all the packages | 1056 If you've modified a package, it's a good idea to rebuild all the packages |
| 1131 that depend on it from source. This function looks for any packages which | 1057 that depend on it from source. This function looks for any packages which |
| 1132 depend on packages that have been modified and ensures that they get | 1058 depend on packages that have been modified and ensures that they get |
| 1133 rebuilt. | 1059 rebuilt. |
| 1134 | 1060 |
| (...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1848 nomerge_packages = " ".join(deps.nomerge) | 1774 nomerge_packages = " ".join(deps.nomerge) |
| 1849 print "Starting fast-emerge." | 1775 print "Starting fast-emerge." |
| 1850 print " Building package %s on %s" % (cmdline_packages, | 1776 print " Building package %s on %s" % (cmdline_packages, |
| 1851 deps.board or "root") | 1777 deps.board or "root") |
| 1852 if nomerge_packages: | 1778 if nomerge_packages: |
| 1853 print " Skipping package %s on %s" % (nomerge_packages, | 1779 print " Skipping package %s on %s" % (nomerge_packages, |
| 1854 deps.board or "root") | 1780 deps.board or "root") |
| 1855 | 1781 |
| 1856 remote_pkgs = {} | 1782 remote_pkgs = {} |
| 1857 if "--getbinpkg" in emerge.opts: | 1783 if "--getbinpkg" in emerge.opts: |
| 1858 binhosts = emerge.settings["PORTAGE_BINHOST"] | 1784 remote_pkgs = deps.RemotePackageDatabase() |
| 1859 for binhost in binhosts.split(): | |
| 1860 try: | |
| 1861 remote_pkgs.update(deps.RemotePackageDatabase(binhost, emerge.settings)) | |
| 1862 except (urllib2.HTTPError, urllib2.URLError): | |
| 1863 pass | |
| 1864 if not remote_pkgs: | |
| 1865 print "Can't find any binary packages. Building from source..." | |
| 1866 del emerge.opts["--getbinpkg"] | |
| 1867 | 1785 |
| 1868 deps_tree, deps_info = deps.GenDependencyTree(remote_pkgs) | 1786 deps_tree, deps_info = deps.GenDependencyTree(remote_pkgs) |
| 1869 | 1787 |
| 1870 # You want me to be verbose? I'll give you two trees! Twice as much value. | 1788 # You want me to be verbose? I'll give you two trees! Twice as much value. |
| 1871 if "--tree" in emerge.opts and "--verbose" in emerge.opts: | 1789 if "--tree" in emerge.opts and "--verbose" in emerge.opts: |
| 1872 deps.PrintTree(deps_tree) | 1790 deps.PrintTree(deps_tree) |
| 1873 | 1791 |
| 1874 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info, remote_pkgs) | 1792 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info, remote_pkgs) |
| 1875 | 1793 |
| 1876 # OK, time to print out our progress so far. | 1794 # OK, time to print out our progress so far. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1920 # need to upgrade the rest of the packages. So we'll go ahead and do that. | 1838 # need to upgrade the rest of the packages. So we'll go ahead and do that. |
| 1921 if portage_upgrade: | 1839 if portage_upgrade: |
| 1922 args = sys.argv[1:] + ["--nomerge=sys-apps/portage"] | 1840 args = sys.argv[1:] + ["--nomerge=sys-apps/portage"] |
| 1923 os.execvp(os.path.realpath(sys.argv[0]), args) | 1841 os.execvp(os.path.realpath(sys.argv[0]), args) |
| 1924 | 1842 |
| 1925 print "Done" | 1843 print "Done" |
| 1926 sys.exit(0) | 1844 sys.exit(0) |
| 1927 | 1845 |
| 1928 if __name__ == "__main__": | 1846 if __name__ == "__main__": |
| 1929 main() | 1847 main() |
| OLD | NEW |