blob: 3acccc2348c63b15c85b367c826fc260f59b0b56 [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 ]
210 cros_build_lib.SudoRunCommand(cmd)
211
212 def CopyImageToDevice(self, image, device):
213 """Copies |image| to the removable |device|.
214
215 Args:
216 image: Path to the image to copy.
217 device: Device to copy to.
218 """
Ralph Nathan9b997232015-05-15 13:13:12 -0700219 cmd = ['dd', 'if=%s' % image, 'of=%s' % device, 'bs=4M', 'iflag=fullblock',
220 'oflag=sync']
221 if logging.getLogger().getEffectiveLevel() <= logging.NOTICE:
222 op = UsbImagerOperation(image)
223 op.Run(cros_build_lib.SudoRunCommand, cmd, debug_level=logging.NOTICE,
224 update_period=0.5)
225 else:
226 cros_build_lib.SudoRunCommand(
227 cmd, debug_level=logging.NOTICE,
228 print_cmd=logging.getLogger().getEffectiveLevel() < logging.NOTICE)
David Pursellf1d16a62015-03-25 13:31:04 -0700229
David Pursellf1d16a62015-03-25 13:31:04 -0700230 cros_build_lib.SudoRunCommand(['sync'], debug_level=self.debug_level)
231
David Pursellf1d16a62015-03-25 13:31:04 -0700232 def _GetImagePath(self):
233 """Returns the image path to use."""
234 image_path = translated_path = None
235 if os.path.isfile(self.image):
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700236 if not self.yes and not _IsFilePathGPTDiskImage(self.image):
David Pursellf1d16a62015-03-25 13:31:04 -0700237 # TODO(wnwen): Open the tarball and if there is just one file in it,
238 # use that instead. Existing code in upload_symbols.py.
239 if cros_build_lib.BooleanPrompt(
240 prolog='The given image file is not a valid disk image. Perhaps '
241 'you forgot to untar it.',
242 prompt='Terminate the current flash process?'):
243 raise FlashError('Update terminated by user.')
244 image_path = self.image
245 elif os.path.isdir(self.image):
246 # Ask user which image (*.bin) in the folder to use.
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700247 image_path = _ChooseImageFromDirectory(self.image)
David Pursellf1d16a62015-03-25 13:31:04 -0700248 else:
249 # Translate the xbuddy path to get the exact image to use.
Gilad Arnolde62ec902015-04-24 14:41:02 -0700250 translated_path, _ = ds_wrapper.GetImagePathWithXbuddy(
Don Garrett97d7dc22015-01-20 14:07:56 -0800251 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700252 image_path = ds_wrapper.TranslatedPathToLocalPath(
Don Garrett97d7dc22015-01-20 14:07:56 -0800253 translated_path, DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700254
255 logging.info('Using image %s', translated_path or image_path)
256 return image_path
257
258 def Run(self):
259 """Image the removable device."""
260 devices = self.ListAllRemovableDevices()
261
262 if self.device:
263 # If user specified a device path, check if it exists.
264 if not os.path.exists(self.device):
265 raise FlashError('Device path %s does not exist.' % self.device)
266
267 # Then check if it is removable.
268 if self.device not in [self.DeviceNameToPath(x) for x in devices]:
269 msg = '%s is not a removable device.' % self.device
270 if not (self.yes or cros_build_lib.BooleanPrompt(
271 default=False, prolog=msg)):
272 raise FlashError('You can specify usb:// to choose from a list of '
273 'removable devices.')
274 target = None
275 if self.device:
276 # Get device name from path (e.g. sdc in /dev/sdc).
277 target = self.device.rsplit(os.path.sep, 1)[-1]
278 elif devices:
279 # Ask user to choose from the list.
280 target = self.ChooseRemovableDevice(devices)
281 else:
282 raise FlashError('No removable devices detected.')
283
284 image_path = self._GetImagePath()
285 try:
286 device = self.DeviceNameToPath(target)
287 if self.install:
288 self.InstallImageToDevice(image_path, device)
289 else:
290 self.CopyImageToDevice(image_path, device)
291 except cros_build_lib.RunCommandError:
292 logging.error('Failed copying image to device %s',
293 self.DeviceNameToPath(target))
294
295
296class FileImager(USBImager):
297 """Copy image to the target path."""
298
299 def Run(self):
300 """Copy the image to the path specified by self.device."""
Mao Huangc4777e82016-03-14 20:20:08 +0800301 if not os.path.isdir(os.path.dirname(self.device)):
302 raise FlashError('Parent of path %s is not a directory.' % self.device)
David Pursellf1d16a62015-03-25 13:31:04 -0700303
304 image_path = self._GetImagePath()
305 if os.path.isdir(self.device):
306 logging.info('Copying to %s',
307 os.path.join(self.device, os.path.basename(image_path)))
308 else:
309 logging.info('Copying to %s', self.device)
310 try:
311 shutil.copy(image_path, self.device)
312 except IOError:
313 logging.error('Failed to copy image %s to %s', image_path, self.device)
314
315
316class RemoteDeviceUpdater(object):
317 """Performs update on a remote device."""
318 DEVSERVER_FILENAME = 'devserver.py'
319 STATEFUL_UPDATE_BIN = '/usr/bin/stateful_update'
320 UPDATE_ENGINE_BIN = 'update_engine_client'
David Pursellf1d16a62015-03-25 13:31:04 -0700321 # Root working directory on the device. This directory is in the
322 # stateful partition and thus has enough space to store the payloads.
323 DEVICE_BASE_DIR = '/mnt/stateful_partition/cros-flash'
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700324 UPDATE_CHECK_INTERVAL_PROGRESSBAR = 0.5
325 UPDATE_CHECK_INTERVAL_NORMAL = 10
David Pursellf1d16a62015-03-25 13:31:04 -0700326
327 def __init__(self, ssh_hostname, ssh_port, image, stateful_update=True,
328 rootfs_update=True, clobber_stateful=False, reboot=True,
Gilad Arnoldd0461442015-07-07 11:52:46 -0700329 board=None, src_image_to_delta=None, wipe=True, debug=False,
Daniel Erat30fd2072016-08-29 10:08:56 -0600330 yes=False, force=False, ssh_private_key=None, ping=True,
Gilad Arnold821547c2015-07-07 08:57:48 -0700331 disable_verification=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700332 """Initializes RemoteDeviceUpdater"""
333 if not stateful_update and not rootfs_update:
334 raise ValueError('No update operation to perform; either stateful or'
335 ' rootfs partitions must be updated.')
336 self.tempdir = tempfile.mkdtemp(prefix='cros-flash')
337 self.ssh_hostname = ssh_hostname
338 self.ssh_port = ssh_port
339 self.image = image
340 self.board = board
David Pursellf1d16a62015-03-25 13:31:04 -0700341 self.src_image_to_delta = src_image_to_delta
342 self.do_stateful_update = stateful_update
343 self.do_rootfs_update = rootfs_update
344 self.disable_verification = disable_verification
345 self.clobber_stateful = clobber_stateful
346 self.reboot = reboot
347 self.debug = debug
Daniel Erat30fd2072016-08-29 10:08:56 -0600348 self.ssh_private_key = ssh_private_key
David Pursellf1d16a62015-03-25 13:31:04 -0700349 self.ping = ping
350 # Do not wipe if debug is set.
351 self.wipe = wipe and not debug
352 self.yes = yes
353 self.force = force
David Pursellf1d16a62015-03-25 13:31:04 -0700354
David Pursellf1d16a62015-03-25 13:31:04 -0700355 def Cleanup(self):
356 """Cleans up the temporary directory."""
357 if self.wipe:
358 logging.info('Cleaning up temporary working directory...')
359 osutils.RmDir(self.tempdir)
360 else:
361 logging.info('You can find the log files and/or payloads in %s',
362 self.tempdir)
363
xixuane851dfb2016-05-02 18:02:37 -0700364 def GetPayloadDir(self, device):
365 """Get directory of payload for update.
David Pursellf1d16a62015-03-25 13:31:04 -0700366
xixuane851dfb2016-05-02 18:02:37 -0700367 This method is used to obtain the directory of payload for cros-flash. The
368 given path 'self.image' is passed in when initializing RemoteDeviceUpdater.
David Pursellf1d16a62015-03-25 13:31:04 -0700369
xixuane851dfb2016-05-02 18:02:37 -0700370 If self.image is a directory, we directly use the provided update payload(s)
371 in this directory.
372
373 If self.image is an image, let devserver access it and generate payloads.
374
375 If not in the above cases, let devserver first obtain the image path. Then
376 devserver will access the image and generate payloads.
David Pursellf1d16a62015-03-25 13:31:04 -0700377
378 Args:
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400379 device: A ChromiumOSDevice object.
David Pursellf1d16a62015-03-25 13:31:04 -0700380
381 Returns:
xixuane851dfb2016-05-02 18:02:37 -0700382 A string payload_dir, that represents the payload directory.
David Pursellf1d16a62015-03-25 13:31:04 -0700383 """
xixuane851dfb2016-05-02 18:02:37 -0700384 payload_dir = self.tempdir
David Pursellf1d16a62015-03-25 13:31:04 -0700385
xixuane851dfb2016-05-02 18:02:37 -0700386 if os.path.isdir(self.image):
387 # The given path is a directory.
388 payload_dir = self.image
389 logging.info('Using provided payloads in %s', payload_dir)
390 elif os.path.isfile(self.image):
391 # The given path is an image.
392 logging.info('Using image %s', self.image)
393 ds_wrapper.GetUpdatePayloadsFromLocalPath(
394 self.image, payload_dir,
395 src_image_to_delta=self.src_image_to_delta,
396 static_dir=DEVSERVER_STATIC_DIR)
397 else:
398 self.board = cros_build_lib.GetBoard(device_board=device.board,
399 override_board=self.board,
400 force=self.yes)
401 if not self.board:
402 raise FlashError('No board identified')
David Pursellf1d16a62015-03-25 13:31:04 -0700403
xixuane851dfb2016-05-02 18:02:37 -0700404 if not self.force and self.board != device.board:
405 # If a board was specified, it must be compatible with the device.
Brian Norrisfab3fb22016-06-02 14:59:20 -0700406 raise FlashError('Device (%s) is incompatible with board %s' %
407 (device.board, self.board))
xixuane851dfb2016-05-02 18:02:37 -0700408
409 logging.info('Board is %s', self.board)
410
411 # Translate the xbuddy path to get the exact image to use.
412 translated_path, resolved_path = ds_wrapper.GetImagePathWithXbuddy(
413 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR,
414 lookup_only=True)
415 logging.info('Using image %s', translated_path)
416 # Convert the translated path to be used in the update request.
417 image_path = ds_wrapper.ConvertTranslatedPath(resolved_path,
418 translated_path)
419
420 # Launch a local devserver to generate/serve update payloads.
421 ds_wrapper.GetUpdatePayloads(
422 image_path, payload_dir, board=self.board,
423 src_image_to_delta=self.src_image_to_delta,
424 static_dir=DEVSERVER_STATIC_DIR)
425
426 return payload_dir
David Pursellf1d16a62015-03-25 13:31:04 -0700427
428 def Run(self):
xixuane851dfb2016-05-02 18:02:37 -0700429 """Perform remote device update.
430
431 The update process includes:
432 1. initialize a device instance for the given remote device.
433 2. achieve payload_dir which contains the required payloads for updating.
434 3. initialize an auto-updater instance to do RunUpdate().
435 4. After auto-update, all temp files and dir will be cleaned up.
436 """
David Pursellf1d16a62015-03-25 13:31:04 -0700437 try:
438 device_connected = False
xixuane851dfb2016-05-02 18:02:37 -0700439
David Pursellf1d16a62015-03-25 13:31:04 -0700440 with remote_access.ChromiumOSDeviceHandler(
Daniel Erat30fd2072016-08-29 10:08:56 -0600441 self.ssh_hostname, port=self.ssh_port, base_dir=self.DEVICE_BASE_DIR,
442 private_key=self.ssh_private_key, ping=self.ping) as device:
David Pursellf1d16a62015-03-25 13:31:04 -0700443 device_connected = True
444
xixuane851dfb2016-05-02 18:02:37 -0700445 # Get payload directory
446 payload_dir = self.GetPayloadDir(device)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700447
xixuane851dfb2016-05-02 18:02:37 -0700448 # Do auto-update
xixuan9a157272016-05-31 11:35:13 -0700449 chromeos_AU = auto_updater.ChromiumOSFlashUpdater(
xixuane851dfb2016-05-02 18:02:37 -0700450 device, payload_dir, self.tempdir,
451 do_rootfs_update=self.do_rootfs_update,
452 do_stateful_update=self.do_stateful_update,
453 reboot=self.reboot,
454 disable_verification=self.disable_verification,
455 clobber_stateful=self.clobber_stateful,
456 yes=self.yes)
457 chromeos_AU.CheckPayloads()
458 chromeos_AU.RunUpdate()
David Pursellf1d16a62015-03-25 13:31:04 -0700459
460 except Exception:
461 logging.error('Device update failed.')
462 if device_connected and device.lsb_release:
463 lsb_entries = sorted(device.lsb_release.items())
464 logging.info('Following are the LSB version details of the device:\n%s',
465 '\n'.join('%s=%s' % (k, v) for k, v in lsb_entries))
466 raise
467 else:
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700468 logging.notice('Update performed successfully.')
David Pursellf1d16a62015-03-25 13:31:04 -0700469 finally:
470 self.Cleanup()
471
Gilad Arnoldbfcfaff2015-07-07 10:08:02 -0700472def Flash(device, image, board=None, install=False, src_image_to_delta=None,
473 rootfs_update=True, stateful_update=True, clobber_stateful=False,
Daniel Erat30fd2072016-08-29 10:08:56 -0600474 reboot=True, wipe=True, ssh_private_key=None, ping=True,
475 disable_rootfs_verification=False, clear_cache=False, yes=False,
476 force=False, debug=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700477 """Flashes a device, USB drive, or file with an image.
478
479 This provides functionality common to `cros flash` and `brillo flash`
480 so that they can parse the commandline separately but still use the
481 same underlying functionality.
482
483 Args:
David Pursell2e773382015-04-03 14:30:47 -0700484 device: commandline.Device object; None to use the default device.
David Pursellf1d16a62015-03-25 13:31:04 -0700485 image: Path (string) to the update image. Can be a local or xbuddy path;
486 non-existant local paths are converted to xbuddy.
David Pursellf1d16a62015-03-25 13:31:04 -0700487 board: Board to use; None to automatically detect.
David Pursellf1d16a62015-03-25 13:31:04 -0700488 install: Install to USB using base disk layout; USB |device| scheme only.
489 src_image_to_delta: Local path to an image to be used as the base to
490 generate delta payloads; SSH |device| scheme only.
491 rootfs_update: Update rootfs partition; SSH |device| scheme only.
492 stateful_update: Update stateful partition; SSH |device| scheme only.
493 clobber_stateful: Clobber stateful partition; SSH |device| scheme only.
494 reboot: Reboot device after update; SSH |device| scheme only.
495 wipe: Wipe temporary working directory; SSH |device| scheme only.
Daniel Erat30fd2072016-08-29 10:08:56 -0600496 ssh_private_key: Path to an SSH private key file; None to use test keys.
David Pursellf1d16a62015-03-25 13:31:04 -0700497 ping: Ping the device before attempting update; SSH |device| scheme only.
498 disable_rootfs_verification: Remove rootfs verification after update; SSH
499 |device| scheme only.
500 clear_cache: Clear the devserver static directory.
501 yes: Assume "yes" for any prompt.
502 force: Ignore sanity checks and prompts. Overrides |yes| if True.
503 debug: Print additional debugging messages.
504
505 Raises:
506 FlashError: An unrecoverable error occured.
507 ValueError: Invalid parameter combination.
508 """
509 if force:
510 yes = True
511
512 if clear_cache:
513 logging.info('Clearing the cache...')
Don Garrett97d7dc22015-01-20 14:07:56 -0800514 ds_wrapper.DevServerWrapper.WipeStaticDirectory(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700515
516 try:
Don Garrett97d7dc22015-01-20 14:07:56 -0800517 osutils.SafeMakedirsNonRoot(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700518 except OSError:
Don Garrett97d7dc22015-01-20 14:07:56 -0800519 logging.error('Failed to create %s', DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700520
521 if install:
David Pursell2e773382015-04-03 14:30:47 -0700522 if not device or device.scheme != commandline.DEVICE_SCHEME_USB:
David Pursellf1d16a62015-03-25 13:31:04 -0700523 raise ValueError(
524 '--install can only be used when writing to a USB device')
525 if not cros_build_lib.IsInsideChroot():
526 raise ValueError('--install can only be used inside the chroot')
527
David Pursell2e773382015-04-03 14:30:47 -0700528 if not device or device.scheme == commandline.DEVICE_SCHEME_SSH:
529 if device:
530 hostname, port = device.hostname, device.port
531 else:
532 hostname, port = None, None
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700533 logging.notice('Preparing to update the remote device %s', hostname)
David Pursellf1d16a62015-03-25 13:31:04 -0700534 updater = RemoteDeviceUpdater(
David Pursell2e773382015-04-03 14:30:47 -0700535 hostname,
536 port,
David Pursellf1d16a62015-03-25 13:31:04 -0700537 image,
538 board=board,
David Pursellf1d16a62015-03-25 13:31:04 -0700539 src_image_to_delta=src_image_to_delta,
540 rootfs_update=rootfs_update,
541 stateful_update=stateful_update,
542 clobber_stateful=clobber_stateful,
543 reboot=reboot,
544 wipe=wipe,
545 debug=debug,
546 yes=yes,
547 force=force,
Daniel Erat30fd2072016-08-29 10:08:56 -0600548 ssh_private_key=ssh_private_key,
David Pursellf1d16a62015-03-25 13:31:04 -0700549 ping=ping,
Gilad Arnold821547c2015-07-07 08:57:48 -0700550 disable_verification=disable_rootfs_verification)
David Pursellf1d16a62015-03-25 13:31:04 -0700551 updater.Run()
552 elif device.scheme == commandline.DEVICE_SCHEME_USB:
553 path = osutils.ExpandPath(device.path) if device.path else ''
554 logging.info('Preparing to image the removable device %s', path)
555 imager = USBImager(path,
556 board,
557 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700558 debug=debug,
559 install=install,
560 yes=yes)
561 imager.Run()
562 elif device.scheme == commandline.DEVICE_SCHEME_FILE:
563 logging.info('Preparing to copy image to %s', device.path)
564 imager = FileImager(device.path,
565 board,
566 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700567 debug=debug,
568 yes=yes)
569 imager.Run()