blob: 4f4f248896ccb8b5b02d111a8f442bf821bbe413 [file] [log] [blame]
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +08001#!/usr/bin/python -Bu
2#
3# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Factory toolkit installer.
8
9The factory toolkit is a self-extracting shellball containing factory test
10related files and this installer. This installer is invoked when the toolkit
11is deployed and is responsible for installing files.
12"""
13
14
15import argparse
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +080016from contextlib import contextmanager
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +080017import os
Wei-Ning Huang4855e792015-06-11 15:33:39 +080018import shutil
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +080019import sys
Jon Salz4f3ade52014-02-20 17:55:09 +080020import tempfile
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +080021
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +080022import factory_common # pylint: disable=W0611
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +080023from cros.factory.test import event_log
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +080024from cros.factory.test import factory
Jon Salz25590302014-07-11 16:07:20 +080025from cros.factory.tools import install_symlinks
Rong Chang6d65fad2014-08-22 16:00:12 +080026from cros.factory.utils import file_utils
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +080027from cros.factory.utils.process_utils import Spawn
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +080028from cros.factory.utils import sys_utils
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +080029
30
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +080031INSTALLER_PATH = 'usr/local/factory/py/toolkit/installer.py'
Rong Chang6d65fad2014-08-22 16:00:12 +080032MAKESELF_SHELL = '/bin/sh'
33TOOLKIT_NAME = 'install_factory_toolkit.run'
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +080034
Jon Salz4f3ade52014-02-20 17:55:09 +080035# Short and sweet help header for the executable generated by makeself.
36HELP_HEADER = """
37Installs the factory toolkit, transforming a test image into a factory test
38image. You can:
39
40- Install the factory toolkit on a CrOS device that is running a test
41 image. To do this, copy install_factory_toolkit.run to the device and
42 run it. The factory tests will then come up on the next boot.
43
44 rsync -a install_factory_toolkit.run crosdevice:/tmp
45 ssh crosdevice '/tmp/install_factory_toolkit.run && sync && reboot'
46
47- Modify a test image, turning it into a factory test image. When you
48 use the image on a device, the factory tests will come up.
49
50 install_factory_toolkit.run chromiumos_test_image.bin
51"""
52
53HELP_HEADER_ADVANCED = """
54- (advanced) Modify a mounted stateful partition, turning it into a factory
55 test image. This is equivalent to the previous command:
56
57 mount_partition -rw chromiumos_test_image.bin 1 /mnt/stateful
58 install_factory_toolkit.run /mnt/stateful
59 umount /mnt/stateful
60
61- (advanced) Unpack the factory toolkit, modify a file, and then repack it.
62
63 # Unpack but don't actually install
64 install_factory_toolkit.run --target /tmp/toolkit --noexec
65 # Edit some files in /tmp/toolkit
66 emacs /tmp/toolkit/whatever
67 # Repack
68 install_factory_toolkit.run -- --repack /tmp/toolkit \\
69 --pack-into /path/to/new/install_factory_toolkit.run
70"""
71
72# The makeself-generated header comes next. This is a little confusing,
73# so explain.
74HELP_HEADER_MAKESELF = """
75For complete usage information and advanced operations, run
76"install_factory_toolkit.run -- --help" (note the extra "--").
77
78Following is the help message from makeself, which was used to create
79this self-extracting archive.
80
81-----
82"""
83
Vic Yangdb1e20e2014-10-05 12:10:33 +080084SERVER_FILE_MASK = [
85 # Exclude Umpire server but keep Umpire client
86 '--include', 'py/umpire/__init__.*',
87 '--include', 'py/umpire/common.*',
88 '--include', 'py/umpire/client',
89 '--include', 'py/umpire/client/**',
90 '--exclude', 'py/umpire/**',
91
92 # Lumberjack is only used on Umpire server
93 '--exclude', 'py/lumberjack'
94]
95
Jon Salz4f3ade52014-02-20 17:55:09 +080096
Hung-Te Lin7b596ff2015-01-16 20:19:15 +080097class FactoryToolkitInstaller(object):
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +080098 """Factory toolkit installer.
99
100 Args:
101 src: Source path containing usr/ and var/.
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800102 dest: Installation destination path. Set this to the mount point of the
103 stateful partition if patching a test image.
104 no_enable: True to not install the tag file.
105 system_root: The path to the root of the file system. This must be left
106 as its default value except for unit testing.
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800107 """
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800108
Jon Salzb7e44262014-05-07 15:53:37 +0800109 # Whether to sudo when rsyncing; set to False for testing.
110 _sudo = True
111
Peter Ammon948b7172014-07-15 12:43:06 -0700112 def __init__(self, src, dest, no_enable, enable_presenter,
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800113 enable_device, non_cros=False, device_id=None, system_root='/'):
Jon Salz4f3ade52014-02-20 17:55:09 +0800114 self._src = src
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800115 self._system_root = system_root
116 if dest == self._system_root:
117 self._usr_local_dest = os.path.join(dest, 'usr', 'local')
118 self._var_dest = os.path.join(dest, 'var')
Jon Salz4f3ade52014-02-20 17:55:09 +0800119
120 # Make sure we're on a CrOS device.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800121 if not non_cros and not sys_utils.InCrOSDevice():
Jon Salz4f3ade52014-02-20 17:55:09 +0800122 sys.stderr.write(
Vic Yang196d5242014-08-05 13:51:35 +0800123 "ERROR: You're not on a CrOS device (for more details, please\n"
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800124 'check sys_utils.py:InCrOSDevice), so you must specify a test\n'
Hung-Te Lin56b18402015-01-16 14:52:30 +0800125 'image or a mounted stateful partition on which to install the\n'
126 'factory toolkit. Please run\n'
127 '\n'
128 ' install_factory_toolkit.run -- --help\n'
129 '\n'
Vic Yang70fdae92015-02-17 19:21:08 -0800130 'for help.\n'
131 '\n'
132 'If you want to install the presenter on a non-CrOS host,\n'
133 'please run\n'
134 '\n'
135 ' install_factory_toolkit.run -- \\\n'
136 ' --non-cros --no-enable-device --enable-presenter\n'
137 '\n')
Jon Salz4f3ade52014-02-20 17:55:09 +0800138 sys.exit(1)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800139 if os.getuid() != 0:
Jon Salz4f3ade52014-02-20 17:55:09 +0800140 raise Exception('You must be root to install the factory toolkit on a '
141 'CrOS device.')
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800142 else:
143 self._usr_local_dest = os.path.join(dest, 'dev_image')
144 self._var_dest = os.path.join(dest, 'var_overlay')
145 if (not os.path.exists(self._usr_local_dest) or
146 not os.path.exists(self._var_dest)):
147 raise Exception(
148 'The destination path %s is not a stateful partition!' % dest)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800149
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800150 self._dest = dest
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800151 self._usr_local_src = os.path.join(src, 'usr', 'local')
152 self._var_src = os.path.join(src, 'var')
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800153 self._no_enable = no_enable
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800154 self._tag_file = os.path.join(self._usr_local_dest, 'factory', 'enabled')
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800155
Peter Ammon948b7172014-07-15 12:43:06 -0700156 self._enable_presenter = enable_presenter
157 self._presenter_tag_file = os.path.join(self._usr_local_dest, 'factory',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800158 'init', 'run_goofy_presenter')
Vic Yang7039f422014-07-07 15:38:13 -0700159
160 self._enable_device = enable_device
Ricky Liangd7716912014-07-10 11:52:24 +0800161 self._device_tag_file = os.path.join(self._usr_local_dest, 'factory',
162 'init', 'run_goofy_device')
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800163 self._device_id = device_id
Vic Yang7039f422014-07-07 15:38:13 -0700164
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800165 if (not os.path.exists(self._usr_local_src) or
166 not os.path.exists(self._var_src)):
167 raise Exception(
168 'This installer must be run from within the factory toolkit!')
169
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800170 def WarningMessage(self, target_test_image=None):
Jon Salz4f3ade52014-02-20 17:55:09 +0800171 with open(os.path.join(self._src, 'VERSION')) as f:
172 ret = f.read()
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800173 if target_test_image:
Jon Salz4f3ade52014-02-20 17:55:09 +0800174 ret += (
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800175 '\n'
176 '\n'
Jon Salz4f3ade52014-02-20 17:55:09 +0800177 '*** You are about to patch the factory toolkit into:\n'
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800178 '*** %s\n'
179 '***' % target_test_image)
180 else:
Jon Salz4f3ade52014-02-20 17:55:09 +0800181 ret += (
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800182 '\n'
183 '\n'
Jon Salz4f3ade52014-02-20 17:55:09 +0800184 '*** You are about to install the factory toolkit to:\n'
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800185 '*** %s\n'
186 '***' % self._dest)
187 if self._dest == self._system_root:
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800188 if self._no_enable:
Hung-Te Lin7b596ff2015-01-16 20:19:15 +0800189 ret += ('\n*** Factory tests will be disabled after this process is '
Hung-Te Lin56b18402015-01-16 14:52:30 +0800190 'done, but\n*** you can enable them by creating the factory '
191 'enabled tag:\n*** %s\n***' % self._tag_file)
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800192 else:
Hung-Te Lin7b596ff2015-01-16 20:19:15 +0800193 ret += ('\n*** After this process is done, your device will start '
Hung-Te Lin56b18402015-01-16 14:52:30 +0800194 'factory\n*** tests on the next reboot.\n***\n*** Factory '
195 'tests can be disabled by deleting the factory enabled\n*** '
196 'tag:\n*** %s\n***' % self._tag_file)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800197 return ret
198
Vic Yang7039f422014-07-07 15:38:13 -0700199 def _SetTagFile(self, name, path, enabled):
200 """Install or remove a tag file."""
201 if enabled:
202 print '*** Installing %s enabled tag...' % name
203 Spawn(['touch', path], sudo=True, log=True, check_call=True)
Ricky Liang8c88a122014-07-11 21:21:22 +0800204 Spawn(['chmod', 'go+r', path], sudo=True, log=True, check_call=True)
Vic Yang7039f422014-07-07 15:38:13 -0700205 else:
206 print '*** Removing %s enabled tag...' % name
207 Spawn(['rm', '-f', path], sudo=True, log=True, check_call=True)
208
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800209 def _SetDeviceID(self):
210 if self._device_id is not None:
211 with open(os.path.join(event_log.DEVICE_ID_PATH), 'w') as f:
212 f.write(self._device_id)
213
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800214 def Install(self):
215 print '*** Installing factory toolkit...'
Jon Salzb7e44262014-05-07 15:53:37 +0800216 for src, dest in ((self._usr_local_src, self._usr_local_dest),
217 (self._var_src, self._var_dest)):
218 # Change the source directory to root, and add group/world read
219 # permissions. This is necessary because when the toolkit was
220 # unpacked, the user may not have been root so the permessions
221 # may be hosed. This is skipped for testing.
Peter Ammon5ac58422014-06-09 14:45:50 -0700222 # --force is necessary to allow goofy directory from prior
223 # toolkit installations to be overwritten by the goofy symlink.
Ricky Liang5e95be22014-07-09 12:52:07 +0800224 try:
225 if self._sudo:
226 Spawn(['chown', '-R', 'root', src],
227 sudo=True, log=True, check_call=True)
228 Spawn(['chmod', '-R', 'go+rX', src],
229 sudo=True, log=True, check_call=True)
230 print '*** %s -> %s' % (src, dest)
Hung-Te Lin56b18402015-01-16 14:52:30 +0800231 Spawn(['rsync', '-a', '--force'] + SERVER_FILE_MASK +
Vic Yangdb1e20e2014-10-05 12:10:33 +0800232 [src + '/', dest], sudo=self._sudo, log=True,
233 check_output=True, cwd=src)
Ricky Liang5e95be22014-07-09 12:52:07 +0800234 finally:
235 # Need to change the source directory back to the original user, or the
236 # script in makeself will fail to remove the temporary source directory.
237 if self._sudo:
238 myuser = os.environ.get('USER')
239 Spawn(['chown', '-R', myuser, src],
240 sudo=True, log=True, check_call=True)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800241
Jon Salz25590302014-07-11 16:07:20 +0800242 print '*** Installing symlinks...'
243 install_symlinks.InstallSymlinks(
244 '../factory/bin',
245 os.path.join(self._usr_local_dest, 'bin'),
246 install_symlinks.MODE_FULL,
247 sudo=self._sudo)
248
249 print '*** Removing factory-mini...'
250 Spawn(['rm', '-rf', os.path.join(self._usr_local_dest, 'factory-mini')],
251 sudo=self._sudo, log=True, check_call=True)
252
Vic Yang7039f422014-07-07 15:38:13 -0700253 self._SetTagFile('factory', self._tag_file, not self._no_enable)
Peter Ammon948b7172014-07-15 12:43:06 -0700254 self._SetTagFile('presenter', self._presenter_tag_file,
255 self._enable_presenter)
Vic Yang7039f422014-07-07 15:38:13 -0700256 self._SetTagFile('device', self._device_tag_file, self._enable_device)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800257
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800258 self._SetDeviceID()
259
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800260 print '*** Installation completed.'
261
262
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800263@contextmanager
264def DummyContext(arg):
265 """A context manager that simply yields its argument."""
266 yield arg
267
268
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800269def PrintBuildInfo(src_root):
270 """Print build information."""
271 info_file = os.path.join(src_root, 'REPO_STATUS')
272 if not os.path.exists(info_file):
273 raise OSError('Build info file not found!')
274 with open(info_file, 'r') as f:
275 print f.read()
276
277
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800278def PackFactoryToolkit(src_root, output_path, enable_device, enable_presenter):
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800279 """Packs the files containing this script into a factory toolkit."""
280 with open(os.path.join(src_root, 'VERSION'), 'r') as f:
281 version = f.read().strip()
Jon Salz4f3ade52014-02-20 17:55:09 +0800282 with tempfile.NamedTemporaryFile() as help_header:
Hung-Te Lin56b18402015-01-16 14:52:30 +0800283 help_header.write(version + '\n' + HELP_HEADER + HELP_HEADER_MAKESELF)
Jon Salz4f3ade52014-02-20 17:55:09 +0800284 help_header.flush()
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800285 cmd = [os.path.join(src_root, 'makeself.sh'), '--bzip2', '--nox11',
Jon Salz4f3ade52014-02-20 17:55:09 +0800286 '--help-header', help_header.name,
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800287 src_root, output_path, version, INSTALLER_PATH, '--in-exe']
288 if not enable_device:
289 cmd.append('--no-enable-device')
290 if not enable_presenter:
291 cmd.append('--no-enable-presenter')
292 Spawn(cmd, check_call=True, log=True)
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800293 print ('\n'
Hung-Te Lin56b18402015-01-16 14:52:30 +0800294 ' Factory toolkit generated at %s.\n'
295 '\n'
296 ' To install factory toolkit on a live device running a test image,\n'
297 ' copy this to the device and execute it as root.\n'
298 '\n'
299 ' Alternatively, the factory toolkit can be used to patch a test\n'
300 ' image. For more information, run:\n'
301 ' %s --help\n'
302 '\n' % (output_path, output_path))
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800303
304
Rong Chang6d65fad2014-08-22 16:00:12 +0800305def InitUmpire(exe_path, src_root, target_board):
306 """Inits Umpire server environment."""
307 if exe_path is None:
308 parent_cmdline = open('/proc/%s/cmdline' % os.getppid(),
309 'r').read().rstrip('\0').split('\0')
310
311 if parent_cmdline > 1 and parent_cmdline[0] == MAKESELF_SHELL:
312 # Get parent script name from parent process.
313 exe_path = parent_cmdline[1]
314 else:
315 # Set to default.
316 exe_path = TOOLKIT_NAME
317
318 if not exe_path.startswith('/'):
319 exe_path = os.path.join(os.environ.get('OLDPWD'), exe_path)
320
321 with file_utils.TempDirectory() as nano_bundle:
322 bundle_toolkit_dir = os.path.join(nano_bundle, 'factory_toolkit')
323 os.mkdir(bundle_toolkit_dir)
324 os.symlink(exe_path, os.path.join(bundle_toolkit_dir,
325 os.path.basename(exe_path)))
326 umpire_bin = os.path.join(src_root, 'usr', 'local', 'factory', 'bin',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800327 'umpire')
Rong Chang6d65fad2014-08-22 16:00:12 +0800328 Spawn([umpire_bin, 'init', '--board', target_board, nano_bundle],
329 check_call=True, log=True)
330 print ('\n'
Hung-Te Lin56b18402015-01-16 14:52:30 +0800331 ' Umpire initialized successfully. Upstart service is running:\n'
332 ' umpire BOARD=%(board)s.\n'
333 ' For more information, please check umpire command line:\n'
334 '\n'
335 ' umpire-%(board)s --help (if your id is in umpire group)\n'
336 ' or sudo umpire-%(board)s --help\n'
337 '\n' % {'board': target_board})
Rong Chang6d65fad2014-08-22 16:00:12 +0800338
339
Wei-Ning Huang4855e792015-06-11 15:33:39 +0800340def ExtractOverlord(src_root, output_dir):
341 output_dir = os.path.join(output_dir, 'overlord')
342 try:
343 os.makedirs(output_dir)
344 except OSError as e:
345 print str(e)
346 return
347
348 # Copy overlord binary and resource files
349 shutil.copyfile(os.path.join(src_root, 'usr/bin/overlordd'),
350 os.path.join(output_dir, 'overlordd'))
351 shutil.copytree(os.path.join(src_root, 'usr/share/overlord/app'),
352 os.path.join(output_dir, 'app'))
353
354 # Give overlordd execution permission
355 os.chmod(os.path.join(output_dir, 'overlordd'), 0755)
356 print "Extarcted overlord under '%s'" % output_dir
357
358
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800359def main():
Jon Salz4f3ade52014-02-20 17:55:09 +0800360 import logging
361 logging.basicConfig(level=logging.INFO)
362
363 # In order to determine which usage message to show, first determine
364 # whether we're in the self-extracting archive. Do this first
365 # because we need it to even parse the arguments.
366 if '--in-exe' in sys.argv:
367 sys.argv = [x for x in sys.argv if x != '--in-exe']
368 in_archive = True
369 else:
370 in_archive = False
371
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800372 parser = argparse.ArgumentParser(
Jon Salz4f3ade52014-02-20 17:55:09 +0800373 description=HELP_HEADER + HELP_HEADER_ADVANCED,
374 usage=('install_factory_toolkit.run -- [options]' if in_archive
375 else None),
376 formatter_class=argparse.RawDescriptionHelpFormatter)
Hung-Te Lin56b18402015-01-16 14:52:30 +0800377 parser.add_argument(
378 'dest', nargs='?', default='/',
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800379 help='A test image or the mount point of the stateful partition. '
380 "If omitted, install to live system, i.e. '/'.")
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800381 parser.add_argument('--no-enable', '-n', action='store_true',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800382 help="Don't enable factory tests after installing")
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800383 parser.add_argument('--yes', '-y', action='store_true',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800384 help="Don't ask for confirmation")
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800385 parser.add_argument('--build-info', action='store_true',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800386 help='Print build information and exit')
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800387 parser.add_argument('--pack-into', metavar='NEW_TOOLKIT',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800388 help='Pack the files into a new factory toolkit')
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800389 parser.add_argument('--repack', metavar='UNPACKED_TOOLKIT',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800390 help='Repack from previously unpacked toolkit')
Vic Yang7039f422014-07-07 15:38:13 -0700391
Peter Ammon948b7172014-07-15 12:43:06 -0700392 parser.add_argument('--enable-presenter', dest='enable_presenter',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800393 action='store_true',
394 help='Run goofy in presenter mode on startup')
Peter Ammon948b7172014-07-15 12:43:06 -0700395 parser.add_argument('--no-enable-presenter', dest='enable_presenter',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800396 action='store_false', help=argparse.SUPPRESS)
Vic Yang423c2722014-09-24 16:05:06 +0800397 parser.set_defaults(enable_presenter=True)
Vic Yang7039f422014-07-07 15:38:13 -0700398
Vic Yang70fdae92015-02-17 19:21:08 -0800399 parser.add_argument('--non-cros', dest='non_cros',
400 action='store_true',
401 help='Install on non-ChromeOS host.')
402
Vic Yang7039f422014-07-07 15:38:13 -0700403 parser.add_argument('--enable-device', dest='enable_device',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800404 action='store_true',
405 help='Run goofy in device mode on startup')
Vic Yang7039f422014-07-07 15:38:13 -0700406 parser.add_argument('--no-enable-device', dest='enable_device',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800407 action='store_false', help=argparse.SUPPRESS)
Vic Yang423c2722014-09-24 16:05:06 +0800408 parser.set_defaults(enable_device=True)
409
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800410 parser.add_argument('--device-id', dest='device_id', type=str, default=None,
411 help='Set device ID for this device')
412
Rong Chang6d65fad2014-08-22 16:00:12 +0800413 parser.add_argument('--init-umpire-board', dest='umpire_board',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800414 nargs='?', default=None,
415 help='Locally install Umpire server for specific board')
Rong Chang6d65fad2014-08-22 16:00:12 +0800416 parser.add_argument('--exe-path', dest='exe_path',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800417 nargs='?', default=None,
418 help='Current self-extracting archive pathname')
Wei-Ning Huang4855e792015-06-11 15:33:39 +0800419 parser.add_argument('--extract-overlord', dest='extract_overlord',
420 metavar='OUTPUT_DIR', type=str, default=None,
421 help='Extract overlord from the toolkit')
Vic Yang7039f422014-07-07 15:38:13 -0700422
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800423 args = parser.parse_args()
424
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800425 src_root = factory.FACTORY_PATH
426 for _ in xrange(3):
427 src_root = os.path.dirname(src_root)
428
Rong Chang6d65fad2014-08-22 16:00:12 +0800429 # --init-umpire-board creates a nano bundle, then calls umpire command
430 # line utility to install the server code and upstart configurations.
431 if args.umpire_board:
432 InitUmpire(args.exe_path, src_root, args.umpire_board)
433 return
434
Wei-Ning Huang4855e792015-06-11 15:33:39 +0800435 if args.extract_overlord is not None:
436 ExtractOverlord(src_root, args.extract_overlord)
437 return
438
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800439 # --pack-into may be called directly so this must be done before changing
440 # working directory to OLDPWD.
441 if args.pack_into and args.repack is None:
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800442 PackFactoryToolkit(src_root, args.pack_into, args.enable_device,
443 args.enable_presenter)
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800444 return
445
Jon Salz4f3ade52014-02-20 17:55:09 +0800446 if not in_archive:
447 # If you're not in the self-extracting archive, you're not allowed to
448 # do anything except the above --pack-into call.
449 parser.error('Not running from install_factory_toolkit.run; '
450 'only --pack-into (without --repack) is allowed')
451
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800452 # Change to original working directory in case the user specifies
453 # a relative path.
454 # TODO: Use USER_PWD instead when makeself is upgraded
455 os.chdir(os.environ['OLDPWD'])
456
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800457 if args.repack:
458 if args.pack_into is None:
459 parser.error('Must specify --pack-into when using --repack.')
460 Spawn([os.path.join(args.repack, INSTALLER_PATH),
461 '--pack-into', args.pack_into], check_call=True, log=True)
462 return
463
464 if args.build_info:
465 PrintBuildInfo(src_root)
466 return
467
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800468 if not os.path.exists(args.dest):
469 parser.error('Destination %s does not exist!' % args.dest)
470
471 patch_test_image = os.path.isfile(args.dest)
472
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800473 with (sys_utils.MountPartition(args.dest, 1, rw=True) if patch_test_image
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800474 else DummyContext(args.dest)) as dest:
Hung-Te Lin56b18402015-01-16 14:52:30 +0800475 installer = FactoryToolkitInstaller(
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800476 src=src_root, dest=dest, no_enable=args.no_enable,
477 enable_presenter=args.enable_presenter,
478 enable_device=args.enable_device, non_cros=args.non_cros,
479 device_id=args.device_id)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800480
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800481 print installer.WarningMessage(args.dest if patch_test_image else None)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800482
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800483 if not args.yes:
484 answer = raw_input('*** Continue? [y/N] ')
485 if not answer or answer[0] not in 'yY':
486 sys.exit('Aborting.')
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800487
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800488 installer.Install()
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800489
490if __name__ == '__main__':
491 main()