blob: 9a739a28988ade405f7919c58724e9646a2931b0 [file] [log] [blame]
Cindy Linc06b4ea2022-01-27 18:13:04 +00001# Copyright 2022 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"""build_packages updates the set of binary packages needed by Chrome OS.
6
7The build_packages process cross compiles all packages that have been
8updated into the given sysroot and builds binary packages as a side-effect.
9The output packages will be used by the build_image script to create a
10bootable Chrome OS image.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000011
12If packages are specified in cli, only build those specific packages and any
13dependencies they might need.
14
15For the fastest builds, use --nowithautotest --noworkon.
Cindy Linc06b4ea2022-01-27 18:13:04 +000016"""
17
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000018import argparse
Alex Kleinfba23ba2022-02-03 11:58:48 -070019import logging
Cindy Linc06b4ea2022-01-27 18:13:04 +000020import os
Alex Kleinfba23ba2022-02-03 11:58:48 -070021import urllib.error
22import urllib.request
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +000023from typing import List, Optional, Tuple
Cindy Linc06b4ea2022-01-27 18:13:04 +000024
Alex Kleina39dc982022-02-03 12:13:14 -070025from chromite.lib import commandline
Cindy Linc06b4ea2022-01-27 18:13:04 +000026from chromite.lib import constants
27from chromite.lib import cros_build_lib
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +000028from chromite.service import sysroot
Cindy Linc06b4ea2022-01-27 18:13:04 +000029
30
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000031def build_shell_bool_style_args(parser: commandline.ArgumentParser,
32 name: str,
33 default_val: bool,
34 help_str: str,
35 deprecation_note: str,
36 alternate_name: Optional[str] = None) -> None:
37 """Build the shell boolean input argument equivalent.
Alex Kleina39dc982022-02-03 12:13:14 -070038
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000039 There are two cases which we will need to handle,
40 case 1: A shell boolean arg, which doesn't need to be re-worded in python.
41 case 2: A shell boolean arg, which needs to be re-worded in python.
42 Example below.
43 For Case 1, for a given input arg name 'argA', we create three python
44 arguments.
45 --argA, --noargA, --no-argA. The arguments --argA and --no-argA will be
46 retained after deprecating --noargA.
47 For Case 2, for a given input arg name 'arg_A' we need to use alternate
48 argument name 'arg-A'. we create four python arguments in this case.
49 --arg_A, --noarg_A, --arg-A, --no-arg-A. The first two arguments will be
50 deprecated later.
51 TODO(b/218522717): Remove the creation of --noargA in case 1 and --arg_A and
52 --noarg_A in case 2.
53
54 Args:
55 parser: The parser to update.
56 name: The input argument name. This will be used as 'dest' variable name.
57 default_val: The default value to assign.
58 help_str: The help string for the input argument.
59 deprecation_note: A deprecation note to use.
60 alternate_name: Alternate argument to be used after deprecation.
61 """
62 arg = f'--{name}'
63 shell_narg = f'--no{name}'
64 py_narg = f'--no-{name}'
65 alt_arg = f'--{alternate_name}' if alternate_name else None
66 alt_py_narg = f'--no-{alternate_name}' if alternate_name else None
67 default_val_str = f'{help_str} (Default: %(default)s).'
68
69 if alternate_name:
70 parser.add_argument(
71 alt_arg,
72 action='store_true',
73 default=default_val,
74 dest=name,
75 help=default_val_str)
76 parser.add_argument(
77 alt_py_narg,
78 action='store_false',
79 dest=name,
80 help="Don't " + help_str.lower())
81
82 parser.add_argument(
83 arg,
84 action='store_true',
85 default=default_val,
86 dest=name,
87 deprecated=deprecation_note % alt_arg if alternate_name else None,
88 help=default_val_str if not alternate_name else argparse.SUPPRESS)
89 parser.add_argument(
90 shell_narg,
91 action='store_false',
92 dest=name,
93 deprecated=deprecation_note %
94 (alt_py_narg if alternate_name else py_narg),
95 help=argparse.SUPPRESS)
96
97 if not alternate_name:
98 parser.add_argument(
99 py_narg,
100 action='store_false',
101 dest=name,
102 help="Don't " + help_str.lower())
103
104
105def get_parser() -> commandline.ArgumentParser:
106 """Creates the cmdline argparser, populates the options and description.
107
108 Returns:
109 Argument parser.
110 """
111 deprecation_note = 'Argument will be removed July, 2022. Use %s instead.'
112 parser = commandline.ArgumentParser(description=__doc__)
113
114 # TODO(rchandrasekar): Check if the board input is set.
115 # Don't proceed if not set.
116 parser.add_argument(
117 '--board',
118 default=cros_build_lib.GetDefaultBoard(),
119 help='The board to build packages for.')
120
121 build_shell_bool_style_args(
122 parser, 'usepkg', True, 'Use binary packages to bootstrap when possible.',
123 deprecation_note)
124 build_shell_bool_style_args(
125 parser, 'usepkgonly', False,
126 'Use binary packages only to bootstrap; abort if any are missing.',
127 deprecation_note)
128 build_shell_bool_style_args(parser, 'workon', True,
129 'Force-build workon packages.', deprecation_note)
130 build_shell_bool_style_args(parser, 'showoutput', False,
131 'Show all output from parallel_emerge.',
132 deprecation_note)
133 build_shell_bool_style_args(
134 parser, 'withrevdeps', True,
135 'Calculate reverse dependencies on changed ebuilds.', deprecation_note)
136 build_shell_bool_style_args(
137 parser, 'cleanbuild', False,
138 'Perform a clean build; delete sysroot if it exists before building.',
139 deprecation_note)
140 build_shell_bool_style_args(
141 parser, 'pretend', False,
142 'Pretend building packages, just display which packages would have '
143 'been installed.', deprecation_note)
144
145 # The --sysroot flag specifies the environment variables ROOT and PKGDIR.
146 # This allows fetching and emerging of all packages to specified sysroot.
147 # Note that --sysroot will setup the board normally in /build/$BOARD, if
148 # it's not setup yet. It also expects the toolchain to already be installed
149 # in the sysroot.
150 # --usepkgonly and --norebuild are required, because building is not
151 # supported when board_root is set.
152 parser.add_argument(
153 '--sysroot', type='path', help='Emerge packages to sysroot.')
154 parser.add_argument(
155 '--board_root',
156 type='path',
157 dest='sysroot',
158 deprecated=deprecation_note % '--sysroot',
159 help=argparse.SUPPRESS)
160
161 # CPU Governor related options.
162 group = parser.add_argument_group('CPU Governor Options')
163 build_shell_bool_style_args(
164 group, 'autosetgov', False,
165 "Automatically set cpu governor to 'performance'.", deprecation_note)
166 build_shell_bool_style_args(
167 group,
168 'autosetgov_sticky',
169 False,
170 'Remember --autosetgov setting for future runs.',
171 deprecation_note,
172 alternate_name='autosetgov-sticky')
173
174 # Chrome building related options.
175 group = parser.add_argument_group('Chrome Options')
176 build_shell_bool_style_args(
177 group,
178 'use_any_chrome',
179 True,
180 "Use any Chrome prebuilt available, even if the prebuilt doesn't "
181 'match exactly.',
182 deprecation_note,
183 alternate_name='use-any-chrome')
184 build_shell_bool_style_args(
185 group, 'internal', False,
186 'Build the internal version of chrome(set the chrome_internal USE flag).',
187 deprecation_note)
188 build_shell_bool_style_args(
189 group, 'chrome', False, 'Ensure chrome instead of chromium. Alias for '
190 '--internal --no-use-any-chrome.', deprecation_note)
191
192 # Setup board related options.
193 group = parser.add_argument_group('Setup Board Config Options')
194 build_shell_bool_style_args(
195 group,
196 'skip_chroot_upgrade',
197 False,
198 'Skip the automatic chroot upgrade; use with care.',
199 deprecation_note,
200 alternate_name='skip-chroot-upgrade')
201 build_shell_bool_style_args(
202 group,
203 'skip_toolchain_update',
204 False,
205 'Skip automatic toolchain update',
206 deprecation_note,
207 alternate_name='skip-toolchain-update')
208 build_shell_bool_style_args(
209 group,
210 'skip_setup_board',
211 False,
212 'Skip running setup_board. Implies '
213 '--skip-chroot-upgrade --skip-toolchain-update.',
214 deprecation_note,
215 alternate_name='skip-setup-board')
216
217 # Image Type selection related options.
218 group = parser.add_argument_group('Image Type Options')
219 build_shell_bool_style_args(group, 'withdev', True,
220 'Build useful developer friendly utilities.',
221 deprecation_note)
222 build_shell_bool_style_args(
223 group, 'withdebug', True,
224 'Build debug versions of Chromium-OS-specific packages.',
225 deprecation_note)
226 build_shell_bool_style_args(group, 'withfactory', True,
227 'Build factory installer.', deprecation_note)
228 build_shell_bool_style_args(group, 'withtest', True,
229 'Build packages required for testing.',
230 deprecation_note)
231 build_shell_bool_style_args(group, 'withautotest', True,
232 'Build autotest client code.', deprecation_note)
233 build_shell_bool_style_args(group, 'withdebugsymbols', False,
234 'Install the debug symbols for all packages.',
235 deprecation_note)
236
237 # Advanced Options.
238 group = parser.add_argument_group('Advanced Options')
239 group.add_argument(
240 '--accept-licenses', help='Licenses to append to the accept list.')
241 group.add_argument(
242 '--accept_licenses',
243 deprecated=deprecation_note % '--accept-licenses',
244 help=argparse.SUPPRESS)
245 build_shell_bool_style_args(group, 'eclean', True,
246 'Run eclean to delete old binpkgs.',
247 deprecation_note)
248 group.add_argument(
249 '--jobs',
250 type=int,
251 default=os.cpu_count(),
252 help='Number of packages to build in parallel. '
253 '(Default: %(default)s)')
254 build_shell_bool_style_args(group, 'rebuild', True,
255 'Automatically rebuild dependencies.',
256 deprecation_note)
257 # TODO(b/218522717): Remove the --nonorebuild argument support.
258 group.add_argument(
259 '--nonorebuild',
260 action='store_true',
261 dest='rebuild',
262 deprecated=deprecation_note % '--rebuild',
263 help=argparse.SUPPRESS)
264 build_shell_bool_style_args(group, 'expandedbinhosts', True,
265 'Allow expanded binhost inheritance.',
266 deprecation_note)
267 # The --reuse-pkgs-from-local-boards flag tells Portage to share binary
268 # packages between boards that are built locally, so that the total time
269 # required to build several boards is reduced. This flag is only useful
270 # when you are not able to use remote binary packages, since remote binary
271 # packages are usually more up to date than anything you have locally.
272 build_shell_bool_style_args(
273 group,
274 'reuse_pkgs_from_local_boards',
275 False,
276 'Bootstrap from local packages instead of remote packages.',
277 deprecation_note,
278 alternate_name='reuse-pkgs-from-local-boards')
279
280 # --run-goma option is designed to be used on bots.
281 # If you're trying to build packages with goma in your local dev env, this is
282 # *not* the option you're looking for. Please see comments below.
283 # This option; 1) starts goma, 2) builds packages (expecting that goma is
284 # used), then 3) stops goma explicitly.
285 # 4) is a request from the goma team, so that stats/logs can be taken.
286 # Note: GOMA_DIR and GOMA_SERVICE_ACCOUNT_JSON_FILE are expected to be passed
287 # via env var.
288 #
289 # In local dev env cases, compiler_proxy is expected to keep running.
290 # In such a case;
291 # $ python ${GOMA_DIR}/goma_ctl.py ensure_start
292 # $ ./build_packages (... and options without --run-goma ...)
293 # is an expected commandline sequence. If you set --run-goma flag while
294 # compiler_proxy is already running, the existing compiler_proxy will be
295 # stopped.
296 #
297 # TODO(rchandrasekar): Use of env variable as input is not right. Added
298 # options to provide them as input arguments. Migrate users to use these
299 # options and deprecate the '--run-goma' arg.
300 build_shell_bool_style_args(
301 group,
302 'run_goma',
303 False,
304 'If set to true, (re)starts goma, builds packages, and then stops goma..',
305 deprecation_note,
306 alternate_name='run-goma')
307 group.add_argument('--goma-dir', type='path', help='Goma directory path.')
308 group.add_argument(
309 '--goma-cfg', type='path', help='Goma service account json file to use.')
310 # This option is for building chrome remotely.
311 # 1) starts reproxy 2) builds chrome with reproxy and 3) stops reproxy so
312 # logs/stats can be collected.
313 # Note: RECLIENT_DIR and REPROXY_CFG env var will be deprecated July, 2022.
314 # Use --reclient-dir and --reproxy-cfg input options instead.
315 #
316 # TODO(rchandrasekar): Use of env variable as input is not right. Added
317 # options to provide them as input arguments. Migrate users to use these
318 # options and deprecate the '--run-remoteexec' arg.
319 build_shell_bool_style_args(
320 group, 'run_remoteexec', False,
321 'If set to true, starts RBE reproxy, builds packages, and then stops '
322 'reproxy.', deprecation_note)
323 group.add_argument('--reclient-dir', type='path', help='Reproxy client path.')
324 group.add_argument(
325 '--reproxy-cfg', type='path', help='Reproxy config file to use.')
326
327 parser.add_argument('packages', nargs='*', help='Packages to build.')
328 return parser
329
330
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000331def parse_args(argv: List[str]) -> Tuple[commandline.ArgumentParser,
332 commandline.ArgumentNamespace]:
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000333 """Parse and validate CLI arguments.
334
335 Args:
336 argv: Arguments passed via CLI.
337
338 Returns:
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000339 Tuple having the below two,
340 Argument Parser
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000341 Validated argument namespace.
342 """
343 parser = get_parser()
344 opts = parser.parse_args(argv)
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000345
346 if opts.chrome:
347 opts.internal_chrome = True
348 opts.use_any_chrome = False
349
350 opts.build_run_config = sysroot.BuildPackagesRunConfig(
351 usepkg=opts.usepkg,
352 install_debug_symbols=opts.withdebugsymbols,
353 packages=opts.packages,
354 use_goma=opts.run_goma,
355 use_remoteexec=opts.run_remoteexec,
356 incremental_build=opts.withrevdeps,
357 expanded_binhosts=opts.expandedbinhosts,
358 setup_board=not opts.skip_setup_board,
359 dryrun=opts.pretend,
360 usepkgonly=opts.usepkgonly,
361 workon=opts.workon,
362 verbose=opts.showoutput,
363 install_auto_test=opts.withautotest,
364 autosetgov=opts.autosetgov,
365 autosetgov_sticky=opts.autosetgov_sticky,
366 use_any_chrome=opts.use_any_chrome,
367 internal_chrome=opts.internal,
368 clean_build=opts.cleanbuild,
369 eclean=opts.eclean,
370 rebuild_dep=opts.rebuild,
371 accept_licenses=opts.accept_licenses,
372 jobs=opts.jobs,
373 local_pkg=opts.reuse_pkgs_from_local_boards,
374 dev_image=opts.withdev,
375 factory_image=opts.withfactory,
376 test_image=opts.withtest,
377 debug_version=opts.withdebug,
378 update_toolchain=not opts.skip_toolchain_update,
379 upgrade_chroot=not opts.skip_chroot_upgrade)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000380 opts.Freeze()
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000381 return parser, opts
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000382
383
384def main(argv: Optional[List[str]] = None) -> Optional[int]:
385 commandline.RunInsideChroot()
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000386 parser, opts = parse_args(argv)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000387
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000388 # TODO(rchandrasekar): Pass the BuildPackage run config to BuildPackage in
389 # sysroot service.
390 #
391 # If the opts.board is not set, then it means user hasn't specified a default
392 # board in 'src/scripts/.default_board' and didn't specify it as input
393 # argument.
394 if not opts.board:
395 parser.error('--board is required')
396
Cindy Linc06b4ea2022-01-27 18:13:04 +0000397 cmd = [
398 'bash',
399 os.path.join(constants.CROSUTILS_DIR, 'build_packages.sh'),
400 '--script-is-run-only-by-chromite-and-not-users'
401 ]
402 cmd.extend(argv)
403 try:
Cindy Line4b243a2022-02-04 22:15:37 +0000404 # TODO(b/187793559): Don't pass in print_cmd once we switch to argparse
405 cros_build_lib.dbg_run(cmd, print_cmd=False)
Cindy Linc06b4ea2022-01-27 18:13:04 +0000406 except cros_build_lib.RunCommandError as e:
Alex Kleinfba23ba2022-02-03 11:58:48 -0700407 try:
408 request = urllib.request.urlopen(
409 'https://chromiumos-status.appspot.com/current?format=raw')
410 logging.notice('Tree Status: %s', request.read().decode())
411 except urllib.error.HTTPError:
412 pass
Cindy Linc06b4ea2022-01-27 18:13:04 +0000413 cros_build_lib.Die(e)