blob: c0f8bcb5ecde2f1fdaa3f31f19e1ed2f296853d6 [file] [log] [blame]
David Pursellf1d16a62015-03-25 13:31:04 -07001# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Install/copy the image to the device."""
6
7from __future__ import print_function
8
David Pursellf1d16a62015-03-25 13:31:04 -07009import os
Ralph Nathan9b997232015-05-15 13:13:12 -070010import re
David Pursellf1d16a62015-03-25 13:31:04 -070011import shutil
12import tempfile
David Pursellf1d16a62015-03-25 13:31:04 -070013
Aviv Keshetb7519e12016-10-04 00:50:00 -070014from chromite.lib import constants
xixuane851dfb2016-05-02 18:02:37 -070015from chromite.lib import auto_updater
David Pursellf1d16a62015-03-25 13:31:04 -070016from chromite.lib import commandline
17from chromite.lib import cros_build_lib
18from chromite.lib import cros_logging as logging
19from chromite.lib import dev_server_wrapper as ds_wrapper
Ralph Nathan872ea4d2015-05-05 18:04:56 -070020from chromite.lib import operation
David Pursellf1d16a62015-03-25 13:31:04 -070021from chromite.lib import osutils
Gilad Arnold1c8eda52015-05-04 22:32:38 -070022from chromite.lib import path_util
David Pursellf1d16a62015-03-25 13:31:04 -070023from chromite.lib import remote_access
24
25
Don Garrett97d7dc22015-01-20 14:07:56 -080026DEVSERVER_STATIC_DIR = path_util.FromChrootPath(
David Pursellf1d16a62015-03-25 13:31:04 -070027 os.path.join(constants.CHROOT_SOURCE_ROOT, 'devserver', 'static'))
28
29
Ralph Nathan9b997232015-05-15 13:13:12 -070030class UsbImagerOperation(operation.ProgressBarOperation):
31 """Progress bar for flashing image to operation."""
32
33 def __init__(self, image):
34 super(UsbImagerOperation, self).__init__()
35 self._size = os.path.getsize(image)
36 self._transferred = 0.
37 self._bytes = re.compile(r'(\d+) bytes')
38
39 def _GetDDPid(self):
40 """Get the Pid of dd."""
41 try:
42 pids = cros_build_lib.RunCommand(['pgrep', 'dd'], capture_output=True,
43 print_cmd=False).output
44 for pid in pids.splitlines():
45 if osutils.IsChildProcess(int(pid), name='dd'):
46 return int(pid)
47 return -1
48 except cros_build_lib.RunCommandError:
49 # If dd isn't still running, then we assume that it is finished.
50 return -1
51
52 def _PingDD(self, dd_pid):
53 """Send USR1 signal to dd to get status update."""
54 try:
55 cmd = ['kill', '-USR1', str(dd_pid)]
56 cros_build_lib.SudoRunCommand(cmd, print_cmd=False)
57 except cros_build_lib.RunCommandError:
58 # Here we assume that dd finished in the background.
59 return
60
61 def ParseOutput(self, output=None):
62 """Parse the output of dd to update progress bar."""
63 dd_pid = self._GetDDPid()
64 if dd_pid == -1:
65 return
66
67 self._PingDD(dd_pid)
68
69 if output is None:
70 stdout = self._stdout.read()
71 stderr = self._stderr.read()
72 output = stdout + stderr
73
74 match = self._bytes.search(output)
75 if match:
76 self._transferred = match.groups()[0]
77
78 self.ProgressBar(float(self._transferred) / self._size)
79
80
Mike Frysinger32759e42016-12-21 18:40:16 -050081def _IsFilePathGPTDiskImage(file_path, require_pmbr=False):
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -070082 """Determines if a file is a valid GPT disk.
83
84 Args:
85 file_path: Path to the file to test.
Mike Frysinger32759e42016-12-21 18:40:16 -050086 require_pmbr: Whether to require a PMBR in LBA0.
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -070087 """
88 if os.path.isfile(file_path):
Mike Frysinger32759e42016-12-21 18:40:16 -050089 with open(file_path) as image_file:
90 if require_pmbr:
91 # Seek to the end of LBA0 and look for the PMBR boot signature.
92 image_file.seek(0x1fe)
93 if image_file.read(2) != '\x55\xaa':
94 return False
95 # Current file position is start of LBA1 now.
96 else:
97 # Seek to LBA1 where the GPT starts.
98 image_file.seek(0x200)
99
100 # See if there's a GPT here.
101 if image_file.read(8) == 'EFI PART':
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700102 return True
Mike Frysinger32759e42016-12-21 18:40:16 -0500103
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700104 return False
105
106
107def _ChooseImageFromDirectory(dir_path):
108 """Lists all image files in |dir_path| and ask user to select one.
109
110 Args:
111 dir_path: Path to the directory.
112 """
113 images = sorted([x for x in os.listdir(dir_path) if
114 _IsFilePathGPTDiskImage(os.path.join(dir_path, x))])
115 idx = 0
116 if len(images) == 0:
117 raise ValueError('No image found in %s.' % dir_path)
118 elif len(images) > 1:
119 idx = cros_build_lib.GetChoice(
120 'Multiple images found in %s. Please select one to continue:' % (
121 (dir_path,)),
122 images)
123
124 return os.path.join(dir_path, images[idx])
125
126
David Pursellf1d16a62015-03-25 13:31:04 -0700127class FlashError(Exception):
128 """Thrown when there is an unrecoverable error during flash."""
129
130
131class USBImager(object):
132 """Copy image to the target removable device."""
133
Gilad Arnoldd0461442015-07-07 11:52:46 -0700134 def __init__(self, device, board, image, debug=False, install=False,
135 yes=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700136 """Initalizes USBImager."""
137 self.device = device
138 self.board = board if board else cros_build_lib.GetDefaultBoard()
139 self.image = image
David Pursellf1d16a62015-03-25 13:31:04 -0700140 self.debug = debug
141 self.debug_level = logging.DEBUG if debug else logging.INFO
142 self.install = install
143 self.yes = yes
144
145 def DeviceNameToPath(self, device_name):
146 return '/dev/%s' % device_name
147
148 def GetRemovableDeviceDescription(self, device):
149 """Returns a informational description of the removable |device|.
150
151 Args:
152 device: the device name (e.g. sdc).
153
154 Returns:
155 A string describing |device| (e.g. Patriot Memory 7918 MB).
156 """
157 desc = [
158 osutils.GetDeviceInfo(device, keyword='manufacturer'),
159 osutils.GetDeviceInfo(device, keyword='product'),
160 osutils.GetDeviceSize(self.DeviceNameToPath(device)),
161 '(%s)' % self.DeviceNameToPath(device),
162 ]
163 return ' '.join([x for x in desc if x])
164
165 def ListAllRemovableDevices(self):
166 """Returns a list of removable devices.
167
168 Returns:
169 A list of device names (e.g. ['sdb', 'sdc']).
170 """
171 devices = osutils.ListBlockDevices()
172 removable_devices = []
173 for d in devices:
174 if d.TYPE == 'disk' and d.RM == '1':
175 removable_devices.append(d.NAME)
176
177 return removable_devices
178
179 def ChooseRemovableDevice(self, devices):
180 """Lists all removable devices and asks user to select/confirm.
181
182 Args:
183 devices: a list of device names (e.g. ['sda', 'sdb']).
184
185 Returns:
186 The device name chosen by the user.
187 """
188 idx = cros_build_lib.GetChoice(
189 'Removable device(s) found. Please select/confirm to continue:',
190 [self.GetRemovableDeviceDescription(x) for x in devices])
191
192 return devices[idx]
193
194 def InstallImageToDevice(self, image, device):
195 """Installs |image| to the removable |device|.
196
197 Args:
198 image: Path to the image to copy.
199 device: Device to copy to.
200 """
201 cmd = [
202 'chromeos-install',
203 '--yes',
204 '--skip_src_removable',
205 '--skip_dst_removable',
206 '--payload_image=%s' % image,
207 '--dst=%s' % device,
208 '--skip_postinstall',
209 ]
Shuqian Zhao33242472017-08-02 18:28:44 -0700210 cros_build_lib.SudoRunCommand(cmd,
211 print_cmd=True,
212 debug_level=logging.NOTICE,
213 combine_stdout_stderr=True,
214 log_output=True)
David Pursellf1d16a62015-03-25 13:31:04 -0700215
216 def CopyImageToDevice(self, image, device):
217 """Copies |image| to the removable |device|.
218
219 Args:
220 image: Path to the image to copy.
221 device: Device to copy to.
222 """
Ralph Nathan9b997232015-05-15 13:13:12 -0700223 cmd = ['dd', 'if=%s' % image, 'of=%s' % device, 'bs=4M', 'iflag=fullblock',
224 'oflag=sync']
225 if logging.getLogger().getEffectiveLevel() <= logging.NOTICE:
226 op = UsbImagerOperation(image)
227 op.Run(cros_build_lib.SudoRunCommand, cmd, debug_level=logging.NOTICE,
228 update_period=0.5)
229 else:
230 cros_build_lib.SudoRunCommand(
231 cmd, debug_level=logging.NOTICE,
232 print_cmd=logging.getLogger().getEffectiveLevel() < logging.NOTICE)
David Pursellf1d16a62015-03-25 13:31:04 -0700233
David Pursellf1d16a62015-03-25 13:31:04 -0700234 cros_build_lib.SudoRunCommand(['sync'], debug_level=self.debug_level)
235
David Pursellf1d16a62015-03-25 13:31:04 -0700236 def _GetImagePath(self):
237 """Returns the image path to use."""
238 image_path = translated_path = None
239 if os.path.isfile(self.image):
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700240 if not self.yes and not _IsFilePathGPTDiskImage(self.image):
David Pursellf1d16a62015-03-25 13:31:04 -0700241 # TODO(wnwen): Open the tarball and if there is just one file in it,
242 # use that instead. Existing code in upload_symbols.py.
243 if cros_build_lib.BooleanPrompt(
244 prolog='The given image file is not a valid disk image. Perhaps '
245 'you forgot to untar it.',
246 prompt='Terminate the current flash process?'):
247 raise FlashError('Update terminated by user.')
248 image_path = self.image
249 elif os.path.isdir(self.image):
250 # Ask user which image (*.bin) in the folder to use.
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700251 image_path = _ChooseImageFromDirectory(self.image)
David Pursellf1d16a62015-03-25 13:31:04 -0700252 else:
253 # Translate the xbuddy path to get the exact image to use.
Gilad Arnolde62ec902015-04-24 14:41:02 -0700254 translated_path, _ = ds_wrapper.GetImagePathWithXbuddy(
Don Garrett97d7dc22015-01-20 14:07:56 -0800255 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700256 image_path = ds_wrapper.TranslatedPathToLocalPath(
Don Garrett97d7dc22015-01-20 14:07:56 -0800257 translated_path, DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700258
259 logging.info('Using image %s', translated_path or image_path)
260 return image_path
261
262 def Run(self):
263 """Image the removable device."""
264 devices = self.ListAllRemovableDevices()
265
266 if self.device:
267 # If user specified a device path, check if it exists.
268 if not os.path.exists(self.device):
269 raise FlashError('Device path %s does not exist.' % self.device)
270
271 # Then check if it is removable.
272 if self.device not in [self.DeviceNameToPath(x) for x in devices]:
273 msg = '%s is not a removable device.' % self.device
274 if not (self.yes or cros_build_lib.BooleanPrompt(
275 default=False, prolog=msg)):
276 raise FlashError('You can specify usb:// to choose from a list of '
277 'removable devices.')
278 target = None
279 if self.device:
280 # Get device name from path (e.g. sdc in /dev/sdc).
281 target = self.device.rsplit(os.path.sep, 1)[-1]
282 elif devices:
283 # Ask user to choose from the list.
284 target = self.ChooseRemovableDevice(devices)
285 else:
286 raise FlashError('No removable devices detected.')
287
288 image_path = self._GetImagePath()
289 try:
290 device = self.DeviceNameToPath(target)
291 if self.install:
292 self.InstallImageToDevice(image_path, device)
293 else:
294 self.CopyImageToDevice(image_path, device)
295 except cros_build_lib.RunCommandError:
296 logging.error('Failed copying image to device %s',
297 self.DeviceNameToPath(target))
298
299
300class FileImager(USBImager):
301 """Copy image to the target path."""
302
303 def Run(self):
304 """Copy the image to the path specified by self.device."""
Mao Huangc4777e82016-03-14 20:20:08 +0800305 if not os.path.isdir(os.path.dirname(self.device)):
306 raise FlashError('Parent of path %s is not a directory.' % self.device)
David Pursellf1d16a62015-03-25 13:31:04 -0700307
308 image_path = self._GetImagePath()
309 if os.path.isdir(self.device):
310 logging.info('Copying to %s',
311 os.path.join(self.device, os.path.basename(image_path)))
312 else:
313 logging.info('Copying to %s', self.device)
314 try:
315 shutil.copy(image_path, self.device)
316 except IOError:
317 logging.error('Failed to copy image %s to %s', image_path, self.device)
318
319
320class RemoteDeviceUpdater(object):
321 """Performs update on a remote device."""
322 DEVSERVER_FILENAME = 'devserver.py'
323 STATEFUL_UPDATE_BIN = '/usr/bin/stateful_update'
324 UPDATE_ENGINE_BIN = 'update_engine_client'
David Pursellf1d16a62015-03-25 13:31:04 -0700325 # Root working directory on the device. This directory is in the
326 # stateful partition and thus has enough space to store the payloads.
327 DEVICE_BASE_DIR = '/mnt/stateful_partition/cros-flash'
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700328 UPDATE_CHECK_INTERVAL_PROGRESSBAR = 0.5
329 UPDATE_CHECK_INTERVAL_NORMAL = 10
David Pursellf1d16a62015-03-25 13:31:04 -0700330
331 def __init__(self, ssh_hostname, ssh_port, image, stateful_update=True,
332 rootfs_update=True, clobber_stateful=False, reboot=True,
Gilad Arnoldd0461442015-07-07 11:52:46 -0700333 board=None, src_image_to_delta=None, wipe=True, debug=False,
Daniel Erat30fd2072016-08-29 10:08:56 -0600334 yes=False, force=False, ssh_private_key=None, ping=True,
Gilad Arnold821547c2015-07-07 08:57:48 -0700335 disable_verification=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700336 """Initializes RemoteDeviceUpdater"""
337 if not stateful_update and not rootfs_update:
338 raise ValueError('No update operation to perform; either stateful or'
339 ' rootfs partitions must be updated.')
340 self.tempdir = tempfile.mkdtemp(prefix='cros-flash')
341 self.ssh_hostname = ssh_hostname
342 self.ssh_port = ssh_port
343 self.image = image
344 self.board = board
David Pursellf1d16a62015-03-25 13:31:04 -0700345 self.src_image_to_delta = src_image_to_delta
346 self.do_stateful_update = stateful_update
347 self.do_rootfs_update = rootfs_update
348 self.disable_verification = disable_verification
349 self.clobber_stateful = clobber_stateful
350 self.reboot = reboot
351 self.debug = debug
Daniel Erat30fd2072016-08-29 10:08:56 -0600352 self.ssh_private_key = ssh_private_key
David Pursellf1d16a62015-03-25 13:31:04 -0700353 self.ping = ping
354 # Do not wipe if debug is set.
355 self.wipe = wipe and not debug
356 self.yes = yes
357 self.force = force
David Pursellf1d16a62015-03-25 13:31:04 -0700358
David Pursellf1d16a62015-03-25 13:31:04 -0700359 def Cleanup(self):
360 """Cleans up the temporary directory."""
361 if self.wipe:
362 logging.info('Cleaning up temporary working directory...')
363 osutils.RmDir(self.tempdir)
364 else:
365 logging.info('You can find the log files and/or payloads in %s',
366 self.tempdir)
367
xixuane851dfb2016-05-02 18:02:37 -0700368 def GetPayloadDir(self, device):
369 """Get directory of payload for update.
David Pursellf1d16a62015-03-25 13:31:04 -0700370
xixuane851dfb2016-05-02 18:02:37 -0700371 This method is used to obtain the directory of payload for cros-flash. The
372 given path 'self.image' is passed in when initializing RemoteDeviceUpdater.
David Pursellf1d16a62015-03-25 13:31:04 -0700373
xixuane851dfb2016-05-02 18:02:37 -0700374 If self.image is a directory, we directly use the provided update payload(s)
375 in this directory.
376
377 If self.image is an image, let devserver access it and generate payloads.
378
379 If not in the above cases, let devserver first obtain the image path. Then
380 devserver will access the image and generate payloads.
David Pursellf1d16a62015-03-25 13:31:04 -0700381
382 Args:
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400383 device: A ChromiumOSDevice object.
David Pursellf1d16a62015-03-25 13:31:04 -0700384
385 Returns:
xixuane851dfb2016-05-02 18:02:37 -0700386 A string payload_dir, that represents the payload directory.
David Pursellf1d16a62015-03-25 13:31:04 -0700387 """
xixuane851dfb2016-05-02 18:02:37 -0700388 payload_dir = self.tempdir
David Pursellf1d16a62015-03-25 13:31:04 -0700389
xixuane851dfb2016-05-02 18:02:37 -0700390 if os.path.isdir(self.image):
391 # The given path is a directory.
392 payload_dir = self.image
393 logging.info('Using provided payloads in %s', payload_dir)
394 elif os.path.isfile(self.image):
395 # The given path is an image.
396 logging.info('Using image %s', self.image)
397 ds_wrapper.GetUpdatePayloadsFromLocalPath(
398 self.image, payload_dir,
399 src_image_to_delta=self.src_image_to_delta,
400 static_dir=DEVSERVER_STATIC_DIR)
401 else:
402 self.board = cros_build_lib.GetBoard(device_board=device.board,
403 override_board=self.board,
404 force=self.yes)
405 if not self.board:
406 raise FlashError('No board identified')
David Pursellf1d16a62015-03-25 13:31:04 -0700407
xixuane851dfb2016-05-02 18:02:37 -0700408 if not self.force and self.board != device.board:
409 # If a board was specified, it must be compatible with the device.
Brian Norrisfab3fb22016-06-02 14:59:20 -0700410 raise FlashError('Device (%s) is incompatible with board %s' %
411 (device.board, self.board))
xixuane851dfb2016-05-02 18:02:37 -0700412
413 logging.info('Board is %s', self.board)
414
415 # Translate the xbuddy path to get the exact image to use.
416 translated_path, resolved_path = ds_wrapper.GetImagePathWithXbuddy(
417 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR,
418 lookup_only=True)
419 logging.info('Using image %s', translated_path)
420 # Convert the translated path to be used in the update request.
421 image_path = ds_wrapper.ConvertTranslatedPath(resolved_path,
422 translated_path)
423
424 # Launch a local devserver to generate/serve update payloads.
425 ds_wrapper.GetUpdatePayloads(
426 image_path, payload_dir, board=self.board,
427 src_image_to_delta=self.src_image_to_delta,
428 static_dir=DEVSERVER_STATIC_DIR)
429
430 return payload_dir
David Pursellf1d16a62015-03-25 13:31:04 -0700431
432 def Run(self):
xixuane851dfb2016-05-02 18:02:37 -0700433 """Perform remote device update.
434
435 The update process includes:
436 1. initialize a device instance for the given remote device.
437 2. achieve payload_dir which contains the required payloads for updating.
438 3. initialize an auto-updater instance to do RunUpdate().
439 4. After auto-update, all temp files and dir will be cleaned up.
440 """
David Pursellf1d16a62015-03-25 13:31:04 -0700441 try:
442 device_connected = False
xixuane851dfb2016-05-02 18:02:37 -0700443
David Pursellf1d16a62015-03-25 13:31:04 -0700444 with remote_access.ChromiumOSDeviceHandler(
Daniel Erat30fd2072016-08-29 10:08:56 -0600445 self.ssh_hostname, port=self.ssh_port, base_dir=self.DEVICE_BASE_DIR,
446 private_key=self.ssh_private_key, ping=self.ping) as device:
David Pursellf1d16a62015-03-25 13:31:04 -0700447 device_connected = True
448
xixuane851dfb2016-05-02 18:02:37 -0700449 # Get payload directory
450 payload_dir = self.GetPayloadDir(device)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700451
xixuane851dfb2016-05-02 18:02:37 -0700452 # Do auto-update
xixuan9a157272016-05-31 11:35:13 -0700453 chromeos_AU = auto_updater.ChromiumOSFlashUpdater(
xixuane851dfb2016-05-02 18:02:37 -0700454 device, payload_dir, self.tempdir,
455 do_rootfs_update=self.do_rootfs_update,
456 do_stateful_update=self.do_stateful_update,
457 reboot=self.reboot,
458 disable_verification=self.disable_verification,
459 clobber_stateful=self.clobber_stateful,
460 yes=self.yes)
461 chromeos_AU.CheckPayloads()
462 chromeos_AU.RunUpdate()
David Pursellf1d16a62015-03-25 13:31:04 -0700463
464 except Exception:
465 logging.error('Device update failed.')
466 if device_connected and device.lsb_release:
467 lsb_entries = sorted(device.lsb_release.items())
468 logging.info('Following are the LSB version details of the device:\n%s',
469 '\n'.join('%s=%s' % (k, v) for k, v in lsb_entries))
470 raise
471 else:
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700472 logging.notice('Update performed successfully.')
David Pursellf1d16a62015-03-25 13:31:04 -0700473 finally:
474 self.Cleanup()
475
Gilad Arnoldbfcfaff2015-07-07 10:08:02 -0700476def Flash(device, image, board=None, install=False, src_image_to_delta=None,
477 rootfs_update=True, stateful_update=True, clobber_stateful=False,
Daniel Erat30fd2072016-08-29 10:08:56 -0600478 reboot=True, wipe=True, ssh_private_key=None, ping=True,
479 disable_rootfs_verification=False, clear_cache=False, yes=False,
480 force=False, debug=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700481 """Flashes a device, USB drive, or file with an image.
482
483 This provides functionality common to `cros flash` and `brillo flash`
484 so that they can parse the commandline separately but still use the
485 same underlying functionality.
486
487 Args:
David Pursell2e773382015-04-03 14:30:47 -0700488 device: commandline.Device object; None to use the default device.
David Pursellf1d16a62015-03-25 13:31:04 -0700489 image: Path (string) to the update image. Can be a local or xbuddy path;
490 non-existant local paths are converted to xbuddy.
David Pursellf1d16a62015-03-25 13:31:04 -0700491 board: Board to use; None to automatically detect.
David Pursellf1d16a62015-03-25 13:31:04 -0700492 install: Install to USB using base disk layout; USB |device| scheme only.
493 src_image_to_delta: Local path to an image to be used as the base to
494 generate delta payloads; SSH |device| scheme only.
495 rootfs_update: Update rootfs partition; SSH |device| scheme only.
496 stateful_update: Update stateful partition; SSH |device| scheme only.
497 clobber_stateful: Clobber stateful partition; SSH |device| scheme only.
498 reboot: Reboot device after update; SSH |device| scheme only.
499 wipe: Wipe temporary working directory; SSH |device| scheme only.
Daniel Erat30fd2072016-08-29 10:08:56 -0600500 ssh_private_key: Path to an SSH private key file; None to use test keys.
David Pursellf1d16a62015-03-25 13:31:04 -0700501 ping: Ping the device before attempting update; SSH |device| scheme only.
502 disable_rootfs_verification: Remove rootfs verification after update; SSH
503 |device| scheme only.
504 clear_cache: Clear the devserver static directory.
505 yes: Assume "yes" for any prompt.
506 force: Ignore sanity checks and prompts. Overrides |yes| if True.
507 debug: Print additional debugging messages.
508
509 Raises:
510 FlashError: An unrecoverable error occured.
511 ValueError: Invalid parameter combination.
512 """
513 if force:
514 yes = True
515
516 if clear_cache:
517 logging.info('Clearing the cache...')
Don Garrett97d7dc22015-01-20 14:07:56 -0800518 ds_wrapper.DevServerWrapper.WipeStaticDirectory(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700519
520 try:
Don Garrett97d7dc22015-01-20 14:07:56 -0800521 osutils.SafeMakedirsNonRoot(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700522 except OSError:
Don Garrett97d7dc22015-01-20 14:07:56 -0800523 logging.error('Failed to create %s', DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700524
525 if install:
David Pursell2e773382015-04-03 14:30:47 -0700526 if not device or device.scheme != commandline.DEVICE_SCHEME_USB:
David Pursellf1d16a62015-03-25 13:31:04 -0700527 raise ValueError(
528 '--install can only be used when writing to a USB device')
529 if not cros_build_lib.IsInsideChroot():
530 raise ValueError('--install can only be used inside the chroot')
531
David Pursell2e773382015-04-03 14:30:47 -0700532 if not device or device.scheme == commandline.DEVICE_SCHEME_SSH:
533 if device:
534 hostname, port = device.hostname, device.port
535 else:
536 hostname, port = None, None
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700537 logging.notice('Preparing to update the remote device %s', hostname)
David Pursellf1d16a62015-03-25 13:31:04 -0700538 updater = RemoteDeviceUpdater(
David Pursell2e773382015-04-03 14:30:47 -0700539 hostname,
540 port,
David Pursellf1d16a62015-03-25 13:31:04 -0700541 image,
542 board=board,
David Pursellf1d16a62015-03-25 13:31:04 -0700543 src_image_to_delta=src_image_to_delta,
544 rootfs_update=rootfs_update,
545 stateful_update=stateful_update,
546 clobber_stateful=clobber_stateful,
547 reboot=reboot,
548 wipe=wipe,
549 debug=debug,
550 yes=yes,
551 force=force,
Daniel Erat30fd2072016-08-29 10:08:56 -0600552 ssh_private_key=ssh_private_key,
David Pursellf1d16a62015-03-25 13:31:04 -0700553 ping=ping,
Gilad Arnold821547c2015-07-07 08:57:48 -0700554 disable_verification=disable_rootfs_verification)
David Pursellf1d16a62015-03-25 13:31:04 -0700555 updater.Run()
556 elif device.scheme == commandline.DEVICE_SCHEME_USB:
557 path = osutils.ExpandPath(device.path) if device.path else ''
558 logging.info('Preparing to image the removable device %s', path)
559 imager = USBImager(path,
560 board,
561 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700562 debug=debug,
563 install=install,
564 yes=yes)
565 imager.Run()
566 elif device.scheme == commandline.DEVICE_SCHEME_FILE:
567 logging.info('Preparing to copy image to %s', device.path)
568 imager = FileImager(device.path,
569 board,
570 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700571 debug=debug,
572 yes=yes)
573 imager.Run()