blob: 7bc999614364f4d118b973a5de654ca7855af23d [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
Vic Yang196d5242014-08-05 13:51:35 +080025from cros.factory.test import utils
Jon Salz25590302014-07-11 16:07:20 +080026from cros.factory.tools import install_symlinks
Rong Chang6d65fad2014-08-22 16:00:12 +080027from cros.factory.utils import file_utils
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +080028from cros.factory.utils.process_utils import Spawn
Hung-Te Lincdc2a042014-08-27 13:05:16 +080029from cros.factory.utils.sys_utils import MountPartition
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +080030
31
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +080032INSTALLER_PATH = 'usr/local/factory/py/toolkit/installer.py'
Rong Chang6d65fad2014-08-22 16:00:12 +080033MAKESELF_SHELL = '/bin/sh'
34TOOLKIT_NAME = 'install_factory_toolkit.run'
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +080035
Jon Salz4f3ade52014-02-20 17:55:09 +080036# Short and sweet help header for the executable generated by makeself.
37HELP_HEADER = """
38Installs the factory toolkit, transforming a test image into a factory test
39image. You can:
40
41- Install the factory toolkit on a CrOS device that is running a test
42 image. To do this, copy install_factory_toolkit.run to the device and
43 run it. The factory tests will then come up on the next boot.
44
45 rsync -a install_factory_toolkit.run crosdevice:/tmp
46 ssh crosdevice '/tmp/install_factory_toolkit.run && sync && reboot'
47
48- Modify a test image, turning it into a factory test image. When you
49 use the image on a device, the factory tests will come up.
50
51 install_factory_toolkit.run chromiumos_test_image.bin
52"""
53
54HELP_HEADER_ADVANCED = """
55- (advanced) Modify a mounted stateful partition, turning it into a factory
56 test image. This is equivalent to the previous command:
57
58 mount_partition -rw chromiumos_test_image.bin 1 /mnt/stateful
59 install_factory_toolkit.run /mnt/stateful
60 umount /mnt/stateful
61
62- (advanced) Unpack the factory toolkit, modify a file, and then repack it.
63
64 # Unpack but don't actually install
65 install_factory_toolkit.run --target /tmp/toolkit --noexec
66 # Edit some files in /tmp/toolkit
67 emacs /tmp/toolkit/whatever
68 # Repack
69 install_factory_toolkit.run -- --repack /tmp/toolkit \\
70 --pack-into /path/to/new/install_factory_toolkit.run
71"""
72
73# The makeself-generated header comes next. This is a little confusing,
74# so explain.
75HELP_HEADER_MAKESELF = """
76For complete usage information and advanced operations, run
77"install_factory_toolkit.run -- --help" (note the extra "--").
78
79Following is the help message from makeself, which was used to create
80this self-extracting archive.
81
82-----
83"""
84
Vic Yang196d5242014-08-05 13:51:35 +080085# The method to determine whether running on Chrome OS device or not.
86# Override this for unit testing.
87_in_cros_device = utils.in_cros_device
88
Vic Yangdb1e20e2014-10-05 12:10:33 +080089SERVER_FILE_MASK = [
90 # Exclude Umpire server but keep Umpire client
91 '--include', 'py/umpire/__init__.*',
92 '--include', 'py/umpire/common.*',
93 '--include', 'py/umpire/client',
94 '--include', 'py/umpire/client/**',
95 '--exclude', 'py/umpire/**',
96
97 # Lumberjack is only used on Umpire server
98 '--exclude', 'py/lumberjack'
99]
100
Jon Salz4f3ade52014-02-20 17:55:09 +0800101
Hung-Te Lin7b596ff2015-01-16 20:19:15 +0800102class FactoryToolkitInstaller(object):
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800103 """Factory toolkit installer.
104
105 Args:
106 src: Source path containing usr/ and var/.
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800107 dest: Installation destination path. Set this to the mount point of the
108 stateful partition if patching a test image.
109 no_enable: True to not install the tag file.
110 system_root: The path to the root of the file system. This must be left
111 as its default value except for unit testing.
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800112 """
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800113
Jon Salzb7e44262014-05-07 15:53:37 +0800114 # Whether to sudo when rsyncing; set to False for testing.
115 _sudo = True
116
Peter Ammon948b7172014-07-15 12:43:06 -0700117 def __init__(self, src, dest, no_enable, enable_presenter,
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800118 enable_device, non_cros=False, device_id=None, system_root='/'):
Jon Salz4f3ade52014-02-20 17:55:09 +0800119 self._src = src
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800120 self._system_root = system_root
121 if dest == self._system_root:
122 self._usr_local_dest = os.path.join(dest, 'usr', 'local')
123 self._var_dest = os.path.join(dest, 'var')
Jon Salz4f3ade52014-02-20 17:55:09 +0800124
125 # Make sure we're on a CrOS device.
Vic Yang70fdae92015-02-17 19:21:08 -0800126 if not non_cros and not _in_cros_device():
Jon Salz4f3ade52014-02-20 17:55:09 +0800127 sys.stderr.write(
Vic Yang196d5242014-08-05 13:51:35 +0800128 "ERROR: You're not on a CrOS device (for more details, please\n"
Hung-Te Lin56b18402015-01-16 14:52:30 +0800129 'check utils.py:in_cros_device), so you must specify a test\n'
130 'image or a mounted stateful partition on which to install the\n'
131 'factory toolkit. Please run\n'
132 '\n'
133 ' install_factory_toolkit.run -- --help\n'
134 '\n'
Vic Yang70fdae92015-02-17 19:21:08 -0800135 'for help.\n'
136 '\n'
137 'If you want to install the presenter on a non-CrOS host,\n'
138 'please run\n'
139 '\n'
140 ' install_factory_toolkit.run -- \\\n'
141 ' --non-cros --no-enable-device --enable-presenter\n'
142 '\n')
Jon Salz4f3ade52014-02-20 17:55:09 +0800143 sys.exit(1)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800144 if os.getuid() != 0:
Jon Salz4f3ade52014-02-20 17:55:09 +0800145 raise Exception('You must be root to install the factory toolkit on a '
146 'CrOS device.')
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800147 else:
148 self._usr_local_dest = os.path.join(dest, 'dev_image')
149 self._var_dest = os.path.join(dest, 'var_overlay')
150 if (not os.path.exists(self._usr_local_dest) or
151 not os.path.exists(self._var_dest)):
152 raise Exception(
153 'The destination path %s is not a stateful partition!' % dest)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800154
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800155 self._dest = dest
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800156 self._usr_local_src = os.path.join(src, 'usr', 'local')
157 self._var_src = os.path.join(src, 'var')
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800158 self._no_enable = no_enable
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800159 self._tag_file = os.path.join(self._usr_local_dest, 'factory', 'enabled')
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800160
Peter Ammon948b7172014-07-15 12:43:06 -0700161 self._enable_presenter = enable_presenter
162 self._presenter_tag_file = os.path.join(self._usr_local_dest, 'factory',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800163 'init', 'run_goofy_presenter')
Vic Yang7039f422014-07-07 15:38:13 -0700164
165 self._enable_device = enable_device
Ricky Liangd7716912014-07-10 11:52:24 +0800166 self._device_tag_file = os.path.join(self._usr_local_dest, 'factory',
167 'init', 'run_goofy_device')
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800168 self._device_id = device_id
Vic Yang7039f422014-07-07 15:38:13 -0700169
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800170 if (not os.path.exists(self._usr_local_src) or
171 not os.path.exists(self._var_src)):
172 raise Exception(
173 'This installer must be run from within the factory toolkit!')
174
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800175 def WarningMessage(self, target_test_image=None):
Jon Salz4f3ade52014-02-20 17:55:09 +0800176 with open(os.path.join(self._src, 'VERSION')) as f:
177 ret = f.read()
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800178 if target_test_image:
Jon Salz4f3ade52014-02-20 17:55:09 +0800179 ret += (
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800180 '\n'
181 '\n'
Jon Salz4f3ade52014-02-20 17:55:09 +0800182 '*** You are about to patch the factory toolkit into:\n'
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800183 '*** %s\n'
184 '***' % target_test_image)
185 else:
Jon Salz4f3ade52014-02-20 17:55:09 +0800186 ret += (
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800187 '\n'
188 '\n'
Jon Salz4f3ade52014-02-20 17:55:09 +0800189 '*** You are about to install the factory toolkit to:\n'
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800190 '*** %s\n'
191 '***' % self._dest)
192 if self._dest == self._system_root:
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800193 if self._no_enable:
Hung-Te Lin7b596ff2015-01-16 20:19:15 +0800194 ret += ('\n*** Factory tests will be disabled after this process is '
Hung-Te Lin56b18402015-01-16 14:52:30 +0800195 'done, but\n*** you can enable them by creating the factory '
196 'enabled tag:\n*** %s\n***' % self._tag_file)
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800197 else:
Hung-Te Lin7b596ff2015-01-16 20:19:15 +0800198 ret += ('\n*** After this process is done, your device will start '
Hung-Te Lin56b18402015-01-16 14:52:30 +0800199 'factory\n*** tests on the next reboot.\n***\n*** Factory '
200 'tests can be disabled by deleting the factory enabled\n*** '
201 'tag:\n*** %s\n***' % self._tag_file)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800202 return ret
203
Vic Yang7039f422014-07-07 15:38:13 -0700204 def _SetTagFile(self, name, path, enabled):
205 """Install or remove a tag file."""
206 if enabled:
207 print '*** Installing %s enabled tag...' % name
208 Spawn(['touch', path], sudo=True, log=True, check_call=True)
Ricky Liang8c88a122014-07-11 21:21:22 +0800209 Spawn(['chmod', 'go+r', path], sudo=True, log=True, check_call=True)
Vic Yang7039f422014-07-07 15:38:13 -0700210 else:
211 print '*** Removing %s enabled tag...' % name
212 Spawn(['rm', '-f', path], sudo=True, log=True, check_call=True)
213
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800214 def _SetDeviceID(self):
215 if self._device_id is not None:
216 with open(os.path.join(event_log.DEVICE_ID_PATH), 'w') as f:
217 f.write(self._device_id)
218
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800219 def Install(self):
220 print '*** Installing factory toolkit...'
Jon Salzb7e44262014-05-07 15:53:37 +0800221 for src, dest in ((self._usr_local_src, self._usr_local_dest),
222 (self._var_src, self._var_dest)):
223 # Change the source directory to root, and add group/world read
224 # permissions. This is necessary because when the toolkit was
225 # unpacked, the user may not have been root so the permessions
226 # may be hosed. This is skipped for testing.
Peter Ammon5ac58422014-06-09 14:45:50 -0700227 # --force is necessary to allow goofy directory from prior
228 # toolkit installations to be overwritten by the goofy symlink.
Ricky Liang5e95be22014-07-09 12:52:07 +0800229 try:
230 if self._sudo:
231 Spawn(['chown', '-R', 'root', src],
232 sudo=True, log=True, check_call=True)
233 Spawn(['chmod', '-R', 'go+rX', src],
234 sudo=True, log=True, check_call=True)
235 print '*** %s -> %s' % (src, dest)
Hung-Te Lin56b18402015-01-16 14:52:30 +0800236 Spawn(['rsync', '-a', '--force'] + SERVER_FILE_MASK +
Vic Yangdb1e20e2014-10-05 12:10:33 +0800237 [src + '/', dest], sudo=self._sudo, log=True,
238 check_output=True, cwd=src)
Ricky Liang5e95be22014-07-09 12:52:07 +0800239 finally:
240 # Need to change the source directory back to the original user, or the
241 # script in makeself will fail to remove the temporary source directory.
242 if self._sudo:
243 myuser = os.environ.get('USER')
244 Spawn(['chown', '-R', myuser, src],
245 sudo=True, log=True, check_call=True)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800246
Jon Salz25590302014-07-11 16:07:20 +0800247 print '*** Installing symlinks...'
248 install_symlinks.InstallSymlinks(
249 '../factory/bin',
250 os.path.join(self._usr_local_dest, 'bin'),
251 install_symlinks.MODE_FULL,
252 sudo=self._sudo)
253
254 print '*** Removing factory-mini...'
255 Spawn(['rm', '-rf', os.path.join(self._usr_local_dest, 'factory-mini')],
256 sudo=self._sudo, log=True, check_call=True)
257
Vic Yang7039f422014-07-07 15:38:13 -0700258 self._SetTagFile('factory', self._tag_file, not self._no_enable)
Peter Ammon948b7172014-07-15 12:43:06 -0700259 self._SetTagFile('presenter', self._presenter_tag_file,
260 self._enable_presenter)
Vic Yang7039f422014-07-07 15:38:13 -0700261 self._SetTagFile('device', self._device_tag_file, self._enable_device)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800262
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800263 self._SetDeviceID()
264
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800265 print '*** Installation completed.'
266
267
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800268@contextmanager
269def DummyContext(arg):
270 """A context manager that simply yields its argument."""
271 yield arg
272
273
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800274def PrintBuildInfo(src_root):
275 """Print build information."""
276 info_file = os.path.join(src_root, 'REPO_STATUS')
277 if not os.path.exists(info_file):
278 raise OSError('Build info file not found!')
279 with open(info_file, 'r') as f:
280 print f.read()
281
282
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800283def PackFactoryToolkit(src_root, output_path, enable_device, enable_presenter):
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800284 """Packs the files containing this script into a factory toolkit."""
285 with open(os.path.join(src_root, 'VERSION'), 'r') as f:
286 version = f.read().strip()
Jon Salz4f3ade52014-02-20 17:55:09 +0800287 with tempfile.NamedTemporaryFile() as help_header:
Hung-Te Lin56b18402015-01-16 14:52:30 +0800288 help_header.write(version + '\n' + HELP_HEADER + HELP_HEADER_MAKESELF)
Jon Salz4f3ade52014-02-20 17:55:09 +0800289 help_header.flush()
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800290 cmd = [os.path.join(src_root, 'makeself.sh'), '--bzip2', '--nox11',
Jon Salz4f3ade52014-02-20 17:55:09 +0800291 '--help-header', help_header.name,
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800292 src_root, output_path, version, INSTALLER_PATH, '--in-exe']
293 if not enable_device:
294 cmd.append('--no-enable-device')
295 if not enable_presenter:
296 cmd.append('--no-enable-presenter')
297 Spawn(cmd, check_call=True, log=True)
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800298 print ('\n'
Hung-Te Lin56b18402015-01-16 14:52:30 +0800299 ' Factory toolkit generated at %s.\n'
300 '\n'
301 ' To install factory toolkit on a live device running a test image,\n'
302 ' copy this to the device and execute it as root.\n'
303 '\n'
304 ' Alternatively, the factory toolkit can be used to patch a test\n'
305 ' image. For more information, run:\n'
306 ' %s --help\n'
307 '\n' % (output_path, output_path))
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800308
309
Rong Chang6d65fad2014-08-22 16:00:12 +0800310def InitUmpire(exe_path, src_root, target_board):
311 """Inits Umpire server environment."""
312 if exe_path is None:
313 parent_cmdline = open('/proc/%s/cmdline' % os.getppid(),
314 'r').read().rstrip('\0').split('\0')
315
316 if parent_cmdline > 1 and parent_cmdline[0] == MAKESELF_SHELL:
317 # Get parent script name from parent process.
318 exe_path = parent_cmdline[1]
319 else:
320 # Set to default.
321 exe_path = TOOLKIT_NAME
322
323 if not exe_path.startswith('/'):
324 exe_path = os.path.join(os.environ.get('OLDPWD'), exe_path)
325
326 with file_utils.TempDirectory() as nano_bundle:
327 bundle_toolkit_dir = os.path.join(nano_bundle, 'factory_toolkit')
328 os.mkdir(bundle_toolkit_dir)
329 os.symlink(exe_path, os.path.join(bundle_toolkit_dir,
330 os.path.basename(exe_path)))
331 umpire_bin = os.path.join(src_root, 'usr', 'local', 'factory', 'bin',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800332 'umpire')
Rong Chang6d65fad2014-08-22 16:00:12 +0800333 Spawn([umpire_bin, 'init', '--board', target_board, nano_bundle],
334 check_call=True, log=True)
335 print ('\n'
Hung-Te Lin56b18402015-01-16 14:52:30 +0800336 ' Umpire initialized successfully. Upstart service is running:\n'
337 ' umpire BOARD=%(board)s.\n'
338 ' For more information, please check umpire command line:\n'
339 '\n'
340 ' umpire-%(board)s --help (if your id is in umpire group)\n'
341 ' or sudo umpire-%(board)s --help\n'
342 '\n' % {'board': target_board})
Rong Chang6d65fad2014-08-22 16:00:12 +0800343
344
Wei-Ning Huang4855e792015-06-11 15:33:39 +0800345def ExtractOverlord(src_root, output_dir):
346 output_dir = os.path.join(output_dir, 'overlord')
347 try:
348 os.makedirs(output_dir)
349 except OSError as e:
350 print str(e)
351 return
352
353 # Copy overlord binary and resource files
354 shutil.copyfile(os.path.join(src_root, 'usr/bin/overlordd'),
355 os.path.join(output_dir, 'overlordd'))
356 shutil.copytree(os.path.join(src_root, 'usr/share/overlord/app'),
357 os.path.join(output_dir, 'app'))
358
359 # Give overlordd execution permission
360 os.chmod(os.path.join(output_dir, 'overlordd'), 0755)
361 print "Extarcted overlord under '%s'" % output_dir
362
363
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800364def main():
Jon Salz4f3ade52014-02-20 17:55:09 +0800365 import logging
366 logging.basicConfig(level=logging.INFO)
367
368 # In order to determine which usage message to show, first determine
369 # whether we're in the self-extracting archive. Do this first
370 # because we need it to even parse the arguments.
371 if '--in-exe' in sys.argv:
372 sys.argv = [x for x in sys.argv if x != '--in-exe']
373 in_archive = True
374 else:
375 in_archive = False
376
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800377 parser = argparse.ArgumentParser(
Jon Salz4f3ade52014-02-20 17:55:09 +0800378 description=HELP_HEADER + HELP_HEADER_ADVANCED,
379 usage=('install_factory_toolkit.run -- [options]' if in_archive
380 else None),
381 formatter_class=argparse.RawDescriptionHelpFormatter)
Hung-Te Lin56b18402015-01-16 14:52:30 +0800382 parser.add_argument(
383 'dest', nargs='?', default='/',
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800384 help='A test image or the mount point of the stateful partition. '
385 "If omitted, install to live system, i.e. '/'.")
Vic (Chun-Ju) Yang7cc3e672014-01-20 14:06:39 +0800386 parser.add_argument('--no-enable', '-n', action='store_true',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800387 help="Don't enable factory tests after installing")
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800388 parser.add_argument('--yes', '-y', action='store_true',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800389 help="Don't ask for confirmation")
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800390 parser.add_argument('--build-info', action='store_true',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800391 help='Print build information and exit')
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800392 parser.add_argument('--pack-into', metavar='NEW_TOOLKIT',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800393 help='Pack the files into a new factory toolkit')
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800394 parser.add_argument('--repack', metavar='UNPACKED_TOOLKIT',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800395 help='Repack from previously unpacked toolkit')
Vic Yang7039f422014-07-07 15:38:13 -0700396
Peter Ammon948b7172014-07-15 12:43:06 -0700397 parser.add_argument('--enable-presenter', dest='enable_presenter',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800398 action='store_true',
399 help='Run goofy in presenter mode on startup')
Peter Ammon948b7172014-07-15 12:43:06 -0700400 parser.add_argument('--no-enable-presenter', dest='enable_presenter',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800401 action='store_false', help=argparse.SUPPRESS)
Vic Yang423c2722014-09-24 16:05:06 +0800402 parser.set_defaults(enable_presenter=True)
Vic Yang7039f422014-07-07 15:38:13 -0700403
Vic Yang70fdae92015-02-17 19:21:08 -0800404 parser.add_argument('--non-cros', dest='non_cros',
405 action='store_true',
406 help='Install on non-ChromeOS host.')
407
Vic Yang7039f422014-07-07 15:38:13 -0700408 parser.add_argument('--enable-device', dest='enable_device',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800409 action='store_true',
410 help='Run goofy in device mode on startup')
Vic Yang7039f422014-07-07 15:38:13 -0700411 parser.add_argument('--no-enable-device', dest='enable_device',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800412 action='store_false', help=argparse.SUPPRESS)
Vic Yang423c2722014-09-24 16:05:06 +0800413 parser.set_defaults(enable_device=True)
414
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800415 parser.add_argument('--device-id', dest='device_id', type=str, default=None,
416 help='Set device ID for this device')
417
Rong Chang6d65fad2014-08-22 16:00:12 +0800418 parser.add_argument('--init-umpire-board', dest='umpire_board',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800419 nargs='?', default=None,
420 help='Locally install Umpire server for specific board')
Rong Chang6d65fad2014-08-22 16:00:12 +0800421 parser.add_argument('--exe-path', dest='exe_path',
Hung-Te Lin56b18402015-01-16 14:52:30 +0800422 nargs='?', default=None,
423 help='Current self-extracting archive pathname')
Wei-Ning Huang4855e792015-06-11 15:33:39 +0800424 parser.add_argument('--extract-overlord', dest='extract_overlord',
425 metavar='OUTPUT_DIR', type=str, default=None,
426 help='Extract overlord from the toolkit')
Vic Yang7039f422014-07-07 15:38:13 -0700427
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800428 args = parser.parse_args()
429
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800430 src_root = factory.FACTORY_PATH
431 for _ in xrange(3):
432 src_root = os.path.dirname(src_root)
433
Rong Chang6d65fad2014-08-22 16:00:12 +0800434 # --init-umpire-board creates a nano bundle, then calls umpire command
435 # line utility to install the server code and upstart configurations.
436 if args.umpire_board:
437 InitUmpire(args.exe_path, src_root, args.umpire_board)
438 return
439
Wei-Ning Huang4855e792015-06-11 15:33:39 +0800440 if args.extract_overlord is not None:
441 ExtractOverlord(src_root, args.extract_overlord)
442 return
443
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800444 # --pack-into may be called directly so this must be done before changing
445 # working directory to OLDPWD.
446 if args.pack_into and args.repack is None:
Wei-Ning Huangb723d7f2014-11-17 17:26:32 +0800447 PackFactoryToolkit(src_root, args.pack_into, args.enable_device,
448 args.enable_presenter)
Vic (Chun-Ju) Yang98b4fbc2014-02-18 19:32:32 +0800449 return
450
Jon Salz4f3ade52014-02-20 17:55:09 +0800451 if not in_archive:
452 # If you're not in the self-extracting archive, you're not allowed to
453 # do anything except the above --pack-into call.
454 parser.error('Not running from install_factory_toolkit.run; '
455 'only --pack-into (without --repack) is allowed')
456
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800457 # Change to original working directory in case the user specifies
458 # a relative path.
459 # TODO: Use USER_PWD instead when makeself is upgraded
460 os.chdir(os.environ['OLDPWD'])
461
Vic (Chun-Ju) Yangb7388f72014-02-19 15:22:58 +0800462 if args.repack:
463 if args.pack_into is None:
464 parser.error('Must specify --pack-into when using --repack.')
465 Spawn([os.path.join(args.repack, INSTALLER_PATH),
466 '--pack-into', args.pack_into], check_call=True, log=True)
467 return
468
469 if args.build_info:
470 PrintBuildInfo(src_root)
471 return
472
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800473 if not os.path.exists(args.dest):
474 parser.error('Destination %s does not exist!' % args.dest)
475
476 patch_test_image = os.path.isfile(args.dest)
477
478 with (MountPartition(args.dest, 1, rw=True) if patch_test_image
479 else DummyContext(args.dest)) as dest:
Hung-Te Lin56b18402015-01-16 14:52:30 +0800480 installer = FactoryToolkitInstaller(
Wei-Ning Huang5135b7e2015-07-03 17:31:15 +0800481 src=src_root, dest=dest, no_enable=args.no_enable,
482 enable_presenter=args.enable_presenter,
483 enable_device=args.enable_device, non_cros=args.non_cros,
484 device_id=args.device_id)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800485
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800486 print installer.WarningMessage(args.dest if patch_test_image else None)
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800487
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800488 if not args.yes:
489 answer = raw_input('*** Continue? [y/N] ')
490 if not answer or answer[0] not in 'yY':
491 sys.exit('Aborting.')
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800492
Vic (Chun-Ju) Yang469592b2014-02-18 19:15:41 +0800493 installer.Install()
Vic (Chun-Ju) Yang296871a2014-01-13 12:05:18 +0800494
495if __name__ == '__main__':
496 main()