blob: 22f8703e270187eb55f39b126f916ba3fb5352e1 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Install/copy the image to the device."""
from __future__ import print_function
import sys
from chromite.cli import command
from chromite.cli import flash
from chromite.cli.cros import cros_chrome_sdk
from chromite.lib import commandline
from chromite.lib import cros_logging as logging
from chromite.lib import dev_server_wrapper
from chromite.lib import path_util
assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
@command.CommandDecorator('flash')
class FlashCommand(command.CliCommand):
"""Update the device with an image.
This command updates the device with the image
(ssh://<hostname>:{port}, copies an image to a removable device
(usb://<device_path>), or copies a xbuddy path to a local
file path with (file://file_path).
For device update, it assumes that device is able to accept ssh
connections.
For rootfs partition update, this command may launch a devserver to
generate payloads. As a side effect, it may create symlinks in
static_dir/others used by the devserver.
"""
EPILOG = """
To update/image the device with the latest locally built image:
cros flash device latest
cros flash device
To update/image the device with an xbuddy path:
cros flash device xbuddy://{local, remote}/<board>/<version>[/<image_type>]
Common xbuddy version aliases are 'latest' (alias for 'latest-stable')
latest-{dev, beta, stable, canary}, and latest-official.
The optional image_type can be one of 'test' (the default), 'dev', 'base',
'recovery', or 'signed'.
To update/image the device with a local image path:
cros flash device /path/to/image.bin
Examples:
cros flash 192.168.1.7 xbuddy://remote/amd64-generic/latest-canary
cros flash 192.168.1.7 xbuddy://remote/amd64-generic-full/R84-13039.0.0
cros flash usb:// xbuddy://remote/kevin
cros flash usb:///dev/sde kevin/latest
cros flash file:///~/images kevin
# For a recovery image
cros flash usb:// xbuddy://remote/link/latest-stable/recovery
# For a signed image
cros flash usb:// xbuddy://remote/eve/latest-stable/signed
For more information and known problems/fixes, please see:
https://dev.chromium.org/chromium-os/build/cros-flash
"""
# Override base class property to use cache related commandline options.
use_caching_options = True
@classmethod
def AddParser(cls, parser):
"""Add parser arguments."""
super(FlashCommand, cls).AddParser(parser)
cls.AddDeviceArgument(
parser,
positional=True,
schemes=[
commandline.DEVICE_SCHEME_FILE,
commandline.DEVICE_SCHEME_SSH,
commandline.DEVICE_SCHEME_USB,
])
parser.add_argument(
'image',
nargs='?',
help='A local path or an xbuddy path: '
'xbuddy://{local|remote}/board/version/{image_type} image_type '
"can be: 'test', 'dev', 'base', 'recovery', or 'signed'. Note any "
'strings that do not map to a real file path will be converted to an '
'xbuddy path i.e., latest, will map to xbuddy://latest.')
parser.add_argument(
'--clear-cache', default=False, action='store_true',
help='Clear the devserver static directory. This deletes all the '
'downloaded images and payloads, and also payloads generated by '
'the devserver. Default is not to clear.')
update = parser.add_argument_group('Advanced device update options')
update.add_argument(
'--board', help='The board to use. By default it is '
'automatically detected. You can override the detected board with '
'this option.')
update.add_argument(
'--yes', default=False, action='store_true',
help='Answer yes to any prompt. Use with caution.')
update.add_argument(
'--force', action='store_true',
help='Ignore sanity checks, just do it. Implies --yes.')
update.add_argument(
'--no-reboot', action='store_false', dest='reboot', default=True,
help='Do not reboot after update. Default is always reboot.')
update.add_argument(
'--no-wipe', action='store_false', dest='wipe', default=True,
help='Do not wipe the temporary working directory. Default '
'is always wipe.')
update.add_argument(
'--no-stateful-update', action='store_false', dest='stateful_update',
help='Do not update the stateful partition on the device. '
'Default is always update.')
update.add_argument(
'--no-rootfs-update', action='store_false', dest='rootfs_update',
help='Do not update the rootfs partition on the device. '
'Default is always update.')
update.add_argument(
'--src-image-to-delta', type='path',
help='Local path to an image to be used as the base to generate '
'delta payloads.')
update.add_argument(
'--clobber-stateful', action='store_true', default=False,
help='Clobber stateful partition when performing update. '
'Recommend to set clear-tpm-owner to true when this option is true.')
update.add_argument(
'--clear-tpm-owner', action='store_true', default=False,
help='Clear the TPM owner on reboot.')
update.add_argument(
'--restore-stateful', action='store_false', dest='rootfs_update',
help='Restore the stateful partition. Same as --no-rootfs-update.')
update.add_argument(
'--private-key', type='path', default=None,
help='SSH identify file (private key).')
update.add_argument(
'--no-ping', dest='ping', action='store_false', default=True,
help='Do not ping the device before attempting to connect to it.')
update.add_argument(
'--disable-rootfs-verification', default=False, action='store_true',
help='Disable rootfs verification after update is completed.')
update.add_argument(
'--send-payload-in-parallel', default=False, action='store_true',
help=('To speed up transfer payload files for long haul, chop '
'payload in chunks and transfer them in parallel.'))
update.add_argument(
'--no-copy-payloads-to-device', dest='copy_payloads_to_device',
action='store_false', default=True,
help=('Do not copy the update payloads to the device. For now this '
'only works for the stateful payload.'))
usb = parser.add_argument_group('USB specific options')
usb.add_argument(
'--install', default=False, action='store_true',
help='Install to the USB device using the base disk layout.')
def _GetDefaultVersion(self):
"""Get default full SDK version.
For non-chrome, use 'latest'. For chrome, look up the
full version in the misc cache.
"""
if path_util.DetermineCheckout().type != path_util.CHECKOUT_TYPE_GCLIENT:
return 'latest'
board = self.options.board or flash.GetDefaultBoard()
if not board:
raise flash.FlashError('Must specify board.')
full_version = cros_chrome_sdk.SDKFetcher.GetCachedFullVersion(
self.options.cache_dir or path_util.GetCacheDir(), board) or 'latest'
logging.notice('CrOS SDK version: %s', full_version)
return full_version
def Run(self):
"""Perform the cros flash command."""
self.options.Freeze()
try:
flash.Flash(
self.options.device,
self.options.image,
board=self.options.board,
version=self._GetDefaultVersion(),
install=self.options.install,
src_image_to_delta=self.options.src_image_to_delta,
rootfs_update=self.options.rootfs_update,
stateful_update=self.options.stateful_update,
clobber_stateful=self.options.clobber_stateful,
clear_tpm_owner=self.options.clear_tpm_owner,
reboot=self.options.reboot,
wipe=self.options.wipe,
ssh_private_key=self.options.private_key,
ping=self.options.ping,
disable_rootfs_verification=self.options.disable_rootfs_verification,
clear_cache=self.options.clear_cache,
yes=self.options.yes,
force=self.options.force,
debug=self.options.debug,
send_payload_in_parallel=self.options.send_payload_in_parallel,
copy_payloads_to_device=self.options.copy_payloads_to_device)
logging.notice('cros flash completed successfully.')
except dev_server_wrapper.ImagePathError:
logging.error('To get the latest remote image, please run:\n'
'cros flash --board=%s %s remote/latest',
self.options.board, self.options.device.raw)
raise