blob: a9f1eac44c49d3839964d053542e7f7dd45d9b13 [file] [log] [blame]
Ryan Cui3045c5d2012-07-13 18:00:33 -07001#!/usr/bin/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
Ryan Cuia56a71e2012-10-18 18:40:35 -07006
7"""
8Script that deploys a Chrome build to a device.
9
10The script supports deploying Chrome from these sources:
11
121. A local build output directory, such as chromium/src/out/[Debug|Release].
132. A Chrome tarball uploaded by a trybot/official-builder to GoogleStorage.
143. A Chrome tarball existing locally.
15
16The script copies the necessary contents of the source location (tarball or
17build directory) and rsyncs the contents of the staging directory onto your
18device's rootfs.
19"""
Ryan Cui3045c5d2012-07-13 18:00:33 -070020
Ryan Cui3045c5d2012-07-13 18:00:33 -070021import logging
David James88e6f032013-03-02 08:13:20 -080022import multiprocessing
Ryan Cui3045c5d2012-07-13 18:00:33 -070023import os
Ryan Cuia56a71e2012-10-18 18:40:35 -070024import optparse
Ryan Cui3045c5d2012-07-13 18:00:33 -070025import time
Ryan Cui3045c5d2012-07-13 18:00:33 -070026
Ryan Cuia56a71e2012-10-18 18:40:35 -070027
David James629febb2012-11-25 13:07:34 -080028from chromite.buildbot import constants
David James88e6f032013-03-02 08:13:20 -080029from chromite.buildbot import cbuildbot_results as results_lib
Ryan Cui686ec052013-02-12 16:39:41 -080030from chromite.cros.commands import cros_chrome_sdk
Ryan Cuia56a71e2012-10-18 18:40:35 -070031from chromite.lib import chrome_util
Ryan Cui3045c5d2012-07-13 18:00:33 -070032from chromite.lib import cros_build_lib
Ryan Cuie535b172012-10-19 18:25:03 -070033from chromite.lib import commandline
Ryan Cui777ff422012-12-07 13:12:54 -080034from chromite.lib import gs
Ryan Cui3045c5d2012-07-13 18:00:33 -070035from chromite.lib import osutils
David James88e6f032013-03-02 08:13:20 -080036from chromite.lib import parallel
Ryan Cui3045c5d2012-07-13 18:00:33 -070037from chromite.lib import remote_access as remote
Ryan Cui3045c5d2012-07-13 18:00:33 -070038
39
Ryan Cuia56a71e2012-10-18 18:40:35 -070040_USAGE = "deploy_chrome [--]\n\n %s" % __doc__
41
Ryan Cui3045c5d2012-07-13 18:00:33 -070042KERNEL_A_PARTITION = 2
43KERNEL_B_PARTITION = 4
44
45KILL_PROC_MAX_WAIT = 10
46POST_KILL_WAIT = 2
47
Ryan Cuie535b172012-10-19 18:25:03 -070048MOUNT_RW_COMMAND = 'mount -o remount,rw /'
David James88e6f032013-03-02 08:13:20 -080049LSOF_COMMAND = 'lsof /opt/google/chrome/chrome'
Ryan Cui3045c5d2012-07-13 18:00:33 -070050
David James2cb34002013-03-01 18:42:40 -080051_CHROME_DIR = '/opt/google/chrome'
52
Ryan Cui3045c5d2012-07-13 18:00:33 -070053
Ryan Cui3045c5d2012-07-13 18:00:33 -070054def _UrlBaseName(url):
55 """Return the last component of the URL."""
56 return url.rstrip('/').rpartition('/')[-1]
57
58
David James88e6f032013-03-02 08:13:20 -080059class DeployFailure(results_lib.StepFailure):
60 """Raised whenever the deploy fails."""
61
62
Ryan Cui3045c5d2012-07-13 18:00:33 -070063class DeployChrome(object):
64 """Wraps the core deployment functionality."""
Ryan Cuia56a71e2012-10-18 18:40:35 -070065 def __init__(self, options, tempdir, staging_dir):
Ryan Cuie535b172012-10-19 18:25:03 -070066 """Initialize the class.
67
68 Arguments:
69 options: Optparse result structure.
70 tempdir: Scratch space for the class. Caller has responsibility to clean
71 it up.
Ryan Cuie535b172012-10-19 18:25:03 -070072 """
Ryan Cui3045c5d2012-07-13 18:00:33 -070073 self.tempdir = tempdir
74 self.options = options
Ryan Cuia56a71e2012-10-18 18:40:35 -070075 self.staging_dir = staging_dir
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070076 self.host = remote.RemoteAccess(options.to, tempdir, port=options.port)
David James88e6f032013-03-02 08:13:20 -080077 self._rootfs_is_still_readonly = multiprocessing.Event()
Ryan Cui3045c5d2012-07-13 18:00:33 -070078
Ryan Cui3045c5d2012-07-13 18:00:33 -070079 def _ChromeFileInUse(self):
David James88e6f032013-03-02 08:13:20 -080080 result = self.host.RemoteSh(LSOF_COMMAND, error_code_ok=True)
Ryan Cui3045c5d2012-07-13 18:00:33 -070081 return result.returncode == 0
82
83 def _DisableRootfsVerification(self):
84 if not self.options.force:
85 logging.error('Detected that the device has rootfs verification enabled.')
86 logging.info('This script can automatically remove the rootfs '
87 'verification, which requires that it reboot the device.')
88 logging.info('Make sure the device is in developer mode!')
89 logging.info('Skip this prompt by specifying --force.')
Brian Harring521e7242012-11-01 16:57:42 -070090 if not cros_build_lib.BooleanPrompt('Remove roots verification?', False):
David James88e6f032013-03-02 08:13:20 -080091 # Since we stopped Chrome earlier, it's good form to start it up again.
92 if self.options.startui:
93 logging.info('Starting Chrome...')
94 self.host.RemoteSh('start ui')
95 raise DeployFailure('Need rootfs verification to be disabled. '
96 'Aborting.')
Ryan Cui3045c5d2012-07-13 18:00:33 -070097
98 logging.info('Removing rootfs verification from %s', self.options.to)
99 # Running in VM's cause make_dev_ssd's firmware sanity checks to fail.
100 # Use --force to bypass the checks.
101 cmd = ('/usr/share/vboot/bin/make_dev_ssd.sh --partitions %d '
102 '--remove_rootfs_verification --force')
103 for partition in (KERNEL_A_PARTITION, KERNEL_B_PARTITION):
104 self.host.RemoteSh(cmd % partition, error_code_ok=True)
105
106 # A reboot in developer mode takes a while (and has delays), so the user
107 # will have time to read and act on the USB boot instructions below.
108 logging.info('Please remember to press Ctrl-U if you are booting from USB.')
109 self.host.RemoteReboot()
110
David James88e6f032013-03-02 08:13:20 -0800111 # Now that the machine has been rebooted, we need to kill Chrome again.
112 self._KillProcsIfNeeded()
113
114 # Make sure the rootfs is writable now.
115 self._MountRootfsAsWritable(error_code_ok=False)
Ryan Cui3045c5d2012-07-13 18:00:33 -0700116
117 def _CheckUiJobStarted(self):
118 # status output is in the format:
119 # <job_name> <status> ['process' <pid>].
120 # <status> is in the format <goal>/<state>.
Ryan Cuif2d1a582013-02-19 14:08:13 -0800121 try:
122 result = self.host.RemoteSh('status ui')
123 except cros_build_lib.RunCommandError as e:
124 if 'Unknown job' in e.result.error:
125 return False
126 else:
127 raise e
128
Ryan Cui3045c5d2012-07-13 18:00:33 -0700129 return result.output.split()[1].split('/')[0] == 'start'
130
131 def _KillProcsIfNeeded(self):
132 if self._CheckUiJobStarted():
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800133 logging.info('Shutting down Chrome...')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700134 self.host.RemoteSh('stop ui')
135
136 # Developers sometimes run session_manager manually, in which case we'll
137 # need to help shut the chrome processes down.
138 try:
139 with cros_build_lib.SubCommandTimeout(KILL_PROC_MAX_WAIT):
140 while self._ChromeFileInUse():
141 logging.warning('The chrome binary on the device is in use.')
142 logging.warning('Killing chrome and session_manager processes...\n')
143
144 self.host.RemoteSh("pkill 'chrome|session_manager'",
145 error_code_ok=True)
146 # Wait for processes to actually terminate
147 time.sleep(POST_KILL_WAIT)
148 logging.info('Rechecking the chrome binary...')
149 except cros_build_lib.TimeoutError:
David James88e6f032013-03-02 08:13:20 -0800150 msg = ('Could not kill processes after %s seconds. Please exit any '
151 'running chrome processes and try again.' % KILL_PROC_MAX_WAIT)
152 raise DeployFailure(msg)
Ryan Cui3045c5d2012-07-13 18:00:33 -0700153
David James88e6f032013-03-02 08:13:20 -0800154 def _MountRootfsAsWritable(self, error_code_ok=True):
155 """Mount the rootfs as writable.
Ryan Cui3045c5d2012-07-13 18:00:33 -0700156
David James88e6f032013-03-02 08:13:20 -0800157 If the command fails, and error_code_ok is True, then this function sets
158 self._rootfs_is_still_readonly.
Ryan Cui3045c5d2012-07-13 18:00:33 -0700159
David James88e6f032013-03-02 08:13:20 -0800160 Arguments:
161 error_code_ok: See remote.RemoteAccess.RemoteSh for details.
162 """
163 result = self.host.RemoteSh(MOUNT_RW_COMMAND, error_code_ok=error_code_ok)
164 if result.returncode:
165 self._rootfs_is_still_readonly.set()
Ryan Cui3045c5d2012-07-13 18:00:33 -0700166
167 def _Deploy(self):
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800168 logging.info('Copying Chrome to device...')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700169 # Show the output (status) for this command.
David James2cb34002013-03-01 18:42:40 -0800170 self.host.Rsync('%s/' % os.path.abspath(self.staging_dir), _CHROME_DIR,
David Jamesa6e08892013-03-01 13:34:11 -0800171 inplace=True, debug_level=logging.INFO,
172 verbose=self.options.verbose)
Ryan Cui82a1f2d2013-02-22 17:34:23 -0800173 if self.options.startui:
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800174 logging.info('Starting Chrome...')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700175 self.host.RemoteSh('start ui')
176
David James88e6f032013-03-02 08:13:20 -0800177 def _CheckConnection(self):
Ryan Cui3045c5d2012-07-13 18:00:33 -0700178 try:
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800179 logging.info('Testing connection to the device...')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700180 self.host.RemoteSh('true')
David James88e6f032013-03-02 08:13:20 -0800181 except cros_build_lib.RunCommandError as ex:
Ryan Cui3045c5d2012-07-13 18:00:33 -0700182 logging.error('Error connecting to the test device.')
David James88e6f032013-03-02 08:13:20 -0800183 raise DeployFailure(ex)
Ryan Cui3045c5d2012-07-13 18:00:33 -0700184
David James88e6f032013-03-02 08:13:20 -0800185 def _PrepareStagingDir(self):
186 _PrepareStagingDir(self.options, self.tempdir, self.staging_dir)
187
188 def Perform(self):
189 # If requested, just do the staging step.
190 if self.options.staging_only:
191 self._PrepareStagingDir()
192 return 0
193
194 # Run setup steps in parallel. If any step fails, RunParallelSteps will
195 # print the error message and squelch any further output, making the
196 # output look nice (though hiding some information).
197 steps = [self._PrepareStagingDir, self._CheckConnection,
198 self._KillProcsIfNeeded, self._MountRootfsAsWritable]
199 parallel.RunParallelSteps(steps, hide_output_after_errors=True)
200
201 # If we failed to mark the rootfs as writable, try disabling rootfs
202 # verification.
203 if self._rootfs_is_still_readonly.is_set():
204 self._DisableRootfsVerification()
205
206 # Actually deploy Chrome to the device.
Ryan Cui3045c5d2012-07-13 18:00:33 -0700207 self._Deploy()
208
209
Ryan Cuia56a71e2012-10-18 18:40:35 -0700210def ValidateGypDefines(_option, _opt, value):
211 """Convert GYP_DEFINES-formatted string to dictionary."""
212 return chrome_util.ProcessGypDefines(value)
213
214
215class CustomOption(commandline.Option):
216 """Subclass Option class to implement path evaluation."""
217 TYPES = commandline.Option.TYPES + ('gyp_defines',)
218 TYPE_CHECKER = commandline.Option.TYPE_CHECKER.copy()
219 TYPE_CHECKER['gyp_defines'] = ValidateGypDefines
220
221
Ryan Cuie535b172012-10-19 18:25:03 -0700222def _CreateParser():
223 """Create our custom parser."""
Ryan Cui504db722013-01-22 11:48:01 -0800224 parser = commandline.OptionParser(usage=_USAGE, option_class=CustomOption,
225 caching=True)
Ryan Cui3045c5d2012-07-13 18:00:33 -0700226
Ryan Cuia56a71e2012-10-18 18:40:35 -0700227 # TODO(rcui): Have this use the UI-V2 format of having source and target
228 # device be specified as positional arguments.
Ryan Cui3045c5d2012-07-13 18:00:33 -0700229 parser.add_option('--force', action='store_true', default=False,
Ryan Cui686ec052013-02-12 16:39:41 -0800230 help='Skip all prompts (i.e., for disabling of rootfs '
231 'verification). This may result in the target '
232 'machine being rebooted.')
Ryan Cuia0215a72013-02-14 16:20:45 -0800233 sdk_board_env = os.environ.get(cros_chrome_sdk.SDKFetcher.SDK_BOARD_ENV)
234 parser.add_option('--board', default=sdk_board_env,
Ryan Cui686ec052013-02-12 16:39:41 -0800235 help="The board the Chrome build is targeted for. When in "
236 "a 'cros chrome-sdk' shell, defaults to the SDK "
237 "board.")
Ryan Cuia56a71e2012-10-18 18:40:35 -0700238 parser.add_option('--build-dir', type='path',
Ryan Cui686ec052013-02-12 16:39:41 -0800239 help='The directory with Chrome build artifacts to deploy '
240 'from. Typically of format <chrome_root>/out/Debug. '
241 'When this option is used, the GYP_DEFINES '
242 'environment variable must be set.')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700243 parser.add_option('-g', '--gs-path', type='gs_path',
Ryan Cui686ec052013-02-12 16:39:41 -0800244 help='GS path that contains the chrome to deploy.')
Ryan Cui82a1f2d2013-02-22 17:34:23 -0800245 parser.add_option('--nostartui', action='store_false', dest='startui',
246 default=True,
247 help="Don't restart the ui daemon after deployment.")
Ryan Cui3045c5d2012-07-13 18:00:33 -0700248 parser.add_option('-p', '--port', type=int, default=remote.DEFAULT_SSH_PORT,
Ryan Cui686ec052013-02-12 16:39:41 -0800249 help='Port of the target device to connect to.')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700250 parser.add_option('-t', '--to',
Ryan Cui686ec052013-02-12 16:39:41 -0800251 help='The IP address of the CrOS device to deploy to.')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700252 parser.add_option('-v', '--verbose', action='store_true', default=False,
Ryan Cui686ec052013-02-12 16:39:41 -0800253 help='Show more debug output.')
Ryan Cuia56a71e2012-10-18 18:40:35 -0700254
255 group = optparse.OptionGroup(parser, 'Advanced Options')
256 group.add_option('-l', '--local-pkg-path', type='path',
Ryan Cui686ec052013-02-12 16:39:41 -0800257 help='Path to local chrome prebuilt package to deploy.')
David Jamesa6e08892013-03-01 13:34:11 -0800258 group.add_option('--sloppy', action='store_true', default=False,
259 help='Ignore when mandatory artifacts are missing.')
Ryan Cuief91e702013-02-04 12:06:36 -0800260 group.add_option('--strict', action='store_true', default=False,
Ryan Cui686ec052013-02-12 16:39:41 -0800261 help='Stage artifacts based on the GYP_DEFINES environment '
David Jamesa6e08892013-03-01 13:34:11 -0800262 'variable and --staging-flags, if set. Enforce that '
263 'all optional artifacts are deployed.')
Ryan Cuief91e702013-02-04 12:06:36 -0800264 group.add_option('--staging-flags', default=None, type='gyp_defines',
David Jamesa6e08892013-03-01 13:34:11 -0800265 help='Extra flags to control staging. Valid flags are - %s'
Ryan Cui686ec052013-02-12 16:39:41 -0800266 % ', '.join(chrome_util.STAGING_FLAGS))
Ryan Cuief91e702013-02-04 12:06:36 -0800267
Ryan Cuia56a71e2012-10-18 18:40:35 -0700268 parser.add_option_group(group)
269
270 # Path of an empty directory to stage chrome artifacts to. Defaults to a
271 # temporary directory that is removed when the script finishes. If the path
272 # is specified, then it will not be removed.
273 parser.add_option('--staging-dir', type='path', default=None,
274 help=optparse.SUPPRESS_HELP)
275 # Only prepare the staging directory, and skip deploying to the device.
276 parser.add_option('--staging-only', action='store_true', default=False,
277 help=optparse.SUPPRESS_HELP)
278 # GYP_DEFINES that Chrome was built with. Influences which files are staged
279 # when --build-dir is set. Defaults to reading from the GYP_DEFINES
280 # enviroment variable.
Ryan Cuief91e702013-02-04 12:06:36 -0800281 parser.add_option('--gyp-defines', default=None, type='gyp_defines',
Ryan Cuia56a71e2012-10-18 18:40:35 -0700282 help=optparse.SUPPRESS_HELP)
Ryan Cuie535b172012-10-19 18:25:03 -0700283 return parser
Ryan Cui3045c5d2012-07-13 18:00:33 -0700284
Ryan Cuie535b172012-10-19 18:25:03 -0700285
286def _ParseCommandLine(argv):
287 """Parse args, and run environment-independent checks."""
288 parser = _CreateParser()
Ryan Cui3045c5d2012-07-13 18:00:33 -0700289 (options, args) = parser.parse_args(argv)
290
Ryan Cuia56a71e2012-10-18 18:40:35 -0700291 if not any([options.gs_path, options.local_pkg_path, options.build_dir]):
292 parser.error('Need to specify either --gs-path, --local-pkg-path, or '
Ryan Cuief91e702013-02-04 12:06:36 -0800293 '--build-dir')
Ryan Cuia56a71e2012-10-18 18:40:35 -0700294 if options.build_dir and any([options.gs_path, options.local_pkg_path]):
295 parser.error('Cannot specify both --build_dir and '
296 '--gs-path/--local-pkg-patch')
Ryan Cui686ec052013-02-12 16:39:41 -0800297 if options.build_dir and not options.board:
298 parser.error('--board is required when --build-dir is specified.')
Ryan Cuia56a71e2012-10-18 18:40:35 -0700299 if options.gs_path and options.local_pkg_path:
300 parser.error('Cannot specify both --gs-path and --local-pkg-path')
301 if not (options.staging_only or options.to):
Ryan Cui3045c5d2012-07-13 18:00:33 -0700302 parser.error('Need to specify --to')
Ryan Cuief91e702013-02-04 12:06:36 -0800303 if (options.strict or options.staging_flags) and not options.build_dir:
304 parser.error('--strict and --staging-flags require --build-dir to be '
305 'set.')
306 if options.staging_flags and not options.strict:
David Jamesa6e08892013-03-01 13:34:11 -0800307 parser.error('--staging-flags requires --strict to be set.')
308 if options.sloppy and options.strict:
309 parser.error('Cannot specify both --strict and --sloppy.')
Ryan Cui3045c5d2012-07-13 18:00:33 -0700310 return options, args
311
312
Ryan Cuie535b172012-10-19 18:25:03 -0700313def _PostParseCheck(options, _args):
Ryan Cui3045c5d2012-07-13 18:00:33 -0700314 """Perform some usage validation (after we've parsed the arguments
315
316 Args:
317 options/args: The options/args object returned by optparse
318 """
Ryan Cuia56a71e2012-10-18 18:40:35 -0700319 if options.local_pkg_path and not os.path.isfile(options.local_pkg_path):
320 cros_build_lib.Die('%s is not a file.', options.local_pkg_path)
321
Ryan Cui686ec052013-02-12 16:39:41 -0800322 if options.strict and not options.gyp_defines:
Ryan Cuia56a71e2012-10-18 18:40:35 -0700323 gyp_env = os.getenv('GYP_DEFINES', None)
324 if gyp_env is not None:
325 options.gyp_defines = chrome_util.ProcessGypDefines(gyp_env)
326 logging.info('GYP_DEFINES taken from environment: %s',
327 options.gyp_defines)
328 else:
Ryan Cui686ec052013-02-12 16:39:41 -0800329 cros_build_lib.Die('When --strict is set, the GYP_DEFINES environment '
330 'variable must be set.')
Ryan Cuia56a71e2012-10-18 18:40:35 -0700331
332
Ryan Cui504db722013-01-22 11:48:01 -0800333def _FetchChromePackage(cache_dir, tempdir, gs_path):
Ryan Cuia56a71e2012-10-18 18:40:35 -0700334 """Get the chrome prebuilt tarball from GS.
335
336 Returns: Path to the fetched chrome tarball.
337 """
Ryan Cui4c2d42c2013-02-08 16:22:26 -0800338 gs_ctx = gs.GSContext.Cached(cache_dir, init_boto=True)
339 files = gs_ctx.LS(gs_path).output.splitlines()
340 files = [found for found in files if
341 _UrlBaseName(found).startswith('%s-' % constants.CHROME_PN)]
342 if not files:
343 raise Exception('No chrome package found at %s' % gs_path)
344 elif len(files) > 1:
345 # - Users should provide us with a direct link to either a stripped or
346 # unstripped chrome package.
347 # - In the case of being provided with an archive directory, where both
348 # stripped and unstripped chrome available, use the stripped chrome
349 # package.
350 # - Stripped chrome pkg is chromeos-chrome-<version>.tar.gz
351 # - Unstripped chrome pkg is chromeos-chrome-<version>-unstripped.tar.gz.
352 files = [f for f in files if not 'unstripped' in f]
353 assert len(files) == 1
354 logging.warning('Multiple chrome packages found. Using %s', files[0])
Ryan Cui777ff422012-12-07 13:12:54 -0800355
Ryan Cui4c2d42c2013-02-08 16:22:26 -0800356 filename = _UrlBaseName(files[0])
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800357 logging.info('Fetching %s...', filename)
Ryan Cui4c2d42c2013-02-08 16:22:26 -0800358 gs_ctx.Copy(files[0], tempdir, print_cmd=False)
359 chrome_path = os.path.join(tempdir, filename)
360 assert os.path.exists(chrome_path)
361 return chrome_path
Ryan Cuia56a71e2012-10-18 18:40:35 -0700362
363
364def _PrepareStagingDir(options, tempdir, staging_dir):
365 """Place the necessary files in the staging directory.
366
367 The staging directory is the directory used to rsync the build artifacts over
368 to the device. Only the necessary Chrome build artifacts are put into the
369 staging directory.
370 """
371 if options.build_dir:
Ryan Cuia0215a72013-02-14 16:20:45 -0800372 sdk = cros_chrome_sdk.SDKFetcher(options.cache_dir, options.board)
Ryan Cui686ec052013-02-12 16:39:41 -0800373 components = (sdk.TARGET_TOOLCHAIN_KEY, constants.CHROME_ENV_TAR)
374 with sdk.Prepare(components=components) as ctx:
375 env_path = os.path.join(ctx.key_map[constants.CHROME_ENV_TAR].path,
376 constants.CHROME_ENV_FILE)
377 strip_bin = osutils.SourceEnvironment(env_path, ['STRIP'])['STRIP']
378 strip_bin = os.path.join(ctx.key_map[sdk.TARGET_TOOLCHAIN_KEY].path,
379 'bin', os.path.basename(strip_bin))
380 chrome_util.StageChromeFromBuildDir(
381 staging_dir, options.build_dir, strip_bin, strict=options.strict,
David Jamesa6e08892013-03-01 13:34:11 -0800382 sloppy=options.sloppy, gyp_defines=options.gyp_defines,
383 staging_flags=options.staging_flags)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700384 else:
385 pkg_path = options.local_pkg_path
386 if options.gs_path:
Ryan Cui504db722013-01-22 11:48:01 -0800387 pkg_path = _FetchChromePackage(options.cache_dir, tempdir,
388 options.gs_path)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700389
390 assert pkg_path
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800391 logging.info('Extracting %s...', pkg_path)
Ryan Cuif2d1a582013-02-19 14:08:13 -0800392 osutils.SafeMakedirs(staging_dir)
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800393 cros_build_lib.DebugRunCommand(['tar', '-xpf', pkg_path], cwd=staging_dir)
Ryan Cui3045c5d2012-07-13 18:00:33 -0700394
395
396def main(argv):
397 options, args = _ParseCommandLine(argv)
398 _PostParseCheck(options, args)
399
400 # Set cros_build_lib debug level to hide RunCommand spew.
401 if options.verbose:
Ryan Cuia56a71e2012-10-18 18:40:35 -0700402 logging.getLogger().setLevel(logging.DEBUG)
Ryan Cui3045c5d2012-07-13 18:00:33 -0700403 else:
Ryan Cui4d6b0db2013-02-28 15:13:24 -0800404 logging.getLogger().setLevel(logging.INFO)
Ryan Cui3045c5d2012-07-13 18:00:33 -0700405
Ryan Cuif2d1a582013-02-19 14:08:13 -0800406 with osutils.TempDirContextManager() as tempdir:
407 staging_dir = options.staging_dir
408 if not staging_dir:
409 staging_dir = os.path.join(tempdir, 'chrome')
Ryan Cuia56a71e2012-10-18 18:40:35 -0700410
Ryan Cuif2d1a582013-02-19 14:08:13 -0800411 deploy = DeployChrome(options, tempdir, staging_dir)
David James88e6f032013-03-02 08:13:20 -0800412 try:
413 deploy.Perform()
414 except results_lib.StepFailure as ex:
415 raise SystemExit(str(ex).strip())