Vic (Chun-Ju) Yang | 296871a | 2014-01-13 12:05:18 +0800 | [diff] [blame] | 1 | #!/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 | |
| 9 | The factory toolkit is a self-extracting shellball containing factory test |
| 10 | related files and this installer. This installer is invoked when the toolkit |
| 11 | is deployed and is responsible for installing files. |
| 12 | """ |
| 13 | |
| 14 | |
| 15 | import argparse |
| 16 | import factory_common # pylint: disable=W0611 |
| 17 | import os |
| 18 | import subprocess |
| 19 | import sys |
| 20 | |
| 21 | from cros.factory.test import factory |
| 22 | |
| 23 | |
| 24 | class FactoryToolkitInstaller(): |
| 25 | """Factory toolkit installer. |
| 26 | |
| 27 | Args: |
| 28 | src: Source path containing usr/ and var/. |
| 29 | args: Arguments including |
| 30 | dest: Installation destination path. Set this to the mount point of the |
| 31 | stateful partition if patching a test image. |
| 32 | patch_test_image: True if patching a test image. |
| 33 | """ |
| 34 | def __init__(self, src, args): |
| 35 | if args.patch_test_image: |
| 36 | self._usr_local_dest = os.path.join(args.dest, 'dev_image', 'local') |
| 37 | self._var_dest = os.path.join(args.dest, 'var_overlay') |
| 38 | if (not os.path.exists(self._usr_local_dest) or |
| 39 | not os.path.exists(self._var_dest)): |
| 40 | raise Exception( |
| 41 | 'The destination path %s is not a stateful partition!' % args.dest) |
| 42 | else: |
| 43 | self._usr_local_dest = os.path.join(args.dest, 'usr', 'local') |
| 44 | self._var_dest = os.path.join(args.dest, 'var') |
| 45 | if os.getuid() != 0: |
| 46 | raise Exception('Must be root to install on live machine!') |
| 47 | if not os.path.exists('/etc/lsb-release'): |
| 48 | raise Exception('/etc/lsb-release is missing. ' |
| 49 | 'Are you running this in chroot?') |
| 50 | |
| 51 | self._patch_test_image = args.patch_test_image |
| 52 | self._dest = args.dest |
| 53 | self._usr_local_src = os.path.join(src, 'usr', 'local') |
| 54 | self._var_src = os.path.join(src, 'var') |
Vic (Chun-Ju) Yang | 7cc3e67 | 2014-01-20 14:06:39 +0800 | [diff] [blame^] | 55 | self._no_enable = args.no_enable |
| 56 | self._tag_file = os.path.join(self._usr_local_dest, 'factory', 'enabled') |
Vic (Chun-Ju) Yang | 296871a | 2014-01-13 12:05:18 +0800 | [diff] [blame] | 57 | |
| 58 | if (not os.path.exists(self._usr_local_src) or |
| 59 | not os.path.exists(self._var_src)): |
| 60 | raise Exception( |
| 61 | 'This installer must be run from within the factory toolkit!') |
| 62 | |
| 63 | def WarningMessage(self): |
| 64 | ret = ( |
| 65 | '\n' |
| 66 | '\n' |
| 67 | '*** You are about to install factory toolkit to:\n' |
| 68 | '*** %s\n' |
| 69 | '***' % self._dest) |
| 70 | if self._dest == '/': |
Vic (Chun-Ju) Yang | 7cc3e67 | 2014-01-20 14:06:39 +0800 | [diff] [blame^] | 71 | if self._no_enable: |
| 72 | ret += ('\n' |
| 73 | '*** Factory tests will be disabled after this process is done, but\n' |
| 74 | '*** you can enable them by creating factory enabled tag:\n' |
| 75 | '*** %s\n' |
| 76 | '***' % self._tag_file) |
| 77 | else: |
| 78 | ret += ('\n' |
| 79 | '*** After this process is done, your device will start factory\n' |
| 80 | '*** tests on the next reboot.\n' |
| 81 | '***\n' |
| 82 | '*** Factory tests can be disabled by deleting factory enabled tag:\n' |
| 83 | '*** %s\n' |
| 84 | '***' % self._tag_file) |
Vic (Chun-Ju) Yang | 296871a | 2014-01-13 12:05:18 +0800 | [diff] [blame] | 85 | return ret |
| 86 | |
| 87 | def _Rsync(self, src, dest): |
| 88 | print '*** %s -> %s' % (src, dest) |
| 89 | subprocess.check_call(['rsync', '-a', src + '/', dest]) |
| 90 | |
| 91 | def Install(self): |
| 92 | print '*** Installing factory toolkit...' |
| 93 | self._Rsync(self._usr_local_src, self._usr_local_dest) |
| 94 | self._Rsync(self._var_src, self._var_dest) |
| 95 | |
Vic (Chun-Ju) Yang | 7cc3e67 | 2014-01-20 14:06:39 +0800 | [diff] [blame^] | 96 | if self._no_enable: |
| 97 | print '*** Removing factory enabled tag...' |
| 98 | try: |
| 99 | os.unlink(self._tag_file) |
| 100 | except OSError: |
| 101 | pass |
| 102 | else: |
| 103 | print '*** Installing factory enabled tag...' |
| 104 | open(self._tag_file, 'w').close() |
Vic (Chun-Ju) Yang | 296871a | 2014-01-13 12:05:18 +0800 | [diff] [blame] | 105 | |
| 106 | print '*** Installation completed.' |
| 107 | |
| 108 | |
| 109 | def main(): |
| 110 | parser = argparse.ArgumentParser( |
| 111 | description='Factory toolkit installer.') |
| 112 | parser.add_argument('--dest', '-d', default='/', |
| 113 | help='Destination path. Mount point of stateful partition if patching ' |
| 114 | 'a test image.') |
| 115 | parser.add_argument('--patch-test-image', '-p', action='store_true', |
| 116 | help='Patching a test image instead of installing to live system.') |
Vic (Chun-Ju) Yang | 7cc3e67 | 2014-01-20 14:06:39 +0800 | [diff] [blame^] | 117 | parser.add_argument('--no-enable', '-n', action='store_true', |
| 118 | help="Don't enable factory tests after installing") |
Vic (Chun-Ju) Yang | 296871a | 2014-01-13 12:05:18 +0800 | [diff] [blame] | 119 | parser.add_argument('--yes', '-y', action='store_true', |
| 120 | help="Don't ask for confirmation") |
| 121 | args = parser.parse_args() |
| 122 | |
| 123 | try: |
| 124 | src_root = factory.FACTORY_PATH |
| 125 | for _ in xrange(3): |
| 126 | src_root = os.path.dirname(src_root) |
| 127 | installer = FactoryToolkitInstaller(src_root, args) |
| 128 | except Exception as e: |
| 129 | parser.error(e.message) |
| 130 | |
| 131 | print installer.WarningMessage() |
| 132 | |
| 133 | if not args.yes: |
| 134 | answer = raw_input('*** Continue? [y/N] ') |
| 135 | if not answer or answer[0] not in 'yY': |
| 136 | sys.exit('Aborting.') |
| 137 | |
| 138 | installer.Install() |
| 139 | |
| 140 | if __name__ == '__main__': |
| 141 | main() |