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