blob: dff2279f7ea08a6b2b3d52baa54bebc1afb89cbc [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2022 The ChromiumOS Authors
Ram Chandrasekar913c0422022-05-09 23:41:22 +00002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""build_image is used to build a Chromium OS image.
6
7Chromium OS comes in many different forms. This script can be used to build
8the following:
9
10base - Pristine Chromium OS image. As similar to Chrome OS as possible.
11dev [default] - Developer image. Like base but with additional dev packages.
12test - Like dev, but with additional test specific packages and can be easily
Alex Klein9e7b29e2023-04-11 16:10:31 -060013 used for automated testing using scripts like test_that, etc.
Ram Chandrasekar913c0422022-05-09 23:41:22 +000014factory_install - Install shim for bootstrapping the factory test process.
Alex Klein9e7b29e2023-04-11 16:10:31 -060015 Cannot be built along with any other image.
Ram Chandrasekar913c0422022-05-09 23:41:22 +000016
17Examples:
18
19build_image --board=<board> dev test - builds developer and test images.
20build_image --board=<board> factory_install - builds a factory install shim.
21
22Note if you want to build an image with custom size partitions, either consider
23adding a new disk layout in build_library/legacy_disk_layout.json OR use
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000024adjust-part. Here are a few examples:
Ram Chandrasekar913c0422022-05-09 23:41:22 +000025
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000026adjust-part='STATE:+1G' -- add one GB to the size the stateful partition
27adjust-part='ROOT-A:-1G' -- remove one GB from the primary rootfs partition
28adjust-part='STATE:=1G' -- make the stateful partition 1 GB
Ram Chandrasekar913c0422022-05-09 23:41:22 +000029"""
30
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000031import argparse
32import os
Ram Chandrasekar913c0422022-05-09 23:41:22 +000033from pathlib import Path
Cindy Lin0abfec02022-09-01 18:25:30 +000034import sys
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000035from typing import List, Optional, Tuple
Ram Chandrasekar913c0422022-05-09 23:41:22 +000036
37from chromite.lib import commandline
38from chromite.lib import constants
39from chromite.lib import cros_build_lib
Cindy Lin0abfec02022-09-01 18:25:30 +000040from chromite.lib import namespaces
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000041from chromite.service import image
Ram Chandrasekar158b32a2022-07-15 17:06:13 +000042from chromite.utils import timer
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000043
44
Ram Chandrasekarf005fa72022-06-16 21:45:14 +000045def build_shell_bool_style_args(
46 parser: commandline.ArgumentParser,
47 name: str,
48 default_val: bool,
49 help_str: str,
50 deprecation_note: str,
51 alternate_name: Optional[str] = None,
Alex Klein1699fab2022-09-08 08:46:06 -060052 additional_neg_options: Optional[List[str]] = None,
53) -> None:
54 """Build the shell boolean input argument equivalent.
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000055
Alex Klein1699fab2022-09-08 08:46:06 -060056 There are two cases which we will need to handle,
57 case 1: A shell boolean arg, which doesn't need to be re-worded in python.
58 case 2: A shell boolean arg, which needs to be re-worded in python.
59 Example below.
60 For Case 1, for a given input arg name 'argA', we create three python
61 arguments.
62 --argA, --noargA, --no-argA. The arguments --argA and --no-argA will be
63 retained after deprecating --noargA.
64 For Case 2, for a given input arg name 'arg_A' we need to use alternate
65 argument name 'arg-A'. we create four python arguments in this case.
66 --arg_A, --noarg_A, --arg-A, --no-arg-A. The first two arguments will be
67 deprecated later.
68 TODO(b/232566937): Remove the creation of --noargA in case 1 and --arg_A and
69 --noarg_A in case 2.
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000070
Alex Klein1699fab2022-09-08 08:46:06 -060071 Args:
Alex Klein9e7b29e2023-04-11 16:10:31 -060072 parser: The parser to update.
73 name: The input argument name. This will be used as 'dest' variable
74 name.
75 default_val: The default value to assign.
76 help_str: The help string for the input argument.
77 deprecation_note: A deprecation note to use.
78 alternate_name: Alternate argument to be used after deprecation.
79 additional_neg_options: Additional negative alias options to use.
Alex Klein1699fab2022-09-08 08:46:06 -060080 """
81 arg = f"--{name}"
82 shell_narg = f"--no{name}"
83 py_narg = f"--no-{name}"
84 alt_arg = f"--{alternate_name}" if alternate_name else None
85 alt_py_narg = f"--no-{alternate_name}" if alternate_name else None
86 default_val_str = f"{help_str} (Default: %(default)s)."
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +000087
Alex Klein1699fab2022-09-08 08:46:06 -060088 if alternate_name:
89 _alternate_narg_list = [alt_py_narg]
90 if additional_neg_options:
91 _alternate_narg_list.extend(additional_neg_options)
92
93 parser.add_argument(
94 alt_arg,
95 action="store_true",
96 default=default_val,
97 dest=name,
98 help=default_val_str,
99 )
100 parser.add_argument(
101 *_alternate_narg_list,
102 action="store_false",
103 dest=name,
104 help="Don't " + help_str.lower(),
105 )
Ram Chandrasekarf005fa72022-06-16 21:45:14 +0000106
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000107 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -0600108 arg,
109 action="store_true",
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000110 default=default_val,
111 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -0600112 deprecated=deprecation_note % alt_arg if alternate_name else None,
113 help=default_val_str if not alternate_name else argparse.SUPPRESS,
114 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000115 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -0600116 shell_narg,
117 action="store_false",
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000118 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -0600119 deprecated=deprecation_note
120 % (alt_py_narg if alternate_name else py_narg),
121 help=argparse.SUPPRESS,
122 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000123
Alex Klein1699fab2022-09-08 08:46:06 -0600124 if not alternate_name:
125 _py_narg_list = [py_narg]
126 if additional_neg_options:
127 _py_narg_list.extend(additional_neg_options)
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000128
Alex Klein1699fab2022-09-08 08:46:06 -0600129 parser.add_argument(
130 *_py_narg_list,
131 action="store_false",
132 dest=name,
133 help="Don't " + help_str.lower(),
134 )
135
136
137def build_shell_string_style_args(
138 parser: commandline.ArgumentParser,
139 name: str,
140 default_val: Optional[str],
141 help_str: str,
142 deprecation_note: str,
143 alternate_name: str,
144) -> None:
145 """Build the shell string input argument equivalent.
146
147 Args:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600148 parser: The parser to update.
149 name: The input argument name. This will be used as 'dest' variable
150 name.
151 default_val: The default value to assign.
152 help_str: The help string for the input argument.
153 deprecation_note: A deprecation note to use.
154 alternate_name: Alternate argument to be used after deprecation.
Alex Klein1699fab2022-09-08 08:46:06 -0600155 """
156 default_val_str = (
157 f"{help_str} (Default: %(default)s)." if default_val else help_str
158 )
Ram Chandrasekarf005fa72022-06-16 21:45:14 +0000159
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000160 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -0600161 f"--{alternate_name}",
162 dest=f"{name}",
163 default=default_val,
164 help=default_val_str,
165 )
166 parser.add_argument(
167 f"--{name}",
168 deprecated=deprecation_note % f"--{alternate_name}",
169 help=argparse.SUPPRESS,
170 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000171
172
173def get_parser() -> commandline.ArgumentParser:
Alex Klein1699fab2022-09-08 08:46:06 -0600174 """Creates the cmdline argparser, populates the options and description.
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000175
Alex Klein1699fab2022-09-08 08:46:06 -0600176 Returns:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600177 Argument parser.
Alex Klein1699fab2022-09-08 08:46:06 -0600178 """
179 deprecation_note = "Argument will be removed January, 2023. Use %s instead."
180 parser = commandline.ArgumentParser(description=__doc__)
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000181
Alex Klein1699fab2022-09-08 08:46:06 -0600182 parser.add_argument(
183 "-b",
184 "--board",
185 "--build-target",
186 dest="board",
187 default=cros_build_lib.GetDefaultBoard(),
188 help="The board to build images for.",
189 )
190 build_shell_string_style_args(
191 parser,
192 "adjust_part",
193 None,
194 "Adjustments to apply to partition table (LABEL:[+-=]SIZE) "
195 "e.g. ROOT-A:+1G.",
196 deprecation_note,
197 "adjust-partition",
198 )
199 build_shell_string_style_args(
200 parser,
201 "output_root",
202 Path(constants.DEFAULT_BUILD_ROOT) / "images",
203 "Directory in which to place image result directories "
204 "(named by version).",
205 deprecation_note,
206 "output-root",
207 )
208 build_shell_string_style_args(
209 parser,
210 "builder_path",
211 None,
212 "The build name to be installed on DUT during hwtest.",
213 deprecation_note,
214 "builder-path",
215 )
216 build_shell_string_style_args(
217 parser,
218 "disk_layout",
219 "default",
220 "The disk layout type to use for this image.",
221 deprecation_note,
222 "disk-layout",
223 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000224
Alex Klein1699fab2022-09-08 08:46:06 -0600225 # Kernel related options.
226 group = parser.add_argument_group("Kernel Options")
227 build_shell_string_style_args(
228 group,
229 "enable_serial",
230 None,
231 "Enable serial port for printks. Example values: ttyS0.",
232 deprecation_note,
233 "enable-serial",
234 )
235 group.add_argument(
236 "--kernel-loglevel",
237 type=int,
238 default=7,
239 help="The loglevel to add to the kernel command line. "
240 "(Default: %(default)s).",
241 )
242 group.add_argument(
243 "--loglevel",
244 dest="kernel_loglevel",
245 type=int,
246 deprecated=deprecation_note % "kernel-loglevel",
247 help=argparse.SUPPRESS,
248 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000249
Alex Klein1699fab2022-09-08 08:46:06 -0600250 # Bootloader related options.
251 group = parser.add_argument_group("Bootloader Options")
252 build_shell_string_style_args(
253 group,
254 "boot_args",
255 "noinitrd",
256 "Additional boot arguments to pass to the commandline.",
257 deprecation_note,
258 "boot-args",
259 )
260 build_shell_bool_style_args(
261 group,
262 "enable_bootcache",
263 False,
264 "Make all bootloaders to use boot cache.",
265 deprecation_note,
266 "enable-bootcache",
267 )
268 build_shell_bool_style_args(
269 group,
270 "enable_rootfs_verification",
271 True,
272 "Make all bootloaders to use kernel based root-fs integrity checking.",
273 deprecation_note,
274 "enable-rootfs-verification",
275 ["-r"],
276 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000277
Alex Klein1699fab2022-09-08 08:46:06 -0600278 # Advanced options.
279 group = parser.add_argument_group("Advanced Options")
280 group.add_argument(
281 "--build-attempt",
282 type=int,
283 default=1,
284 help="The build attempt for this image build. (Default: %(default)s).",
285 )
286 group.add_argument(
287 "--build_attempt",
288 type=int,
289 deprecated=deprecation_note % "build-attempt",
290 help=argparse.SUPPRESS,
291 )
292 build_shell_string_style_args(
293 group,
294 "build_root",
295 Path(constants.DEFAULT_BUILD_ROOT) / "images",
296 "Directory in which to compose the image, before copying it to "
297 "output_root.",
298 deprecation_note,
299 "build-root",
300 )
301 group.add_argument(
302 "-j",
303 "--jobs",
304 dest="jobs",
305 type=int,
306 default=os.cpu_count(),
307 help="Number of packages to build in parallel at maximum. "
308 "(Default: %(default)s).",
309 )
310 build_shell_bool_style_args(
311 group,
312 "replace",
313 False,
314 "Overwrite existing output, if any.",
315 deprecation_note,
316 )
317 group.add_argument(
318 "--symlink",
319 default="latest",
320 help="Symlink name to use for this image. (Default: %(default)s).",
321 )
322 group.add_argument(
323 "--version",
324 default=None,
325 help="Overrides version number in name to this version.",
326 )
327 build_shell_string_style_args(
328 group,
329 "output_suffix",
330 None,
331 "Add custom suffix to output directory.",
332 deprecation_note,
333 "output-suffix",
334 )
335 group.add_argument(
336 "--eclean",
337 action="store_true",
338 default=True,
339 dest="eclean",
340 deprecated=(
341 "eclean is being removed from build_images. Argument will be "
342 "removed January, 2023."
343 ),
344 help=argparse.SUPPRESS,
345 )
346 group.add_argument(
347 "--noeclean",
348 action="store_false",
349 dest="eclean",
350 deprecated=(
351 "eclean is being removed from build_images. Argument will be "
352 "removed January, 2023."
353 ),
354 help=argparse.SUPPRESS,
355 )
356 group.add_argument(
357 "--no-eclean",
358 action="store_false",
359 dest="eclean",
360 deprecated=(
361 "eclean is being removed from build_images. Argument will be "
362 "removed January, 2023."
363 ),
364 help=argparse.SUPPRESS,
365 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000366
Alex Klein1699fab2022-09-08 08:46:06 -0600367 parser.add_argument(
368 "images",
369 nargs="*",
370 default=["dev"],
371 help="list of images to build. (Default: %(default)s).",
372 )
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000373
Alex Klein1699fab2022-09-08 08:46:06 -0600374 return parser
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000375
376
377def parse_args(
Alex Klein1699fab2022-09-08 08:46:06 -0600378 argv: List[str],
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000379) -> Tuple[commandline.ArgumentParser, commandline.ArgumentNamespace]:
Alex Klein1699fab2022-09-08 08:46:06 -0600380 """Parse and validate CLI arguments.
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000381
Alex Klein1699fab2022-09-08 08:46:06 -0600382 Args:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600383 argv: Arguments passed via CLI.
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000384
Alex Klein1699fab2022-09-08 08:46:06 -0600385 Returns:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600386 Tuple having the below two,
387 Argument Parser
388 Validated argument namespace.
Alex Klein1699fab2022-09-08 08:46:06 -0600389 """
390 parser = get_parser()
391 opts = parser.parse_args(argv)
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000392
Alex Klein1699fab2022-09-08 08:46:06 -0600393 opts.build_run_config = image.BuildConfig(
394 adjust_partition=opts.adjust_part,
395 output_root=opts.output_root,
396 builder_path=opts.builder_path,
397 disk_layout=opts.disk_layout,
398 enable_serial=opts.enable_serial,
399 kernel_loglevel=opts.kernel_loglevel,
400 boot_args=opts.boot_args,
401 enable_bootcache=opts.enable_bootcache,
402 enable_rootfs_verification=opts.enable_rootfs_verification,
403 build_attempt=opts.build_attempt,
404 build_root=opts.build_root,
405 jobs=opts.jobs,
406 replace=opts.replace,
407 symlink=opts.symlink,
408 version=opts.version,
409 output_dir_suffix=opts.output_suffix,
410 )
411 opts.Freeze()
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000412
Alex Klein1699fab2022-09-08 08:46:06 -0600413 return parser, opts
Ram Chandrasekar913c0422022-05-09 23:41:22 +0000414
415
Alex Klein1699fab2022-09-08 08:46:06 -0600416@timer.timed("Elapsed time (build_image)")
Jae Hoon Kim06d5a702023-02-17 22:40:27 +0000417def inner_main(argv: Optional[List[str]] = None):
418 """Inner main that processes building the image."""
Alex Klein1699fab2022-09-08 08:46:06 -0600419 parser, opts = parse_args(argv)
Ram Chandrasekar913c0422022-05-09 23:41:22 +0000420
Alex Klein9e7b29e2023-04-11 16:10:31 -0600421 # If the opts.board is not set, then it means user hasn't specified a
422 # default board in 'src/scripts/.default_board' and didn't specify it as
423 # input argument.
Alex Klein1699fab2022-09-08 08:46:06 -0600424 if not opts.board:
425 parser.error("--board is required")
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000426
Alex Klein1699fab2022-09-08 08:46:06 -0600427 invalid_image = [
428 x for x in opts.images if x not in constants.IMAGE_TYPE_TO_NAME
429 ]
430 if invalid_image:
431 parser.error(f"Invalid image type argument(s) {invalid_image}")
Ram Chandrasekar355c8cc2022-05-24 23:10:30 +0000432
Alex Klein1699fab2022-09-08 08:46:06 -0600433 result = image.Build(opts.board, opts.images, opts.build_run_config)
434 if result.run_error:
435 cros_build_lib.Die(
436 f"Error running build_image. Exit Code : {result.return_code}"
437 )
Jae Hoon Kim06d5a702023-02-17 22:40:27 +0000438
439
440def main(argv: Optional[List[str]] = None) -> Optional[int]:
441 commandline.RunInsideChroot()
442
443 # Make sure we run with network disabled to prevent leakage.
444 namespaces.ReExecuteWithNamespace(sys.argv, preserve_env=True)
445
446 inner_main(argv)