blob: 12176381fb5ce85c9092865dd45d61fcb794a8b2 [file] [log] [blame]
Zdenek Behan508dcce2011-12-05 15:39:32 +01001#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This script manages the installed toolchains in the chroot.
7"""
8
9import copy
Zdenek Behan7e33b4e2012-03-12 17:00:56 +010010import errno
Zdenek Behan508dcce2011-12-05 15:39:32 +010011import optparse
12import os
13import sys
14
Brian Harring503f3ab2012-03-09 21:39:41 -080015from chromite.buildbot import constants
16from chromite.lib import cros_build_lib
Zdenek Behan508dcce2011-12-05 15:39:32 +010017
18# Some sanity checks first.
19if not cros_build_lib.IsInsideChroot():
20 print '%s: This needs to be run inside the chroot' % sys.argv[0]
21 sys.exit(1)
22# Only import portage after we've checked that we're inside the chroot.
23# Outside may not have portage, in which case the above may not happen.
24import portage
25
26
Zdenek Behan331f9822012-04-13 05:02:36 +020027EMERGE_CMD = os.path.join(
28 constants.SOURCE_ROOT, 'chromite/bin/parallel_emerge')
29CROS_OVERLAY_LIST_CMD = os.path.join(
30 constants.SOURCE_ROOT, 'src/platform/dev/host/cros_overlay_list')
Zdenek Behan508dcce2011-12-05 15:39:32 +010031PACKAGE_STABLE = '[stable]'
32PACKAGE_NONE = '[none]'
33SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010034
35CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
36STABLE_OVERLAY = '/usr/local/portage/stable'
37CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010038
39
40# TODO: The versions are stored here very much like in setup_board.
41# The goal for future is to differentiate these using a config file.
42# This is done essentially by messing with GetDesiredPackageVersions()
43DEFAULT_VERSION = PACKAGE_STABLE
44DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010045}
46TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010047 'host' : {
48 'binutils' : '2.21.1',
49 'gdb' : PACKAGE_NONE,
50 },
51}
52# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
53CONFIG_TARGET_SUFFIXES = {
54 'binutils' : {
55 'i686-pc-linux-gnu' : '-gold',
56 'x86_64-cros-linux-gnu' : '-gold',
57 },
58}
Zdenek Behan508dcce2011-12-05 15:39:32 +010059# Global per-run cache that will be filled ondemand in by GetPackageMap()
60# function as needed.
61target_version_map = {
62}
63
64
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010065# Global variable cache. It has to be a descendant of 'object', rather than
66# instance thereof, because attributes cannot be set on 'object' instances.
67class VariableCache(object):
68 pass
69VAR_CACHE = VariableCache()
70
71
Zdenek Behan508dcce2011-12-05 15:39:32 +010072def GetPackageMap(target):
73 """Compiles a package map for the given target from the constants.
74
75 Uses a cache in target_version_map, that is dynamically filled in as needed,
76 since here everything is static data and the structuring is for ease of
77 configurability only.
78
79 args:
80 target - the target for which to return a version map
81
82 returns a map between packages and desired versions in internal format
83 (using the PACKAGE_* constants)
84 """
85 if target in target_version_map:
86 return target_version_map[target]
87
88 # Start from copy of the global defaults.
89 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
90
Zdenek Behanf4d18a02012-03-22 15:45:05 +010091 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +010092 # prefer any specific overrides
93 if pkg in TARGET_VERSION_MAP.get(target, {}):
94 result[pkg] = TARGET_VERSION_MAP[target][pkg]
95 else:
96 # finally, if not already set, set a sane default
97 result.setdefault(pkg, DEFAULT_VERSION)
98 target_version_map[target] = result
99 return result
100
101
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100102def GetHostTuple():
103 """Returns compiler tuple for the host system.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100104
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100105 Caches the result, because the command can be fairly expensive, and never
106 changes throughout a single run.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100107 """
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100108 CACHE_ATTR = '_host_tuple'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100109
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100110 val = getattr(VAR_CACHE, CACHE_ATTR, None)
111 if val is None:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100112 val = portage.settings['CHOST']
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100113 setattr(VAR_CACHE, CACHE_ATTR, val)
114 return val
115
116
117def GetCrossdevConf(target):
118 """Returns a map of crossdev provided variables about a tuple."""
119 CACHE_ATTR = '_target_tuple_map'
120
121 val = getattr(VAR_CACHE, CACHE_ATTR, {})
122 if not target in val:
123 # Find out the crossdev tuple.
124 target_tuple = target
125 if target == 'host':
126 target_tuple = GetHostTuple()
127 # Catch output of crossdev.
128 out = cros_build_lib.RunCommand(['crossdev', '--show-target-cfg',
129 '--ex-gdb', target_tuple],
130 print_cmd=False, redirect_stdout=True).output.splitlines()
131 # List of tuples split at the first '=', converted into dict.
132 val[target] = dict([x.split('=', 1) for x in out])
133 setattr(VAR_CACHE, CACHE_ATTR, {})
134 return val[target]
135
136
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100137def GetTargetPackages(target):
138 """Returns a list of packages for a given target."""
139 conf = GetCrossdevConf(target)
140 # Undesired packages are denoted by empty ${pkg}_pn variable.
141 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
142
143
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100144# Portage helper functions:
145def GetPortagePackage(target, package):
146 """Returns a package name for the given target."""
147 conf = GetCrossdevConf(target)
148 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100149 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100150 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100151 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100152 category = conf['category']
153 # Portage package:
154 pn = conf[package + '_pn']
155 # Final package name:
156 assert(category)
157 assert(pn)
158 return '%s/%s' % (category, pn)
159
160
161def GetPortageKeyword(target):
162 """Returns a portage friendly keyword for a given target."""
163 return GetCrossdevConf(target)['arch']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100164
165
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100166def IsPackageDisabled(target, package):
167 """Returns if the given package is not used for the target."""
168 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
169
Zdenek Behan508dcce2011-12-05 15:39:32 +0100170# Tree interface functions. They help with retrieving data about the current
171# state of the tree:
172def GetAllTargets():
173 """Get the complete list of targets.
174
175 returns the list of cross targets for the current tree
176 """
Zdenek Behan331f9822012-04-13 05:02:36 +0200177 cmd = [CROS_OVERLAY_LIST_CMD, '--all_boards']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100178 overlays = cros_build_lib.RunCommand(cmd, print_cmd=False,
179 redirect_stdout=True).output.splitlines()
180 targets = set()
181 for overlay in overlays:
182 config = os.path.join(overlay, 'toolchain.conf')
183 if os.path.exists(config):
184 with open(config) as config_file:
185 lines = config_file.read().splitlines()
186 for line in lines:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100187 line = line.split('#', 1)[0]
188 targets.update(line.split())
Zdenek Behan508dcce2011-12-05 15:39:32 +0100189
190 # Remove the host target as that is not a cross-target. Replace with 'host'.
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100191 targets.discard(GetHostTuple())
Zdenek Behan508dcce2011-12-05 15:39:32 +0100192 return targets
193
194
195def GetInstalledPackageVersions(target, package):
196 """Extracts the list of current versions of a target, package pair.
197
198 args:
199 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
200
201 returns the list of versions of the package currently installed.
202 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100203 versions = []
204 # This is the package name in terms of portage.
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100205 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100206 for pkg in portage.db['/']['vartree'].dbapi.match(atom):
207 version = portage.versions.cpv_getversion(pkg)
208 versions.append(version)
209 return versions
210
211
Zdenek Behan508dcce2011-12-05 15:39:32 +0100212def GetStablePackageVersion(target, package):
213 """Extracts the current stable version for a given package.
214
215 args:
216 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
217
218 returns a string containing the latest version.
219 """
Zdenek Behan20d6ea22012-04-05 05:15:39 +0200220 def mass_portageq_splitline(entry):
221 """Splits the output of mass_best_visible into package:version tuple."""
222 # mass_best_visible returns lines of the format "package:cpv"
223 split_string = entry.split(':', 1)
224 split_string[1] = portage.versions.cpv_getversion(split_string[1])
225 return split_string
226
227 CACHE_ATTR = '_target_stable_map'
228
229 val = getattr(VAR_CACHE, CACHE_ATTR, {})
230 if not target in val:
231 keyword = GetPortageKeyword(target)
232 extra_env = {'ACCEPT_KEYWORDS' : '-* ' + keyword}
233 # Evaluate all packages for a target in one swoop, because it's much faster.
234 pkgs = [GetPortagePackage(target, p) for p in GetTargetPackages(target)]
235 cmd = ['portageq', 'mass_best_visible', '/'] + pkgs
236 cpvs = cros_build_lib.RunCommand(cmd,
237 print_cmd=False, redirect_stdout=True,
238 extra_env=extra_env).output.splitlines()
239 val[target] = dict(map(mass_portageq_splitline, cpvs))
240 setattr(VAR_CACHE, CACHE_ATTR, val)
241
242 return val[target][GetPortagePackage(target, package)]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100243
244
245def VersionListToNumeric(target, package, versions):
246 """Resolves keywords in a given version list for a particular package.
247
248 Resolving means replacing PACKAGE_STABLE with the actual number.
249
250 args:
251 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
252 versions - list of versions to resolve
253
254 returns list of purely numeric versions equivalent to argument
255 """
256 resolved = []
257 for version in versions:
258 if version == PACKAGE_STABLE:
259 resolved.append(GetStablePackageVersion(target, package))
260 elif version != PACKAGE_NONE:
261 resolved.append(version)
262 return resolved
263
264
265def GetDesiredPackageVersions(target, package):
266 """Produces the list of desired versions for each target, package pair.
267
268 The first version in the list is implicitly treated as primary, ie.
269 the version that will be initialized by crossdev and selected.
270
271 If the version is PACKAGE_STABLE, it really means the current version which
272 is emerged by using the package atom with no particular version key.
273 Since crossdev unmasks all packages by default, this will actually
274 mean 'unstable' in most cases.
275
276 args:
277 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
278
279 returns a list composed of either a version string, PACKAGE_STABLE
280 """
281 packagemap = GetPackageMap(target)
282
283 versions = []
284 if package in packagemap:
285 versions.append(packagemap[package])
286
287 return versions
288
289
290def TargetIsInitialized(target):
291 """Verifies if the given list of targets has been correctly initialized.
292
293 This determines whether we have to call crossdev while emerging
294 toolchain packages or can do it using emerge. Emerge is naturally
295 preferred, because all packages can be updated in a single pass.
296
297 args:
298 targets - list of individual cross targets which are checked
299
300 returns True if target is completely initialized
301 returns False otherwise
302 """
303 # Check if packages for the given target all have a proper version.
304 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100305 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100306 # Do we even want this package && is it initialized?
307 if not IsPackageDisabled(target, package) and \
308 not GetInstalledPackageVersions(target, package):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100309 return False
310 return True
311 except cros_build_lib.RunCommandError:
312 # Fails - The target has likely never been initialized before.
313 return False
314
315
316def RemovePackageMask(target):
317 """Removes a package.mask file for the given platform.
318
319 The pre-existing package.mask files can mess with the keywords.
320
321 args:
322 target - the target for which to remove the file
323 """
324 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100325 try:
326 os.unlink(maskfile)
327 except EnvironmentError as e:
328 if e.errno != errno.ENOENT:
329 raise
Zdenek Behan508dcce2011-12-05 15:39:32 +0100330
331
332def CreatePackageMask(target, masks):
333 """[Re]creates a package.mask file for the given platform.
334
335 args:
336 target - the given target on which to operate
337 masks - a map of package : version,
338 where version is the highest permissible version (mask >)
339 """
340 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
341 assert not os.path.exists(maskfile)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100342 cros_build_lib.SafeMakedirs(os.path.dirname(maskfile))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100343
344 with open(maskfile, 'w') as f:
345 for pkg, m in masks.items():
346 f.write('>%s-%s\n' % (pkg, m))
347
348
349def CreatePackageKeywords(target):
350 """[Re]create a package.keywords file for the platform.
351
352 This sets all package.keywords files to unmask all stable/testing packages.
353 TODO: Note that this approach should be deprecated and is only done for
354 compatibility reasons. In the future, we'd like to stop using keywords
355 altogether, and keep just stable unmasked.
356
357 args:
358 target - target for which to recreate package.keywords
359 """
360 maskfile = os.path.join('/etc/portage/package.keywords', 'cross-' + target)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100361 try:
362 os.unlink(maskfile)
363 except EnvironmentError as e:
364 if e.errno != errno.ENOENT:
365 raise
366 cros_build_lib.SafeMakedirs(os.path.dirname(maskfile))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100367
368 keyword = GetPortageKeyword(target)
369
370 with open(maskfile, 'w') as f:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100371 for pkg in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100372 if IsPackageDisabled(target, pkg):
373 continue
374 f.write('%s %s ~%s\n' %
375 (GetPortagePackage(target, pkg), keyword, keyword))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376
377
378# Main functions performing the actual update steps.
379def InitializeCrossdevTargets(targets, usepkg):
380 """Calls crossdev to initialize a cross target.
381 args:
382 targets - the list of targets to initialize using crossdev
383 usepkg - copies the commandline opts
384 """
385 print 'The following targets need to be re-initialized:'
386 print targets
Zdenek Behan508dcce2011-12-05 15:39:32 +0100387
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100388 extra_env = { 'FEATURES' : 'splitdebug' }
Zdenek Behan508dcce2011-12-05 15:39:32 +0100389 for target in targets:
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100390 cmd = ['crossdev', '--show-fail-log',
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100391 '-t', target]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392 # Pick stable by default, and override as necessary.
393 cmd.extend(['-P', '--oneshot'])
394 if usepkg:
395 cmd.extend(['-P', '--getbinpkg',
396 '-P', '--usepkgonly',
397 '--without-headers'])
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100398
399 cmd.extend(['--overlays', '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)])
400 cmd.extend(['--ov-output', CROSSDEV_OVERLAY])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100401
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100402 for pkg in GetTargetPackages(target):
403 if pkg == 'gdb':
404 # Gdb does not have selectable versions.
405 cmd.append('--ex-gdb')
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100406 continue
Zdenek Behan508dcce2011-12-05 15:39:32 +0100407 # The first of the desired versions is the "primary" one.
408 version = GetDesiredPackageVersions(target, pkg)[0]
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100409 cmd.extend(['--%s' % pkg, version])
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100410 cros_build_lib.RunCommand(cmd, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100411
412
413def UpdateTargets(targets, usepkg):
414 """Determines which packages need update/unmerge and defers to portage.
415
416 args:
417 targets - the list of targets to update
418 usepkg - copies the commandline option
419 """
420 # TODO(zbehan): This process is rather complex due to package.* handling.
421 # With some semantic changes over the original setup_board functionality,
422 # it can be considerably cleaned up.
423 mergemap = {}
424
425 # For each target, we do two things. Figure out the list of updates,
426 # and figure out the appropriate keywords/masks. Crossdev will initialize
427 # these, but they need to be regenerated on every update.
428 print 'Determining required toolchain updates...'
429 for target in targets:
430 # Record the highest needed version for each target, for masking purposes.
431 RemovePackageMask(target)
432 CreatePackageKeywords(target)
433 packagemasks = {}
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100434 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100435 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100436 if IsPackageDisabled(target, package):
437 continue
438 pkg = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100439 current = GetInstalledPackageVersions(target, package)
440 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100441 desired_num = VersionListToNumeric(target, package, desired)
442 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100443
444 # Pick the highest version for mask.
445 packagemasks[pkg] = portage.versions.best(desired_num)
446
447 CreatePackageMask(target, packagemasks)
448
449 packages = []
450 for pkg in mergemap:
451 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200452 if ver != PACKAGE_NONE:
453 # Be a little more permissive for usepkg, the binaries may not exist.
454 packages.append('%s%s-%s' % ('<=' if usepkg else '=', pkg, ver))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100455
456 if not packages:
457 print 'Nothing to update!'
458 return
459
460 print 'Updating packages:'
461 print packages
462
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100463 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100464 if usepkg:
465 cmd.extend(['--getbinpkg', '--usepkgonly'])
466
467 cmd.extend(packages)
468 cros_build_lib.RunCommand(cmd)
469
470
471def CleanTargets(targets):
472 """Unmerges old packages that are assumed unnecessary."""
473 unmergemap = {}
474 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100475 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100476 if IsPackageDisabled(target, package):
477 continue
478 pkg = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100479 current = GetInstalledPackageVersions(target, package)
480 desired = GetDesiredPackageVersions(target, package)
481 desired_num = VersionListToNumeric(target, package, desired)
482 assert set(desired).issubset(set(desired))
483 unmergemap[pkg] = set(current).difference(desired_num)
484
485 # Cleaning doesn't care about consistency and rebuilding package.* files.
486 packages = []
487 for pkg, vers in unmergemap.iteritems():
488 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
489
490 if packages:
491 print 'Cleaning packages:'
492 print packages
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100493 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100494 cmd.extend(packages)
495 cros_build_lib.RunCommand(cmd)
496 else:
497 print 'Nothing to clean!'
498
499
500def SelectActiveToolchains(targets, suffixes):
501 """Runs gcc-config and binutils-config to select the desired.
502
503 args:
504 targets - the targets to select
505 """
506 for package in ['gcc', 'binutils']:
507 for target in targets:
508 # Pick the first version in the numbered list as the selected one.
509 desired = GetDesiredPackageVersions(target, package)
510 desired_num = VersionListToNumeric(target, package, desired)
511 desired = desired_num[0]
512 # *-config does not play revisions, strip them, keep just PV.
513 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
514
515 if target == 'host':
516 # *-config is the only tool treating host identically (by tuple).
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100517 target = GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100518
519 # And finally, attach target to it.
520 desired = '%s-%s' % (target, desired)
521
522 # Target specific hacks
523 if package in suffixes:
524 if target in suffixes[package]:
525 desired += suffixes[package][target]
526
527 cmd = [ package + '-config', '-c', target ]
528 current = cros_build_lib.RunCommand(cmd, print_cmd=False,
529 redirect_stdout=True).output.splitlines()[0]
530 # Do not gcc-config when the current is live or nothing needs to be done.
531 if current != desired and current != '9999':
532 cmd = [ package + '-config', desired ]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100533 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100534
535
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100536def UpdateToolchains(usepkg, deleteold, hostonly, targets_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100537 """Performs all steps to create a synchronized toolchain enviroment.
538
539 args:
540 arguments correspond to the given commandline flags
541 """
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100542 targets = set()
543 if not hostonly:
544 # For hostonly, we can skip most of the below logic, much of which won't
545 # work on bare systems where this is useful.
546 alltargets = GetAllTargets()
547 nonexistant = []
548 if targets_wanted == set(['all']):
549 targets = set(alltargets)
550 else:
551 targets = set(targets_wanted)
552 # Verify user input.
553 for target in targets_wanted:
554 if target not in alltargets:
555 nonexistant.append(target)
556 if nonexistant:
557 raise Exception("Invalid targets: " + ','.join(nonexistant))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100558
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100559 # First check and initialize all cross targets that need to be.
560 crossdev_targets = \
561 [t for t in targets if not TargetIsInitialized(t)]
562 if crossdev_targets:
563 InitializeCrossdevTargets(crossdev_targets, usepkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100565 # We want host updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100566 targets.add('host')
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100567
568 # Now update all packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100569 UpdateTargets(targets, usepkg)
570 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
571
572 if deleteold:
573 CleanTargets(targets)
574
575
Brian Harring30675052012-02-29 12:18:22 -0800576def main(argv):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100577 usage = """usage: %prog [options]
578
579 The script installs and updates the toolchains in your chroot.
580 """
581 parser = optparse.OptionParser(usage)
582 parser.add_option('-u', '--nousepkg',
583 action='store_false', dest='usepkg', default=True,
584 help=('Use prebuilt packages if possible.'))
585 parser.add_option('-d', '--deleteold',
586 action='store_true', dest='deleteold', default=False,
587 help=('Unmerge deprecated packages.'))
588 parser.add_option('-t', '--targets',
589 dest='targets', default='all',
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100590 help=('Comma separated list of tuples. '
591 'Special keyword \'host\' is allowed. Default: all.'))
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100592 parser.add_option('', '--hostonly',
593 dest='hostonly', default=False, action='store_true',
594 help=('Only setup the host toolchain. '
595 'Useful for bootstrapping chroot.'))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100596
Brian Harring30675052012-02-29 12:18:22 -0800597 (options, _remaining_arguments) = parser.parse_args(argv)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100598
Mike Frysingerb9a28fe2012-03-21 11:35:42 -0400599 # This has to be always ran as root.
600 if not os.getuid() == 0:
601 print "%s: This script must be run as root!" % sys.argv[0]
602 sys.exit(1)
603
Zdenek Behan508dcce2011-12-05 15:39:32 +0100604 targets = set(options.targets.split(','))
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100605 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly, targets)