blob: 19b7f4271d1e3b90caf322f4f37cd8dbf0dd56d3 [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# Copyright 2019 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"""Package utility functionality."""
6
Yaakov Shaul730814a2019-09-10 13:58:25 -06007import collections
Ben Reiche779cf42020-12-15 03:21:31 +00008from distutils.version import LooseVersion
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -06009import fileinput
Alex Klein87531182019-08-12 15:23:37 -060010import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060011import json
Chris McDonaldf7c03d42021-07-21 11:54:26 -060012import logging
Evan Hernandezb51f1522019-08-15 11:29:40 -060013import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060014import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060015import sys
Alex Klein5caab872021-09-10 11:44:37 -060016from typing import List, Optional, TYPE_CHECKING, Union
Alex Klein87531182019-08-12 15:23:37 -060017
Mike Frysinger2c024062021-05-22 15:43:22 -040018from chromite.third_party.google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060019
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060021from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060022from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060023from chromite.lib import cros_build_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060025from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060026from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070028from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060029from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060030from chromite.lib.parser import package_info
Alex Kleineb77ffa2019-05-28 14:47:44 -060031
Alex Klein5caab872021-09-10 11:44:37 -060032if TYPE_CHECKING:
33 from chromite.lib import build_target_lib
Chris McDonaldf7c03d42021-07-21 11:54:26 -060034
Alex Klein36b117f2019-09-30 15:13:46 -060035if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060036 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060037 from chromite.service import dependency
38
Alex Klein87531182019-08-12 15:23:37 -060039# Registered handlers for uprevving versioned packages.
40_UPREV_FUNCS = {}
41
Alex Kleineb77ffa2019-05-28 14:47:44 -060042
43class Error(Exception):
44 """Module's base error class."""
45
46
Alex Klein4de25e82019-08-05 15:58:39 -060047class UnknownPackageError(Error):
48 """Uprev attempted for a package without a registered handler."""
49
50
Alex Kleineb77ffa2019-05-28 14:47:44 -060051class UprevError(Error):
52 """An error occurred while uprevving packages."""
53
54
Michael Mortensenb70e8a82019-10-10 18:43:41 -060055class NoAndroidVersionError(Error):
56 """An error occurred while trying to determine the android version."""
57
58
59class NoAndroidBranchError(Error):
60 """An error occurred while trying to determine the android branch."""
61
62
63class NoAndroidTargetError(Error):
64 """An error occurred while trying to determine the android target."""
65
66
Alex Klein4de25e82019-08-05 15:58:39 -060067class AndroidIsPinnedUprevError(UprevError):
68 """Raised when we try to uprev while Android is pinned."""
69
70 def __init__(self, new_android_atom):
71 """Initialize a AndroidIsPinnedUprevError.
72
73 Args:
74 new_android_atom: The Android atom that we failed to
75 uprev to, due to Android being pinned.
76 """
77 assert new_android_atom
78 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
79 new_android_atom)
Jae Hoon Kimad176b82021-07-26 19:29:29 +000080 super().__init__(msg)
Alex Klein4de25e82019-08-05 15:58:39 -060081 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060082
83
Andrew Lamb9563a152019-12-04 11:42:18 -070084class GeneratedCrosConfigFilesError(Error):
85 """Error when cros_config_schema does not produce expected files"""
86
87 def __init__(self, expected_files, found_files):
88 msg = ('Expected to find generated C files: %s. Actually found: %s' %
89 (expected_files, found_files))
Jae Hoon Kimad176b82021-07-26 19:29:29 +000090 super().__init__(msg)
Andrew Lamb9563a152019-12-04 11:42:18 -070091
Alex Klein7a3a7dd2020-01-08 16:44:38 -070092
Alex Klein6becabc2020-09-11 14:03:05 -060093NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
94 'needs_chrome_source',
95 'builds_chrome',
96 'packages',
97 'missing_chrome_prebuilt',
98 'missing_follower_prebuilt',
Alex Klein9ce3f682021-06-23 15:06:44 -060099 'local_uprev',
Alex Klein6becabc2020-09-11 14:03:05 -0600100))
101
102
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600103def patch_ebuild_vars(ebuild_path, variables):
104 """Updates variables in ebuild.
105
106 Use this function rather than portage_util.EBuild.UpdateEBuild when you
107 want to preserve the variable position and quotes within the ebuild.
108
109 Args:
110 ebuild_path: The path of the ebuild.
111 variables: Dictionary of variables to update in ebuild.
112 """
113 try:
114 for line in fileinput.input(ebuild_path, inplace=1):
115 varname, eq, _ = line.partition('=')
116 if eq == '=' and varname.strip() in variables:
117 value = variables[varname]
118 sys.stdout.write('%s="%s"\n' % (varname, value))
119 else:
120 sys.stdout.write(line)
121 finally:
122 fileinput.close()
123
124
Alex Klein87531182019-08-12 15:23:37 -0600125def uprevs_versioned_package(package):
126 """Decorator to register package uprev handlers."""
127 assert package
128
129 def register(func):
130 """Registers |func| as a handler for |package|."""
131 _UPREV_FUNCS[package] = func
132
133 @functools.wraps(func)
134 def pass_through(*args, **kwargs):
135 return func(*args, **kwargs)
136
137 return pass_through
138
139 return register
140
141
Shao-Chuan Leeb6a2cb62021-02-19 14:18:59 +0900142def uprev_android(android_package,
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700143 chroot,
144 build_targets=None,
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900145 android_build_branch=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900146 android_version=None,
147 skip_commit=False):
Alex Klein4de25e82019-08-05 15:58:39 -0600148 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700149 command = [
150 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900151 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700152 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600153 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900154 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900155 if android_build_branch:
156 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600157 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900158 command.append(f'--force_version={android_version}')
159 if skip_commit:
160 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600161
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700162 result = cros_build_lib.run(
163 command,
164 stdout=True,
165 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500166 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700167 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600168
Mike Frysinger88d96362020-02-14 19:05:45 -0500169 portage_atom_string = result.stdout.strip()
170 android_atom = None
171 if portage_atom_string:
172 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600173 if not android_atom:
174 logging.info('Found nothing to rev.')
175 return None
176
177 for target in build_targets or []:
178 # Sanity check: We should always be able to merge the version of
179 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900180 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600181 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700182 cros_build_lib.run(
183 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600184 except cros_build_lib.RunCommandError:
185 logging.error(
186 'Cannot emerge-%s =%s\nIs Android pinned to an older '
187 'version?', target, android_atom)
188 raise AndroidIsPinnedUprevError(android_atom)
189
190 return android_atom
191
192
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700193def uprev_build_targets(build_targets,
194 overlay_type,
195 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600196 output_dir=None):
197 """Uprev the set provided build targets, or all if not specified.
198
199 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600200 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600201 whose overlays should be uprevved, empty or None for all.
202 overlay_type (str): One of the valid overlay types except None (see
203 constants.VALID_OVERLAYS).
204 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
205 output_dir (str|None): The path to optionally dump result files.
206 """
207 # Need a valid overlay, but exclude None.
208 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
209
210 if build_targets:
211 overlays = portage_util.FindOverlaysForBoards(
212 overlay_type, boards=[t.name for t in build_targets])
213 else:
214 overlays = portage_util.FindOverlays(overlay_type)
215
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700216 return uprev_overlays(
217 overlays,
218 build_targets=build_targets,
219 chroot=chroot,
220 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600221
222
223def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
224 """Uprev the given overlays.
225
226 Args:
227 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600228 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600229 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
230 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
231 output_dir (str|None): The path to optionally dump result files.
232
233 Returns:
234 list[str] - The paths to all of the modified ebuild files. This includes the
235 new files that were added (i.e. the new versions) and all of the removed
236 files (i.e. the old versions).
237 """
238 assert overlays
239
240 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
241
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700242 uprev_manager = uprev_lib.UprevOverlayManager(
243 overlays,
244 manifest,
245 build_targets=build_targets,
246 chroot=chroot,
247 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600248 uprev_manager.uprev()
249
Dhanya Ganeshd03a4162021-08-25 00:21:50 +0000250 return uprev_manager.modified_ebuilds, uprev_manager.revved_packages
Alex Kleineb77ffa2019-05-28 14:47:44 -0600251
252
Alex Klein87531182019-08-12 15:23:37 -0600253def uprev_versioned_package(package, build_targets, refs, chroot):
254 """Call registered uprev handler function for the package.
255
256 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600257 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600258 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600259 clean on a successful uprev.
260 refs (list[uprev_lib.GitRef]):
261 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
262
263 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600264 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600265 """
266 assert package
267
268 if package.cp not in _UPREV_FUNCS:
269 raise UnknownPackageError(
270 'Package "%s" does not have a registered handler.' % package.cp)
271
Andrew Lambea9a8a22019-12-12 14:03:43 -0700272 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600273
274
Navil Perezf57ba872020-06-04 22:38:37 +0000275@uprevs_versioned_package('media-libs/virglrenderer')
276def uprev_virglrenderer(_build_targets, refs, _chroot):
277 """Updates virglrenderer ebuilds.
278
279 See: uprev_versioned_package.
280
281 Returns:
282 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
283 """
Navil Perezf57ba872020-06-04 22:38:37 +0000284 overlay = os.path.join(constants.SOURCE_ROOT,
285 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600286 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
287 'virglrenderer')
288 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000289
290 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
291 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000292 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
293 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000294 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
295
George Engelbrechte73f2782020-06-10 14:10:46 -0600296 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600297 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000298 result.add_result(refs[0].revision, updated_files)
299 return result
300
Jose Magana03b5a842020-08-19 12:52:59 +1000301@uprevs_versioned_package('chromeos-base/drivefs')
302def uprev_drivefs(_build_targets, refs, chroot):
303 """Updates drivefs ebuilds.
304
Harvey Yang3eee06c2021-03-18 15:47:56 +0800305 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000306 See: uprev_versioned_package.
307
308 Returns:
309 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
310 """
311
Ben Reiche779cf42020-12-15 03:21:31 +0000312 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000313 result = uprev_lib.UprevVersionedPackageResult()
314 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000315
Harvey Yang3eee06c2021-03-18 15:47:56 +0800316 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
317 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000318 if not drivefs_version:
319 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000320 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000321
Ben Reiche779cf42020-12-15 03:21:31 +0000322 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000323
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000324 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000325 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000326 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000327 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800328 chroot,
329 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000330
331 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000332 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000333 all_changed_files.extend(uprev_result.changed_files)
334
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000335 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000336 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000337 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000338 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800339 chroot,
340 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000341
342 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000343 logging.warning(
344 'drivefs package has changed files %s but drivefs-ipc does not',
345 all_changed_files)
346 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000347
348 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000349 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000350
351 return result
352
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800353@uprevs_versioned_package('chromeos-base/perfetto')
354def uprev_perfetto(_build_targets, refs, chroot):
355 """Updates Perfetto ebuilds.
356
Harvey Yang3eee06c2021-03-18 15:47:56 +0800357 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800358 See: uprev_versioned_package.
359
360 Returns:
361 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
362 """
363 result = uprev_lib.UprevVersionedPackageResult()
364
Harvey Yang3eee06c2021-03-18 15:47:56 +0800365 PERFETTO_REFS_PREFIX = 'refs/tags/v'
366 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800367 if not perfetto_version:
368 # No valid Perfetto version is identified.
369 return result
370
371 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
372
373 # Attempt to uprev perfetto package.
374 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
375
Harvey Yang3eee06c2021-03-18 15:47:56 +0800376 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
377 PERFETTO_PATH,
378 perfetto_version,
379 chroot,
380 allow_downrev=False,
381 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800382
383 if not uprev_result:
384 return result
385
386 result.add_result(perfetto_version, uprev_result.changed_files)
387
388 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000389
Yaakov Shaul395ae832019-09-09 14:45:32 -0600390@uprevs_versioned_package('afdo/kernel-profiles')
391def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600392 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600393
394 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600395
396 Raises:
397 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600398 """
399 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
400 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
401
David Burger92485342019-09-10 17:52:45 -0600402 with open(path, 'r') as f:
403 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600404
Chris McDonald38409112020-09-24 11:24:51 -0600405 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600406 for kernel_pkg, version_info in versions.items():
407 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
408 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600409 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600410 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600411 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600412 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600413 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600414 patch_ebuild_vars(ebuild_path,
415 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600416
417 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600418 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400419 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600420 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600421 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600422 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600423 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600424
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600425 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600426
Yaakov Shaul730814a2019-09-10 13:58:25 -0600427 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
428
429 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600430
431
Trent Begineb624182020-07-14 10:09:45 -0600432@uprevs_versioned_package('chromeos-base/termina-dlc')
433def uprev_termina_dlc(_build_targets, _refs, chroot):
434 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600435
436 See: uprev_versioned_package.
437 """
Trent Begineb624182020-07-14 10:09:45 -0600438 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600439 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
440 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000441
442 version_pin_src_path = _get_version_pin_src_path(package_path)
443 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
444
Chris McDonald38409112020-09-24 11:24:51 -0600445 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000446
447
Julio Hurtadof1befec2021-05-05 21:34:26 +0000448@uprevs_versioned_package('chromeos-base/chromeos-lacros')
449def uprev_lacros(_build_targets, refs, chroot):
450 """Updates lacros ebuilds.
451
Julio Hurtadoa994e002021-07-07 17:57:45 +0000452 Version to uprev to is gathered from the QA qualified version tracking file
453 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
454 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000455
456 See: uprev_versioned_package.
457 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000458 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000459 path = os.path.join(
460 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base','chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000461 lacros_version = refs[0].revision
462 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
463 lacros_version,
464 chroot,
465 allow_downrev=False)
466
467 if not uprev_result:
468 return result
469
470 result.add_result(lacros_version, uprev_result.changed_files)
471 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000472
473
Patrick Meiring5897add2020-09-16 16:30:17 +1000474@uprevs_versioned_package('app-emulation/parallels-desktop')
475def uprev_parallels_desktop(_build_targets, _refs, chroot):
476 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
477
478 See: uprev_versioned_package
479
480 Returns:
481 UprevVersionedPackageResult: The result.
482 """
483 package = 'parallels-desktop'
484 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
485 'app-emulation', package)
486 version_pin_src_path = _get_version_pin_src_path(package_path)
487
488 # Expect a JSON blob like the following:
489 # {
490 # "version": "1.2.3",
491 # "test_image": { "url": "...", "size": 12345678,
492 # "sha256sum": "<32 bytes of hexadecimal>" }
493 # }
494 with open(version_pin_src_path, 'r') as f:
495 pinned = json.load(f)
496
497 if 'version' not in pinned or 'test_image' not in pinned:
498 raise UprevError('VERSION-PIN for %s missing version and/or '
499 'test_image field' % package)
500
501 version = pinned['version']
502 if not isinstance(version, str):
503 raise UprevError('version in VERSION-PIN for %s not a string' % package)
504
505 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600506 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000507
508 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100509 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
510 'local/bundles/crosint/pita/data/'
511 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000512 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
513 with open(test_image_src_path, 'w') as f:
514 json.dump(pinned['test_image'], f, indent=2)
515 result.add_result(version, [test_image_src_path])
516
517 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600518
519
Trent Begin315d9d92019-12-03 21:55:53 -0700520@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600521def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700522 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
523
524 See: uprev_versioned_package.
525 """
526 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700527 package_path = os.path.join('src', 'private-overlays',
528 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000529 version_pin_src_path = _get_version_pin_src_path(package_path)
530 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700531
Chris McDonald38409112020-09-24 11:24:51 -0600532 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700533
534
Patrick Meiring5897add2020-09-16 16:30:17 +1000535def _get_version_pin_src_path(package_path):
536 """Returns the path to the VERSION-PIN file for the given package."""
537 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
538
539
Alex Klein87531182019-08-12 15:23:37 -0600540@uprevs_versioned_package(constants.CHROME_CP)
Alex Kleinf69bd802021-06-22 15:43:49 -0600541def uprev_chrome_from_ref(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600542 """Uprev chrome and its related packages.
543
544 See: uprev_versioned_package.
545 """
546 # Determine the version from the refs (tags), i.e. the chrome versions are the
547 # tag names.
548 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600549 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600550
Alex Kleinf69bd802021-06-22 15:43:49 -0600551 return uprev_chrome(build_targets, chrome_version, chroot)
552
553
Alex Klein9ce3f682021-06-23 15:06:44 -0600554def revbump_chrome(
555 build_targets: List['build_target_lib.BuildTarget'],
556 chroot: Optional['chroot_lib.Chroot'] = None
557) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600558 """Attempt to revbump chrome.
559
560 Revbumps are done by executing an uprev using the current stable version.
561 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
562 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
563 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
564 """
565 chrome_version = uprev_lib.get_stable_chrome_version()
566 return uprev_chrome(build_targets, chrome_version, chroot)
567
568
Alex Klein9ce3f682021-06-23 15:06:44 -0600569def uprev_chrome(
570 build_targets: List['build_target_lib.BuildTarget'], chrome_version: str,
571 chroot: Union['chroot_lib.Chroot', None]
572) -> uprev_lib.UprevVersionedPackageResult:
573 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600574 uprev_manager = uprev_lib.UprevChromeManager(
575 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600576 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600577 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
578 # attempt. The expected behavior is documented in the following table:
579 #
580 # Outcome of Chrome uprev attempt:
581 # NEWER_VERSION_EXISTS:
582 # Do nothing.
583 # SAME_VERSION_EXISTS or REVISION_BUMP:
584 # Uprev followers
585 # Assert not VERSION_BUMP (any other outcome is fine)
586 # VERSION_BUMP or NEW_EBUILD_CREATED:
587 # Uprev followers
588 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600589
590 # Start with chrome itself so we can proceed accordingly.
591 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
592 if chrome_result.newer_version_exists:
593 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600594 return result
Alex Klein87531182019-08-12 15:23:37 -0600595
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600596 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600597 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600598 follower_result = uprev_manager.uprev(package)
599 if chrome_result.stable_version and follower_result.version_bump:
600 logging.warning('%s had a version bump, but no more than a revision bump '
601 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600602
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600603 if uprev_manager.modified_ebuilds:
604 # Record changes when we have them.
605 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
606
607 return result
Alex Klein87531182019-08-12 15:23:37 -0600608
609
Harvey Yang3eee06c2021-03-18 15:47:56 +0800610def _get_latest_version_from_refs(refs_prefix: str,
611 refs: List[uprev_lib.GitRef]) -> str:
612 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000613
Ben Reiche779cf42020-12-15 03:21:31 +0000614 Versions are compared using |distutils.version.LooseVersion| and
615 the latest version is returned.
616
617 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800618 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800619 refs: The tags to parse for the latest Perfetto version.
620
621 Returns:
622 The latest Perfetto version to use.
623 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800624 valid_refs = []
625 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800626 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800627 valid_refs.append(gitiles.ref)
628
629 if not valid_refs:
630 return None
631
632 # Sort by version and take the latest version.
633 target_version_ref = sorted(valid_refs,
634 key=LooseVersion,
635 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800636 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800637
638
Andrew Lamb9563a152019-12-04 11:42:18 -0700639def _generate_platform_c_files(replication_config, chroot):
640 """Generates platform C files from a platform JSON payload.
641
642 Args:
643 replication_config (replication_config_pb2.ReplicationConfig): A
644 ReplicationConfig that has already been run. If it produced a
645 build_config.json file, that file will be used to generate platform C
646 files. Otherwise, nothing will be generated.
647 chroot (chroot_lib.Chroot): The chroot to use to generate.
648
649 Returns:
650 A list of generated files.
651 """
652 # Generate the platform C files from the build config. Note that it would be
653 # more intuitive to generate the platform C files from the platform config;
654 # however, cros_config_schema does not allow this, because the platform config
655 # payload is not always valid input. For example, if a property is both
656 # 'required' and 'build-only', it will fail schema validation. Thus, use the
657 # build config, and use '-f' to filter.
658 build_config_path = [
659 rule.destination_path
660 for rule in replication_config.file_replication_rules
661 if rule.destination_path.endswith('build_config.json')
662 ]
663
664 if not build_config_path:
665 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700666 'No build_config.json found, will not generate platform C files. '
667 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700668 return []
669
670 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700671 raise ValueError('Expected at most one build_config.json destination path. '
672 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700673
674 build_config_path = build_config_path[0]
675
676 # Paths to the build_config.json and dir to output C files to, in the
677 # chroot.
678 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
679 build_config_path)
680 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
681 os.path.dirname(build_config_path))
682
683 command = [
684 'cros_config_schema', '-m', build_config_chroot_path, '-g',
685 generated_output_chroot_dir, '-f', '"TRUE"'
686 ]
687
688 cros_build_lib.run(
689 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
690
691 # A relative (to the source root) path to the generated C files.
692 generated_output_dir = os.path.dirname(build_config_path)
693 generated_files = []
694 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
695 for f in expected_c_files:
696 if os.path.exists(
697 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
698 generated_files.append(os.path.join(generated_output_dir, f))
699
700 if len(expected_c_files) != len(generated_files):
701 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
702
703 return generated_files
704
705
Andrew Lambe836f222019-12-09 12:27:38 -0700706def _get_private_overlay_package_root(ref, package):
707 """Returns the absolute path to the root of a given private overlay.
708
709 Args:
710 ref (uprev_lib.GitRef): GitRef for the private overlay.
711 package (str): Path to the package in the overlay.
712 """
713 # There might be a cleaner way to map from package -> path within the source
714 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700715 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700716 match = re.match(private_overlay_ref_pattern, ref.path)
717 if not match:
718 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
719 (private_overlay_ref_pattern, ref))
720
721 overlay = match.group(1)
722
723 return os.path.join(constants.SOURCE_ROOT,
724 'src/private-overlays/overlay-%s-private' % overlay,
725 package)
726
727
Andrew Lambea9a8a22019-12-12 14:03:43 -0700728@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
729def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700730 """Replicate a private cros_config change to the corresponding public config.
731
Alex Kleinad6b48a2020-01-08 16:57:41 -0700732 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700733 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700734 package = 'chromeos-base/chromeos-config-bsp'
735
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700736 if len(refs) != 1:
737 raise ValueError('Expected exactly one ref, actual %s' % refs)
738
739 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700740 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700741 replication_config_path = os.path.join(package_root,
742 'replication_config.jsonpb')
743
744 try:
745 replication_config = json_format.Parse(
746 osutils.ReadFile(replication_config_path),
747 replication_config_pb2.ReplicationConfig())
748 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700749 raise ValueError(
750 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700751
752 replication_lib.Replicate(replication_config)
753
754 modified_files = [
755 rule.destination_path
756 for rule in replication_config.file_replication_rules
757 ]
758
Andrew Lamb9563a152019-12-04 11:42:18 -0700759 # The generated platform C files are not easily filtered by replication rules,
760 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
761 # files cannot. Therefore, replicate and filter the JSON payloads, and then
762 # generate filtered C files from the JSON payload.
763 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700764
765 # Use the private repo's commit hash as the new version.
766 new_private_version = refs[0].revision
767
Andrew Lamb988f4da2019-12-10 10:16:43 -0700768 # modified_files should contain only relative paths at this point, but the
769 # returned UprevVersionedPackageResult must contain only absolute paths.
770 for i, modified_file in enumerate(modified_files):
771 assert not os.path.isabs(modified_file)
772 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
773
Chris McDonald38409112020-09-24 11:24:51 -0600774 return uprev_lib.UprevVersionedPackageResult().add_result(
775 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700776
777
Alex Klein5caab872021-09-10 11:44:37 -0600778def get_best_visible(
779 atom: str,
780 build_target: Optional['build_target_lib.BuildTarget'] = None
781) -> package_info.PackageInfo:
Alex Kleinbbef2b32019-08-27 10:38:50 -0600782 """Returns the best visible CPV for the given atom.
783
784 Args:
Alex Klein5caab872021-09-10 11:44:37 -0600785 atom: The atom to look up.
786 build_target: The build target whose sysroot should be searched, or the SDK
787 if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700788
789 Returns:
Alex Klein5caab872021-09-10 11:44:37 -0600790 The best visible package, or None if none are visible.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600791 """
David Burger1e0fe232019-07-01 14:52:07 -0600792 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600793
Alex Klein5caab872021-09-10 11:44:37 -0600794 return portage_util.PortageqBestVisible(
795 atom,
796 board=build_target.name if build_target else None,
797 sysroot=build_target.root if build_target else None)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600798
799
Alex Klein149fd3b2019-12-16 16:01:05 -0700800def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600801 """Check if a prebuilt exists.
802
803 Args:
804 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600805 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600806 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700807 useflags: Any additional USE flags that should be set. May be a string
808 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700809
810 Returns:
811 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600812 """
813 assert atom
814
815 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700816 extra_env = None
817 if useflags:
818 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500819 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700820 new_flags = ' '.join(useflags)
821
822 existing = os.environ.get('USE', '')
823 final_flags = '%s %s' % (existing, new_flags)
824 extra_env = {'USE': final_flags.strip()}
825 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600826
827
David Burger0f9dd4e2019-10-08 12:33:42 -0600828def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600829 """Check if |build_target| builds |atom| (has it in its depgraph)."""
830 cros_build_lib.AssertInsideChroot()
831
Alex Kleind8cd4c62020-09-14 13:37:47 -0600832 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600833 # TODO(crbug/1081828): Receive and use sysroot.
834 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600835 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600836 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600837
838
Alex Klein6becabc2020-09-11 14:03:05 -0600839def needs_chrome_source(
840 build_target: 'build_target_lib.BuildTarget',
841 compile_source=False,
842 packages: Optional[List[package_info.PackageInfo]] = None,
843 useflags=None):
844 """Check if the chrome source is needed.
845
846 The chrome source is needed if the build target builds chrome or any of its
847 follower packages, and can't use a prebuilt for them either because it's not
848 available, or because we can't use prebuilts because it must build from
849 source.
850 """
851 cros_build_lib.AssertInsideChroot()
852
853 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700854 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600855 builds_chrome = constants.CHROME_CP in graph
856 builds_follower = {
857 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
858 }
859
Alex Klein9ce3f682021-06-23 15:06:44 -0600860 local_uprev = builds_chrome and revbump_chrome([build_target])
861
Alex Klein6becabc2020-09-11 14:03:05 -0600862 # When we are compiling source set False since we do not use prebuilts.
863 # When not compiling from source, start with True, i.e. we have every prebuilt
864 # we've checked for up to this point.
865 has_chrome_prebuilt = not compile_source
866 has_follower_prebuilts = not compile_source
867 # Save packages that need prebuilts for reporting.
868 pkgs_needing_prebuilts = []
869 if compile_source:
870 # Need everything.
871 pkgs_needing_prebuilts.append(constants.CHROME_CP)
872 pkgs_needing_prebuilts.extend(
873 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
874 else:
875 # Check chrome itself.
876 if builds_chrome:
877 has_chrome_prebuilt = has_prebuilt(
878 constants.CHROME_CP, build_target=build_target, useflags=useflags)
879 if not has_chrome_prebuilt:
880 pkgs_needing_prebuilts.append(constants.CHROME_CP)
881 # Check follower packages.
882 for pkg, builds_pkg in builds_follower.items():
883 if not builds_pkg:
884 continue
885 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
886 has_follower_prebuilts &= prebuilt
887 if not prebuilt:
888 pkgs_needing_prebuilts.append(pkg)
889 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
890 # reflect whether we actually have the corresponding prebuilts for the build.
891
892 needs_chrome = builds_chrome and not has_chrome_prebuilt
893 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
894
895 return NeedsChromeSourceResult(
Sergey Frolov26ff97b2021-08-14 00:02:11 +0000896 needs_chrome_source=needs_chrome or needs_follower,
Alex Klein6becabc2020-09-11 14:03:05 -0600897 builds_chrome=builds_chrome,
898 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
899 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -0600900 missing_follower_prebuilt=not has_follower_prebuilts,
901 local_uprev=local_uprev,
902 )
Alex Klein6becabc2020-09-11 14:03:05 -0600903
904
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600905def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600906 """Returns the current Chrome version for the board (or in buildroot).
907
908 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600909 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700910
911 Returns:
912 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600913 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600914 # TODO(crbug/1019770): Long term we should not need the try/catch here once
915 # the builds function above only returns True for chrome when
916 # determine_chrome_version will succeed.
917 try:
Alex Klein5caab872021-09-10 11:44:37 -0600918 pkg_info = portage_util.PortageqBestVisible(
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700919 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600920 except cros_build_lib.RunCommandError as e:
921 # Return None because portage failed when trying to determine the chrome
922 # version.
923 logging.warning('Caught exception in determine_chrome_package: %s', e)
924 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600925 # Something like 78.0.3877.4_rc -> 78.0.3877.4
Alex Klein5caab872021-09-10 11:44:37 -0600926 return pkg_info.version.partition('_')[0]
Michael Mortensenc2615b72019-10-15 08:12:24 -0600927
928
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600929def determine_android_package(board):
930 """Returns the active Android container package in use by the board.
931
932 Args:
933 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700934
935 Returns:
936 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600937 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600938 try:
939 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600940 except cros_build_lib.RunCommandError as e:
941 # Return None because a command (likely portage) failed when trying to
942 # determine the package.
943 logging.warning('Caught exception in determine_android_package: %s', e)
944 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600945
Alex Kleinad6b48a2020-01-08 16:57:41 -0700946 # We assume there is only one Android package in the depgraph.
947 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400948 if (package.startswith('chromeos-base/android-container-') or
949 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700950 return package
951 return None
952
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600953
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500954def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600955 """Determine the current Android version in buildroot now and return it.
956
957 This uses the typical portage logic to determine which version of Android
958 is active right now in the buildroot.
959
960 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500961 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500962 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600963
964 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500965 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600966
967 Raises:
968 NoAndroidVersionError: if no unique Android version can be determined.
969 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500970 if not package:
971 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500972 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600973 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500974 cpv = package_info.SplitCPV(package)
975 if not cpv:
976 raise NoAndroidVersionError(
977 'Android version could not be determined for %s' % board)
978 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600979
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700980
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500981def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600982 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500983 if not package:
984 package = determine_android_package(board)
985 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600986 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500987 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600988 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900989 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900990 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600991 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
992 for target in targets:
993 if target in ebuild_content:
994 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
995 if branch is not None:
996 return branch.group(1)
997 raise NoAndroidBranchError(
998 'Android branch could not be determined for %s (ebuild empty?)' % board)
999
1000
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001001def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -06001002 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001003 if not package:
1004 package = determine_android_package(board)
1005 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001006 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001007 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001008 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001009 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001010 return 'cheets'
1011
1012 raise NoAndroidTargetError(
1013 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001014 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001015
1016
1017def determine_platform_version():
1018 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001019 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001020 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1021 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001022
1023
1024def determine_milestone_version():
1025 """Returns the platform version from the source root."""
1026 # Milestone version is something like '79'.
1027 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1028 return version.chrome_branch
1029
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001030
Michael Mortensen009cb662019-10-21 11:38:43 -06001031def determine_full_version():
1032 """Returns the full version from the source root."""
1033 # Full version is something like 'R79-12575.0.0'.
1034 milestone_version = determine_milestone_version()
1035 platform_version = determine_platform_version()
1036 full_version = ('R%s-%s' % (milestone_version, platform_version))
1037 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001038
1039
Michael Mortensende716a12020-05-15 11:27:00 -06001040def find_fingerprints(build_target):
1041 """Returns a list of fingerprints for this build.
1042
1043 Args:
1044 build_target (build_target_lib.BuildTarget): The build target.
1045
1046 Returns:
1047 list[str] - List of fingerprint strings.
1048 """
1049 cros_build_lib.AssertInsideChroot()
1050 fp_file = 'cheets-fingerprint.txt'
1051 fp_path = os.path.join(
1052 image_lib.GetLatestImageLink(build_target.name),
1053 fp_file)
1054 if not os.path.isfile(fp_path):
1055 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001056 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001057 logging.info('Reading fingerprint file: %s', fp_path)
1058 fingerprints = osutils.ReadFile(fp_path).splitlines()
1059 return fingerprints
1060
1061
Michael Mortensen59e30872020-05-18 14:12:49 -06001062def get_all_firmware_versions(build_target):
1063 """Extract firmware version for all models present.
1064
1065 Args:
1066 build_target (build_target_lib.BuildTarget): The build target.
1067
1068 Returns:
1069 A dict of FirmwareVersions namedtuple instances by model.
1070 Each element will be populated based on whether it was present in the
1071 command output.
1072 """
1073 cros_build_lib.AssertInsideChroot()
1074 result = {}
1075 # Note that example output for _get_firmware_version_cmd_result is available
1076 # in the packages_unittest.py for testing get_all_firmware_versions.
1077 cmd_result = _get_firmware_version_cmd_result(build_target)
1078
1079 # There is a blank line between the version info for each model.
1080 firmware_version_payloads = cmd_result.split('\n\n')
1081 for firmware_version_payload in firmware_version_payloads:
1082 if 'BIOS' in firmware_version_payload:
1083 firmware_version = _find_firmware_versions(firmware_version_payload)
1084 result[firmware_version.model] = firmware_version
1085 return result
1086
1087
Michael Mortensen71ef5682020-05-07 14:29:24 -06001088FirmwareVersions = collections.namedtuple(
1089 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1090
1091
1092def get_firmware_versions(build_target):
1093 """Extract version information from the firmware updater, if one exists.
1094
1095 Args:
1096 build_target (build_target_lib.BuildTarget): The build target.
1097
1098 Returns:
1099 A FirmwareVersions namedtuple instance.
1100 Each element will either be set to the string output by the firmware
1101 updater shellball, or None if there is no firmware updater.
1102 """
1103 cros_build_lib.AssertInsideChroot()
1104 cmd_result = _get_firmware_version_cmd_result(build_target)
1105 if cmd_result:
1106 return _find_firmware_versions(cmd_result)
1107 else:
1108 return FirmwareVersions(None, None, None, None, None)
1109
1110
1111def _get_firmware_version_cmd_result(build_target):
1112 """Gets the raw result output of the firmware updater version command.
1113
1114 Args:
1115 build_target (build_target_lib.BuildTarget): The build target.
1116
1117 Returns:
1118 Command execution result.
1119 """
1120 updater = os.path.join(build_target.root,
1121 'usr/sbin/chromeos-firmwareupdate')
1122 logging.info('Calling updater %s', updater)
1123 # Call the updater using the chroot-based path.
1124 return cros_build_lib.run([updater, '-V'],
1125 capture_output=True, log_output=True,
1126 encoding='utf-8').stdout
1127
1128
1129def _find_firmware_versions(cmd_output):
1130 """Finds firmware version output via regex matches against the cmd_output.
1131
1132 Args:
1133 cmd_output: The raw output to search against.
1134
1135 Returns:
1136 FirmwareVersions namedtuple with results.
1137 Each element will either be set to the string output by the firmware
1138 updater shellball, or None if there is no match.
1139 """
1140
1141 # Sometimes a firmware bundle includes a special combination of RO+RW
1142 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1143 # version" field. In other cases, the "(RW) version" field is not present.
1144 # Therefore, search for the "(RW)" fields first and if they aren't present,
1145 # fallback to the other format. e.g. just "BIOS version:".
1146 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1147 main = None
1148 main_rw = None
1149 ec = None
1150 ec_rw = None
1151 model = None
1152
1153 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1154 if match:
1155 main = match.group('version')
1156
1157 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1158 if match:
1159 main_rw = match.group('version')
1160
1161 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1162 if match:
1163 ec = match.group('version')
1164
1165 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1166 if match:
1167 ec_rw = match.group('version')
1168
1169 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1170 if match:
1171 model = match.group('model')
1172
1173 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001174
1175
1176MainEcFirmwareVersions = collections.namedtuple(
1177 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1178
1179def determine_firmware_versions(build_target):
1180 """Returns a namedtuple with main and ec firmware versions.
1181
1182 Args:
1183 build_target (build_target_lib.BuildTarget): The build target.
1184
1185 Returns:
1186 MainEcFirmwareVersions namedtuple with results.
1187 """
1188 fw_versions = get_firmware_versions(build_target)
1189 main_fw_version = fw_versions.main_rw or fw_versions.main
1190 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1191
1192 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001193
1194def determine_kernel_version(build_target):
1195 """Returns a string containing the kernel version for this build target.
1196
1197 Args:
1198 build_target (build_target_lib.BuildTarget): The build target.
1199
1200 Returns:
1201 (str) The kernel versions, or None.
1202 """
1203 try:
1204 packages = portage_util.GetPackageDependencies(build_target.name,
1205 'virtual/linux-sources')
1206 except cros_build_lib.RunCommandError as e:
1207 logging.warning('Unable to get package list for metadata: %s', e)
1208 return None
1209 for package in packages:
1210 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001211 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001212 logging.info('Found active kernel version: %s', kernel_version)
1213 return kernel_version
1214 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001215
1216
1217def get_models(build_target, log_output=True):
1218 """Obtain a list of models supported by a unified board.
1219
1220 This ignored whitelabel models since GoldenEye has no specific support for
1221 these at present.
1222
1223 Args:
1224 build_target (build_target_lib.BuildTarget): The build target.
1225 log_output: Whether to log the output of the cros_config_host invocation.
1226
1227 Returns:
1228 A list of models supported by this board, if it is a unified build; None,
1229 if it is not a unified build.
1230 """
1231 return _run_cros_config_host(build_target, ['list-models'],
1232 log_output=log_output)
1233
1234
Michael Mortensen359c1f32020-05-28 19:35:42 -06001235def get_key_id(build_target, model):
1236 """Obtain the key_id for a model within the build_target.
1237
1238 Args:
1239 build_target (build_target_lib.BuildTarget): The build target.
1240 model (str): The model name
1241
1242 Returns:
1243 A key_id (str) or None.
1244 """
1245 model_arg = '--model=' + model
1246 key_id_list = _run_cros_config_host(
1247 build_target,
1248 [model_arg, 'get', '/firmware-signing', 'key-id'])
1249 key_id = None
1250 if len(key_id_list) == 1:
1251 key_id = key_id_list[0]
1252 return key_id
1253
1254
Michael Mortensen125bb012020-05-21 14:02:10 -06001255def _run_cros_config_host(build_target, args, log_output=True):
1256 """Run the cros_config_host tool.
1257
1258 Args:
1259 build_target (build_target_lib.BuildTarget): The build target.
1260 args: List of arguments to pass.
1261 log_output: Whether to log the output of the cros_config_host.
1262
1263 Returns:
1264 Output of the tool
1265 """
1266 cros_build_lib.AssertInsideChroot()
1267 tool = '/usr/bin/cros_config_host'
1268 if not os.path.isfile(tool):
1269 return None
1270
1271 config_fname = build_target.full_path(
1272 'usr/share/chromeos-config/yaml/config.yaml')
1273
1274 result = cros_build_lib.run(
1275 [tool, '-c', config_fname] + args,
1276 capture_output=True,
1277 encoding='utf-8',
1278 log_output=log_output,
1279 check=False)
1280 if result.returncode:
1281 # Show the output for debugging purposes.
1282 if 'No such file or directory' not in result.error:
1283 logging.error('cros_config_host failed: %s\n', result.error)
1284 return None
1285 return result.output.strip().splitlines()