Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 1 | # Copyright (c) 2011 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 | """Implementation of the 'build' chromite command.""" |
| 6 | |
| 7 | # Python imports |
| 8 | import optparse |
| 9 | import os |
| 10 | |
| 11 | |
| 12 | # Local imports |
| 13 | import chromite.lib.cros_build_lib as cros_lib |
| 14 | from chromite.shell import utils |
| 15 | from chromite.shell import subcmd |
| 16 | |
| 17 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 18 | def _DoMakeChroot(chroot_config, clean_first): |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 19 | """Build the chroot, if needed. |
| 20 | |
| 21 | Args: |
| 22 | chroot_config: A SafeConfigParser representing the config for the chroot. |
| 23 | clean_first: Delete any old chroot first. |
| 24 | """ |
| 25 | # Skip this whole command if things already exist. |
| 26 | # TODO(dianders): Theoretically, calling make_chroot a second time is OK |
| 27 | # and "fixes up" the chroot. ...but build_packages will do the fixups |
| 28 | # anyway (I think), so this isn't that important. |
| 29 | chroot_dir = utils.GetChrootAbsDir(chroot_config) |
| 30 | if (not clean_first) and utils.DoesChrootExist(chroot_config): |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 31 | cros_lib.Info('%s already exists, skipping make_chroot.' % chroot_dir) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 32 | return |
| 33 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 34 | cros_lib.Info('MAKING THE CHROOT') |
| 35 | |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 36 | # Put together command. |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 37 | cmd_list = [ |
| 38 | './make_chroot', |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 39 | '--chroot="%s"' % chroot_dir, |
| 40 | chroot_config.get('CHROOT', 'make_chroot_flags'), |
| 41 | ] |
| 42 | if clean_first: |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 43 | cmd_list.insert(1, '--replace') |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 44 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 45 | # We're going convert to a string and force the shell to do all of the |
| 46 | # splitting of arguments, since we're throwing all of the flags from the |
| 47 | # config file in there. |
| 48 | cmd = ' '.join(cmd_list) |
| 49 | |
| 50 | # We'll put CWD as src/scripts when running the command. Since everyone |
| 51 | # running by hand has their cwd there, it is probably the safest. |
| 52 | cwd = os.path.join(utils.SRCROOT_PATH, 'src', 'scripts') |
| 53 | |
| 54 | # Run it. Exceptions will cause the program to exit. |
| 55 | cros_lib.RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 56 | |
| 57 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 58 | def _DoSetupBoard(build_config, clean_first): |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 59 | """Setup the board, if needed. |
| 60 | |
| 61 | This just runs the setup_board command with the proper args, if needed. |
| 62 | |
| 63 | Args: |
| 64 | build_config: A SafeConfigParser representing the build config. |
| 65 | clean_first: Delete any old board config first. |
| 66 | """ |
| 67 | # Skip this whole command if things already exist. |
| 68 | board_dir = utils.GetBoardDir(build_config) |
| 69 | if (not clean_first) and os.path.isdir(board_dir): |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 70 | cros_lib.Info('%s already exists, skipping setup_board.' % board_dir) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 71 | return |
| 72 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 73 | cros_lib.Info('SETTING UP THE BOARD') |
| 74 | |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 75 | # Put together command. |
| 76 | cmd_list = [ |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 77 | './setup_board', |
Doug Anderson | 6f53061 | 2011-02-11 13:19:25 -0800 | [diff] [blame] | 78 | '--board="%s"' % build_config.get('DEFAULT', 'target'), |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 79 | build_config.get('BUILD', 'setup_board_flags'), |
| 80 | ] |
| 81 | if clean_first: |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 82 | cmd_list.insert(1, '--force') |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 83 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 84 | # We're going convert to a string and force the shell to do all of the |
| 85 | # splitting of arguments, since we're throwing all of the flags from the |
| 86 | # config file in there. |
| 87 | cmd = ' '.join(cmd_list) |
| 88 | |
| 89 | # We'll put CWD as src/scripts when running the command. Since everyone |
| 90 | # running by hand has their cwd there, it is probably the safest. |
| 91 | cwd = os.path.join(utils.SRCROOT_PATH, 'src', 'scripts') |
| 92 | |
| 93 | # Run it. Exceptions will cause the program to exit. |
| 94 | cros_lib.RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 95 | |
| 96 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 97 | def _DoBuildPackages(build_config): |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 98 | """Build packages. |
| 99 | |
| 100 | This just runs the build_packages command with the proper args. |
| 101 | |
| 102 | Args: |
| 103 | build_config: A SafeConfigParser representing the build config. |
| 104 | """ |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 105 | cros_lib.Info('BUILDING PACKAGES') |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 106 | |
| 107 | # Put together command. We're going to force the shell to do all of the |
| 108 | # splitting of arguments, since we're throwing all of the flags from the |
| 109 | # config file in there. |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 110 | cmd = '%s ./build_packages --board="%s" %s' % ( |
| 111 | build_config.get('BUILD', 'build_packages_environ'), |
| 112 | build_config.get('DEFAULT', 'target'), |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 113 | build_config.get('BUILD', 'build_packages_flags') |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 114 | ) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 115 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 116 | # We'll put CWD as src/scripts when running the command. Since everyone |
| 117 | # running by hand has their cwd there, it is probably the safest. |
| 118 | cwd = os.path.join(utils.SRCROOT_PATH, 'src', 'scripts') |
| 119 | |
| 120 | # Run it. Exceptions will cause the program to exit. |
| 121 | cros_lib.RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 122 | |
| 123 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 124 | def _DoBuildImage(build_config): |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 125 | """Build an image. |
| 126 | |
| 127 | This just runs the build_image command with the proper args. |
| 128 | |
| 129 | Args: |
| 130 | build_config: A SafeConfigParser representing the build config. |
| 131 | """ |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 132 | cros_lib.Info('BUILDING THE IMAGE') |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 133 | |
| 134 | # Put together command. We're going to force the shell to do all of the |
| 135 | # splitting of arguments, since we're throwing all of the flags from the |
| 136 | # config file in there. |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 137 | cmd = '%s ./build_image --board="%s" %s' % ( |
| 138 | build_config.get('IMAGE', 'build_image_environ'), |
| 139 | build_config.get('DEFAULT', 'target'), |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 140 | build_config.get('IMAGE', 'build_image_flags') |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 141 | ) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 142 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 143 | # We'll put CWD as src/scripts when running the command. Since everyone |
| 144 | # running by hand has their cwd there, it is probably the safest. |
| 145 | cwd = os.path.join(utils.SRCROOT_PATH, 'src', 'scripts') |
| 146 | |
| 147 | # Run it. Exceptions will cause the program to exit. |
| 148 | cros_lib.RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 149 | |
| 150 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 151 | def _DoImagePostProcessing(build_config): |
Doug Anderson | 36f7542 | 2011-02-11 13:34:08 -0800 | [diff] [blame] | 152 | """Do post processing steps after the build image runs. |
| 153 | |
| 154 | Args: |
| 155 | build_config: A SafeConfigParser representing the build config. |
| 156 | """ |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 157 | # We'll put CWD as src/scripts when running the commands, since many of these |
| 158 | # legacy commands live in src/scripts. |
| 159 | # TODO(dianders): Don't set CWD once crosutils are properly installed. |
| 160 | cwd = os.path.join(utils.SRCROOT_PATH, 'src', 'scripts') |
| 161 | |
Doug Anderson | 36f7542 | 2011-02-11 13:34:08 -0800 | [diff] [blame] | 162 | # The user specifies a list of "steps" in this space-separated variable. |
| 163 | # We'll use each step name to construct other variable names to look for |
| 164 | # the actual commands. |
| 165 | steps = build_config.get('IMAGE', 'post_process_steps') |
| 166 | for step_name in steps.split(): |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 167 | cros_lib.Info('IMAGING POST-PROCESS: %s' % step_name) |
| 168 | |
Doug Anderson | 36f7542 | 2011-02-11 13:34:08 -0800 | [diff] [blame] | 169 | # Get the name of the variable that the user stored the cmd in. |
| 170 | cmd_var_name = 'post_process_%s_cmd' % step_name |
| 171 | |
| 172 | # Run the command. Exceptions will cause the program to exit. |
| 173 | cmd = build_config.get('IMAGE', cmd_var_name) |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 174 | cros_lib.RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True) |
Doug Anderson | 36f7542 | 2011-02-11 13:34:08 -0800 | [diff] [blame] | 175 | |
| 176 | |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 177 | class BuildCmd(subcmd.ChromiteCmd): |
| 178 | """Build the chroot (if needed), the packages for a target, and the image.""" |
| 179 | |
| 180 | def Run(self, raw_argv, chroot_config=None, |
| 181 | loaded_config=False, build_config=None): |
| 182 | """Run the command. |
| 183 | |
| 184 | Args: |
| 185 | raw_argv: Command line arguments, including this command's name, but not |
| 186 | the chromite command name or chromite options. |
| 187 | chroot_config: A SafeConfigParser for the chroot config; or None chromite |
| 188 | was called from within the chroot. |
| 189 | loaded_config: If True, we've already loaded the config. |
| 190 | build_config: None when called normally, but contains the SafeConfigParser |
| 191 | for the build config if we call ourselves with _DoEnterChroot(). Note |
| 192 | that even when called through _DoEnterChroot(), could still be None |
| 193 | if user chose 'HOST' as the target. |
| 194 | """ |
| 195 | # Parse options for command... |
| 196 | usage_str = ('usage: %%prog [chromite_options] %s [options] [target]' % |
| 197 | raw_argv[0]) |
| 198 | parser = optparse.OptionParser(usage=usage_str) |
| 199 | parser.add_option('--clean', default=False, action='store_true', |
| 200 | help='Clean before building.') |
| 201 | (options, argv) = parser.parse_args(raw_argv[1:]) |
| 202 | |
| 203 | # Load the build config if needed... |
| 204 | if not loaded_config: |
| 205 | argv, build_config = utils.GetBuildConfigFromArgs(argv) |
| 206 | if argv: |
| 207 | cros_lib.Die('Unknown arguments: %s' % ' '.join(argv)) |
| 208 | |
| 209 | if not cros_lib.IsInsideChroot(): |
| 210 | # Note: we only want to clean the chroot if they do --clean and have the |
| 211 | # host target. If they do --clean and have a board target, it means |
| 212 | # that they just want to clean the board... |
| 213 | want_clean_chroot = options.clean and build_config is None |
| 214 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 215 | _DoMakeChroot(chroot_config, want_clean_chroot) |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 216 | |
| 217 | if build_config is not None: |
| 218 | utils.EnterChroot(chroot_config, (self, 'Run'), raw_argv, |
| 219 | build_config=build_config, loaded_config=True) |
| 220 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 221 | cros_lib.Info('Done building.') |
Doug Anderson | a9b1090 | 2011-02-01 17:54:31 -0800 | [diff] [blame] | 222 | else: |
| 223 | if build_config is None: |
| 224 | cros_lib.Die("You can't build the host chroot from within the chroot.") |
| 225 | |
David James | 0315636 | 2011-03-04 20:28:26 -0800 | [diff] [blame] | 226 | _DoSetupBoard(build_config, options.clean) |
| 227 | _DoBuildPackages(build_config) |
| 228 | _DoBuildImage(build_config) |
| 229 | _DoImagePostProcessing(build_config) |