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 |