Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python2.6 | 1 #!/usr/bin/python2.6 |
| 2 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 2 # Copyright (c) 2011 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 """Perform various tasks related to updating Portage packages.""" | 6 """Perform various tasks related to updating Portage packages.""" |
| 7 | 7 |
| 8 import glob | 8 import glob |
| 9 import logging | 9 import logging |
| 10 import optparse | 10 import optparse |
| 11 import os | 11 import os |
| 12 import parallel_emerge | 12 import parallel_emerge |
| 13 import portage | 13 import portage |
| 14 import re | 14 import re |
| 15 import shutil | 15 import shutil |
| 16 import sys | 16 import sys |
| 17 | 17 |
| 18 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) | 18 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) |
| 19 import chromite.lib.cros_build_lib as cros_lib | 19 import chromite.lib.cros_build_lib as cros_lib |
| 20 | 20 |
| 21 | 21 |
| 22 class Updater(object): | 22 class Upgrader(object): |
| 23 """A class to perform various tasks related to updating Portage packages.""" | 23 """A class to perform various tasks related to updating Portage packages.""" |
| 24 | 24 |
| 25 def __init__(self, options, args): | 25 def __init__(self, options, args): |
| 26 self._options = options | 26 self._options = options |
| 27 self._args = args | 27 self._args = args |
| 28 self._stable_repo = os.path.join(self._options.srcroot, | 28 self._stable_repo = os.path.join(self._options.srcroot, |
| 29 'third_party', 'portage-stable') | 29 'third_party', 'portage-stable') |
| 30 self._upstream_repo = self._options.upstream | 30 self._upstream_repo = self._options.upstream |
| 31 if not self._upstream_repo: | 31 if not self._upstream_repo: |
| 32 self._upstream_repo = os.path.join(self._options.srcroot, | 32 self._upstream_repo = os.path.join(self._options.srcroot, |
| 33 'third_party', 'portage') | 33 'third_party', 'portage') |
| 34 | 34 |
| 35 @staticmethod | 35 @staticmethod |
| 36 def _GetPreOrderDepGraphPackage(deps_graph, package, pkglist, visited): | 36 def _GetPreOrderDepGraphPackage(deps_graph, package, pkglist, visited): |
| 37 """Collect packages from |deps_graph| into |pkglist| in pre-order.""" | 37 """Collect packages from |deps_graph| into |pkglist| in pre-order.""" |
| 38 if package in visited: | 38 if package in visited: |
| 39 return | 39 return |
| 40 visited.add(package) | 40 visited.add(package) |
| 41 for parent in deps_graph[package]['provides']: | 41 for parent in deps_graph[package]['provides']: |
| 42 Updater._GetPreOrderDepGraphPackage(deps_graph, parent, pkglist, visited) | 42 Upgrader._GetPreOrderDepGraphPackage(deps_graph, parent, pkglist, visited) |
| 43 pkglist.append(package) | 43 pkglist.append(package) |
| 44 | 44 |
| 45 @staticmethod | 45 @staticmethod |
| 46 def _GetPreOrderDepGraph(deps_graph): | 46 def _GetPreOrderDepGraph(deps_graph): |
| 47 """Return packages from |deps_graph| in pre-order.""" | 47 """Return packages from |deps_graph| in pre-order.""" |
| 48 pkglist = [] | 48 pkglist = [] |
| 49 visited = set() | 49 visited = set() |
| 50 for package in deps_graph: | 50 for package in deps_graph: |
| 51 Updater._GetPreOrderDepGraphPackage(deps_graph, package, pkglist, visited) | 51 Upgrader._GetPreOrderDepGraphPackage(deps_graph, package, pkglist, |
| 52 visited) | |
| 52 return pkglist | 53 return pkglist |
| 53 | 54 |
| 54 @staticmethod | 55 @staticmethod |
| 55 def _IsStableEBuild(ebuild_path): | 56 def _IsStableEBuild(ebuild_path): |
| 56 """Returns true if |ebuild_path| is a stable ebuild, false otherwise.""" | 57 """Returns true if |ebuild_path| is a stable ebuild, false otherwise.""" |
| 57 with open(ebuild_path, 'r') as ebuild: | 58 with open(ebuild_path, 'r') as ebuild: |
| 58 for line in ebuild: | 59 for line in ebuild: |
| 59 if line.startswith('KEYWORDS='): | 60 if line.startswith('KEYWORDS='): |
| 60 # TODO(petkov): Support non-x86 targets. | 61 # TODO(petkov): Support non-x86 targets. |
| 61 return re.search(r'[ "]x86[ "]', line) | 62 return re.search(r'[ "]x86[ "]', line) |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 74 (ebuild_path, cat) = os.path.split(ebuild_path) | 75 (ebuild_path, cat) = os.path.split(ebuild_path) |
| 75 (ebuild_path, overlay) = os.path.split(ebuild_path) | 76 (ebuild_path, overlay) = os.path.split(ebuild_path) |
| 76 return (overlay, cat, pn, pv) | 77 return (overlay, cat, pn, pv) |
| 77 | 78 |
| 78 def _FindLatestVersion(self, cpv): | 79 def _FindLatestVersion(self, cpv): |
| 79 """Returns the latest cpv in |_upstream_repo| if it's newer than |cpv|.""" | 80 """Returns the latest cpv in |_upstream_repo| if it's newer than |cpv|.""" |
| 80 latest_cpv = cpv | 81 latest_cpv = cpv |
| 81 (cat, pn, version, rev) = portage.versions.catpkgsplit(cpv) | 82 (cat, pn, version, rev) = portage.versions.catpkgsplit(cpv) |
| 82 pkgpath = os.path.join(self._upstream_repo, cat, pn) | 83 pkgpath = os.path.join(self._upstream_repo, cat, pn) |
| 83 for ebuild_path in glob.glob(os.path.join(pkgpath, '%s*.ebuild' % pn)): | 84 for ebuild_path in glob.glob(os.path.join(pkgpath, '%s*.ebuild' % pn)): |
| 84 if not Updater._IsStableEBuild(ebuild_path): continue | 85 if not Upgrader._IsStableEBuild(ebuild_path): continue |
| 85 (overlay, cat, pn, pv) = self._SplitEBuildPath(ebuild_path) | 86 (overlay, cat, pn, pv) = self._SplitEBuildPath(ebuild_path) |
| 86 upstream_cpv = os.path.join(cat, pv) | 87 upstream_cpv = os.path.join(cat, pv) |
| 87 if portage.versions.pkgcmp(portage.versions.pkgsplit(upstream_cpv), | 88 if portage.versions.pkgcmp(portage.versions.pkgsplit(upstream_cpv), |
| 88 portage.versions.pkgsplit(latest_cpv)) > 0: | 89 portage.versions.pkgsplit(latest_cpv)) > 0: |
| 89 latest_cpv = upstream_cpv | 90 latest_cpv = upstream_cpv |
| 90 if latest_cpv != cpv: return latest_cpv | 91 if latest_cpv != cpv: return latest_cpv |
| 91 return None | 92 return None |
| 92 | 93 |
| 93 def _CopyUpstreamPackage(self, info): | 94 def _CopyUpstreamPackage(self, info): |
| 94 """Upgrades package described by |info| by copying from usptream. | 95 """Upgrades package described by |info| by copying from usptream. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 112 # Copy the whole package except the ebuilds. | 113 # Copy the whole package except the ebuilds. |
| 113 shutil.copytree(upstream_pkgdir, pkgdir, | 114 shutil.copytree(upstream_pkgdir, pkgdir, |
| 114 ignore=shutil.ignore_patterns('*.ebuild')) | 115 ignore=shutil.ignore_patterns('*.ebuild')) |
| 115 # Copy just the ebuild that will be used in the build. | 116 # Copy just the ebuild that will be used in the build. |
| 116 shutil.copy2(os.path.join(upstream_pkgdir, | 117 shutil.copy2(os.path.join(upstream_pkgdir, |
| 117 latest_cpv.split('/')[1] + '.ebuild'), pkgdir) | 118 latest_cpv.split('/')[1] + '.ebuild'), pkgdir) |
| 118 self._RunGit(self._stable_repo, 'add ' + catpkgname) | 119 self._RunGit(self._stable_repo, 'add ' + catpkgname) |
| 119 return True | 120 return True |
| 120 | 121 |
| 121 def _UpgradePackage(self, info): | 122 def _UpgradePackage(self, info): |
| 122 """Updates |info| with latest_cpv and performs an upgrade if necessary.""" | 123 """Updates |info| with latest_cpv and performs an upgrade if necessary.""" |
|
sosa
2011/03/30 18:38:59
Upgrade?
petkov
2011/03/30 18:49:48
It does _update_ the map structure and then "_upgr
| |
| 123 cpv = info['cpv'] | 124 cpv = info['cpv'] |
| 124 # No need to report or try to upgrade chromeos-base packages. | 125 # No need to report or try to upgrade chromeos-base packages. |
| 125 if cpv.startswith('chromeos-base/'): return | 126 if cpv.startswith('chromeos-base/'): return |
| 126 info['latest_cpv'] = self._FindLatestVersion(cpv) | 127 info['latest_cpv'] = self._FindLatestVersion(cpv) |
| 127 info['upgraded'] = self._CopyUpstreamPackage(info) | 128 info['upgraded'] = self._CopyUpstreamPackage(info) |
| 128 update = '' | 129 upgrade = '' |
| 129 if info['latest_cpv']: update = ' -> %s' % info['latest_cpv'] | 130 if info['latest_cpv']: upgrade = ' -> %s' % info['latest_cpv'] |
| 130 upgraded = '' | 131 upgraded = '' |
| 131 if info['upgraded']: upgraded = ' (UPGRADED)' | 132 if info['upgraded']: upgraded = ' (UPGRADED)' |
| 132 print '[%s] %s%s%s' % (info['overlay'], info['cpv'], update, upgraded) | 133 print '[%s] %s%s%s' % (info['overlay'], info['cpv'], upgrade, upgraded) |
| 133 | 134 |
| 134 def _UpgradePackages(self, infolist): | 135 def _UpgradePackages(self, infolist): |
| 135 """Given a list of cpv info maps, adds the latest_cpv to the infos.""" | 136 """Given a list of cpv info maps, adds the latest_cpv to the infos.""" |
| 136 dash_q = '' | 137 dash_q = '' |
| 137 if not self._options.verbose: dash_q = '-q' | 138 if not self._options.verbose: dash_q = '-q' |
| 138 try: | 139 try: |
| 139 # TODO(petkov): Currently portage's master branch is stale so we need to | 140 # TODO(petkov): Currently portage's master branch is stale so we need to |
| 140 # checkout latest upstream. At some point portage's master branch will be | 141 # checkout latest upstream. At some point portage's master branch will be |
| 141 # upstream so there will be no need to chdir/checkout. At that point we | 142 # upstream so there will be no need to chdir/checkout. At that point we |
| 142 # can also fuse this loop into the caller and avoid generating a separate | 143 # can also fuse this loop into the caller and avoid generating a separate |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 165 if not self._options.verbose: | 166 if not self._options.verbose: |
| 166 argv.append('--quiet') | 167 argv.append('--quiet') |
| 167 if self._options.rdeps: | 168 if self._options.rdeps: |
| 168 argv.append('--root-deps=rdeps') | 169 argv.append('--root-deps=rdeps') |
| 169 argv.extend(self._args) | 170 argv.extend(self._args) |
| 170 | 171 |
| 171 deps = parallel_emerge.DepGraphGenerator() | 172 deps = parallel_emerge.DepGraphGenerator() |
| 172 deps.Initialize(argv) | 173 deps.Initialize(argv) |
| 173 deps_tree, deps_info = deps.GenDependencyTree({}) | 174 deps_tree, deps_info = deps.GenDependencyTree({}) |
| 174 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info, {}) | 175 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info, {}) |
| 175 return Updater._GetPreOrderDepGraph(deps_graph) | 176 return Upgrader._GetPreOrderDepGraph(deps_graph) |
| 176 | 177 |
| 177 def _GetInfoListWithOverlays(self, cpvlist): | 178 def _GetInfoListWithOverlays(self, cpvlist): |
| 178 """Returns a list of cpv/overlay info maps corresponding to |cpvlist|.""" | 179 """Returns a list of cpv/overlay info maps corresponding to |cpvlist|.""" |
| 179 infolist = [] | 180 infolist = [] |
| 180 for cpv in cpvlist: | 181 for cpv in cpvlist: |
| 181 # TODO(petkov): Use internal portage utilities to find the overlay instead | 182 # TODO(petkov): Use internal portage utilities to find the overlay instead |
| 182 # of equery to improve performance, if possible. | 183 # of equery to improve performance, if possible. |
| 183 equery = ['equery-%s' % self._options.board, 'which', cpv] | 184 equery = ['equery-%s' % self._options.board, 'which', cpv] |
| 184 ebuild_path = cros_lib.RunCommand(equery, print_cmd=self._options.verbose, | 185 ebuild_path = cros_lib.RunCommand(equery, print_cmd=self._options.verbose, |
| 185 redirect_stdout=True).output.strip() | 186 redirect_stdout=True).output.strip() |
| 186 (overlay, cat, pn, pv) = self._SplitEBuildPath(ebuild_path) | 187 (overlay, cat, pn, pv) = self._SplitEBuildPath(ebuild_path) |
| 187 infolist.append({'cpv': cpv, 'overlay': overlay}) | 188 infolist.append({'cpv': cpv, 'overlay': overlay}) |
| 188 | 189 |
| 189 return infolist | 190 return infolist |
| 190 | 191 |
| 191 def Run(self): | 192 def Run(self): |
| 192 """Runs the updater based on the supplied options and arguments. | 193 """Runs the upgrader based on the supplied options and arguments. |
| 193 | 194 |
| 194 Currently just lists all package dependencies in pre-order along with | 195 Currently just lists all package dependencies in pre-order along with |
| 195 potential upgrades.""" | 196 potential upgrades.""" |
| 196 cpvlist = self._GetCurrentVersions() | 197 cpvlist = self._GetCurrentVersions() |
| 197 infolist = self._GetInfoListWithOverlays(cpvlist) | 198 infolist = self._GetInfoListWithOverlays(cpvlist) |
| 198 self._UpgradePackages(infolist) | 199 self._UpgradePackages(infolist) |
| 199 | 200 |
| 200 def main(): | 201 def main(): |
| 201 usage = 'Usage: %prog [options] packages...' | 202 usage = 'Usage: %prog [options] packages...' |
| 202 parser = optparse.OptionParser(usage=usage) | 203 parser = optparse.OptionParser(usage=usage) |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 223 if (options.verbose): logging.basicConfig(level=logging.DEBUG) | 224 if (options.verbose): logging.basicConfig(level=logging.DEBUG) |
| 224 | 225 |
| 225 if not options.board: | 226 if not options.board: |
| 226 parser.print_help() | 227 parser.print_help() |
| 227 cros_lib.Die('board is required') | 228 cros_lib.Die('board is required') |
| 228 | 229 |
| 229 if not args: | 230 if not args: |
| 230 parser.print_help() | 231 parser.print_help() |
| 231 cros_lib.Die('no packages provided') | 232 cros_lib.Die('no packages provided') |
| 232 | 233 |
| 233 updater = Updater(options, args) | 234 upgrader = Upgrader(options, args) |
| 234 updater.Run() | 235 upgrader.Run() |
| 235 | 236 |
| 236 | 237 |
| 237 if __name__ == '__main__': | 238 if __name__ == '__main__': |
| 238 main() | 239 main() |
| OLD | NEW |