blob: 08fe9c4df9b6a259ef2379b8eb6cb9a81d990855 [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 Klein68a28712021-11-08 11:08:30 -070016from typing import Iterable, List, NamedTuple, 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
Shao-Chuan Lee05e51142021-11-24 12:27:37 +090031from chromite.service import android
Alex Kleineb77ffa2019-05-28 14:47:44 -060032
Alex Klein5caab872021-09-10 11:44:37 -060033if TYPE_CHECKING:
34 from chromite.lib import build_target_lib
Alex Klein16ea1b32021-10-01 15:48:50 -060035 from chromite.lib import chroot_lib
Chris McDonaldf7c03d42021-07-21 11:54:26 -060036
Alex Klein36b117f2019-09-30 15:13:46 -060037if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060038 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060039 from chromite.service import dependency
40
Alex Klein87531182019-08-12 15:23:37 -060041# Registered handlers for uprevving versioned packages.
42_UPREV_FUNCS = {}
43
Alex Kleineb77ffa2019-05-28 14:47:44 -060044
45class Error(Exception):
46 """Module's base error class."""
47
48
Alex Klein4de25e82019-08-05 15:58:39 -060049class UnknownPackageError(Error):
50 """Uprev attempted for a package without a registered handler."""
51
52
Alex Kleineb77ffa2019-05-28 14:47:44 -060053class UprevError(Error):
54 """An error occurred while uprevving packages."""
55
56
Michael Mortensenb70e8a82019-10-10 18:43:41 -060057class NoAndroidVersionError(Error):
58 """An error occurred while trying to determine the android version."""
59
60
61class NoAndroidBranchError(Error):
62 """An error occurred while trying to determine the android branch."""
63
64
65class NoAndroidTargetError(Error):
66 """An error occurred while trying to determine the android target."""
67
68
Alex Klein4de25e82019-08-05 15:58:39 -060069class AndroidIsPinnedUprevError(UprevError):
70 """Raised when we try to uprev while Android is pinned."""
71
72 def __init__(self, new_android_atom):
73 """Initialize a AndroidIsPinnedUprevError.
74
75 Args:
76 new_android_atom: The Android atom that we failed to
77 uprev to, due to Android being pinned.
78 """
79 assert new_android_atom
80 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
81 new_android_atom)
Jae Hoon Kimad176b82021-07-26 19:29:29 +000082 super().__init__(msg)
Alex Klein4de25e82019-08-05 15:58:39 -060083 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060084
85
Andrew Lamb9563a152019-12-04 11:42:18 -070086class GeneratedCrosConfigFilesError(Error):
87 """Error when cros_config_schema does not produce expected files"""
88
89 def __init__(self, expected_files, found_files):
90 msg = ('Expected to find generated C files: %s. Actually found: %s' %
91 (expected_files, found_files))
Jae Hoon Kimad176b82021-07-26 19:29:29 +000092 super().__init__(msg)
Andrew Lamb9563a152019-12-04 11:42:18 -070093
Alex Klein7a3a7dd2020-01-08 16:44:38 -070094
Alex Klein6becabc2020-09-11 14:03:05 -060095NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
96 'needs_chrome_source',
97 'builds_chrome',
98 'packages',
99 'missing_chrome_prebuilt',
100 'missing_follower_prebuilt',
Alex Klein9ce3f682021-06-23 15:06:44 -0600101 'local_uprev',
Alex Klein6becabc2020-09-11 14:03:05 -0600102))
103
104
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600105def patch_ebuild_vars(ebuild_path, variables):
106 """Updates variables in ebuild.
107
108 Use this function rather than portage_util.EBuild.UpdateEBuild when you
109 want to preserve the variable position and quotes within the ebuild.
110
111 Args:
112 ebuild_path: The path of the ebuild.
113 variables: Dictionary of variables to update in ebuild.
114 """
115 try:
116 for line in fileinput.input(ebuild_path, inplace=1):
117 varname, eq, _ = line.partition('=')
118 if eq == '=' and varname.strip() in variables:
119 value = variables[varname]
120 sys.stdout.write('%s="%s"\n' % (varname, value))
121 else:
122 sys.stdout.write(line)
123 finally:
124 fileinput.close()
125
126
Alex Klein87531182019-08-12 15:23:37 -0600127def uprevs_versioned_package(package):
128 """Decorator to register package uprev handlers."""
129 assert package
130
131 def register(func):
132 """Registers |func| as a handler for |package|."""
133 _UPREV_FUNCS[package] = func
134
135 @functools.wraps(func)
136 def pass_through(*args, **kwargs):
137 return func(*args, **kwargs)
138
139 return pass_through
140
141 return register
142
143
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900144class UprevAndroidResult(NamedTuple):
145 """Results of an Android uprev."""
146 revved: bool
147 android_atom: str = None
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900148 modified_files: List[str] = None
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900149
150
151def uprev_android(
152 android_package: str,
153 chroot: 'chroot_lib.Chroot',
154 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
155 android_build_branch: Optional[str] = None,
156 android_version: Optional[str] = None,
157 skip_commit: bool = False) -> UprevAndroidResult:
158 """Performs an Android uprev by calling cros_mark_android_as_stable.
159
160 Args:
161 android_package: The Android package to uprev.
162 chroot: The chroot to enter.
163 build_targets: List of build targets to cleanup after uprev.
164 android_build_branch: Override the default Android branch corresponding to
165 the package.
166 android_version: Uprev to the particular version. By default the latest
167 available version is used.
168 skip_commit: Whether to skip committing the change after a successful uprev.
169
170 Returns:
171 The uprev result containing:
172 revved: Whether an uprev happened.
173 android_atom: If revved, the portage atom for the revved Android ebuild.
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900174 modified_files: If revved, list of files being modified.
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900175 """
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700176 command = [
177 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900178 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700179 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600180 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900181 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900182 if android_build_branch:
183 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600184 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900185 command.append(f'--force_version={android_version}')
186 if skip_commit:
187 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600188
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700189 result = cros_build_lib.run(
190 command,
191 stdout=True,
192 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500193 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700194 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600195
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900196 # cros_mark_android_as_stable prints the uprev result to stdout as JSON in a
197 # single line. We only take the last line from stdout to make sure no junk
198 # output is included (e.g. messages from bashrc scripts that run upon entering
199 # the chroot.)
200 output = json.loads(result.stdout.strip().splitlines()[-1])
201
202 if not output['revved']:
Alex Klein4de25e82019-08-05 15:58:39 -0600203 logging.info('Found nothing to rev.')
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900204 return UprevAndroidResult(revved=False)
205
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900206 android_atom = output['android_atom']
Alex Klein4de25e82019-08-05 15:58:39 -0600207
208 for target in build_targets or []:
209 # Sanity check: We should always be able to merge the version of
210 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900211 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600212 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700213 cros_build_lib.run(
214 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600215 except cros_build_lib.RunCommandError:
216 logging.error(
217 'Cannot emerge-%s =%s\nIs Android pinned to an older '
218 'version?', target, android_atom)
219 raise AndroidIsPinnedUprevError(android_atom)
220
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900221 return UprevAndroidResult(revved=True,
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900222 android_atom=android_atom,
223 modified_files=output['modified_files'])
224
225
226def uprev_android_lkgb(android_package: str,
227 build_targets: List['build_target_lib.BuildTarget'],
228 chroot: 'chroot_lib.Chroot'
229 ) -> uprev_lib.UprevVersionedPackageResult:
230 """Uprevs an Android package to the version specified in the LKGB file.
231
232 This is the PUpr handler for Android packages, triggered whenever the
233 corresponding LKGB file is being updated.
234
235 PUpr for Android does not test the uprev change in CQ; instead we run separate
236 jobs to test new Android versions, and we write the latest vetted version to
237 the LKGB file. Find the design at go/android-uprev-recipes.
238
239 Args:
240 android_package: The Android package to uprev.
241 build_targets: List of build targets to cleanup after uprev.
242 chroot: The chroot to enter.
243
244 Returns:
245 An uprev_lib.UprevVersionedPackageResult containing the new version and a
246 list of modified files.
247 """
Shao-Chuan Lee0e787d22021-12-13 21:33:35 +0900248 android_package_dir = android.GetAndroidPackageDir(android_package)
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900249 android_version = android.ReadLKGB(android_package_dir)
250
251 result = uprev_lib.UprevVersionedPackageResult()
252 uprev_result = uprev_android(android_package, chroot,
253 build_targets=build_targets,
254 android_version=android_version,
255 skip_commit=True)
256 if not uprev_result.revved:
257 return result
258
Shao-Chuan Lee0e787d22021-12-13 21:33:35 +0900259 # cros_mark_android_as_stable returns paths relative to |android.OVERLAY_DIR|.
260 result.add_result(android_version,
261 [os.path.join(android.OVERLAY_DIR, f)
262 for f in uprev_result.modified_files])
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900263 return result
264
265
266def define_uprev_android_lkgb_handlers():
267 """Dynamically define uprev handlers for each Android package"""
268
269 def define_handler(android_package):
270 """Defines the uprev handler for an Android package."""
271 full_package_name = 'chromeos-base/' + android_package
272
273 @uprevs_versioned_package(full_package_name)
274 def _handler(build_targets, _refs, chroot):
275 return uprev_android_lkgb(android_package, build_targets, chroot)
276
277 for android_package in constants.ANDROID_ALL_PACKAGES:
278 define_handler(android_package)
279
280
281define_uprev_android_lkgb_handlers()
Alex Klein4de25e82019-08-05 15:58:39 -0600282
283
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700284def uprev_build_targets(
285 build_targets: Optional[List['build_target_lib.BuildTarget']],
286 overlay_type: str,
287 chroot: 'chroot_lib.Chroot' = None,
288 output_dir: Optional[str] = None):
Alex Kleineb77ffa2019-05-28 14:47:44 -0600289 """Uprev the set provided build targets, or all if not specified.
290
291 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700292 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600293 whose overlays should be uprevved, empty or None for all.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700294 overlay_type: One of the valid overlay types except None (see
Alex Kleineb77ffa2019-05-28 14:47:44 -0600295 constants.VALID_OVERLAYS).
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700296 chroot: The chroot to clean, if desired.
297 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600298 """
299 # Need a valid overlay, but exclude None.
300 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
301
302 if build_targets:
303 overlays = portage_util.FindOverlaysForBoards(
304 overlay_type, boards=[t.name for t in build_targets])
305 else:
306 overlays = portage_util.FindOverlays(overlay_type)
307
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700308 return uprev_overlays(
309 overlays,
310 build_targets=build_targets,
311 chroot=chroot,
312 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600313
314
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700315def uprev_overlays(
316 overlays: List[str],
317 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
318 chroot: Optional['chroot_lib.Chroot'] = None,
319 output_dir: Optional[str] = None) -> List[str]:
Alex Kleineb77ffa2019-05-28 14:47:44 -0600320 """Uprev the given overlays.
321
322 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700323 overlays: The list of overlay paths.
324 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600325 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700326 chroot: The chroot to clean, if desired.
327 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600328
329 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700330 The paths to all of the modified ebuild files. This includes the new files
331 that were added (i.e. the new versions) and all of the removed files
332 (i.e. the old versions).
Alex Kleineb77ffa2019-05-28 14:47:44 -0600333 """
334 assert overlays
335
336 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
337
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700338 uprev_manager = uprev_lib.UprevOverlayManager(
339 overlays,
340 manifest,
341 build_targets=build_targets,
342 chroot=chroot,
343 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600344 uprev_manager.uprev()
345
Dhanya Ganeshd03a4162021-08-25 00:21:50 +0000346 return uprev_manager.modified_ebuilds, uprev_manager.revved_packages
Alex Kleineb77ffa2019-05-28 14:47:44 -0600347
348
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700349def uprev_versioned_package(
350 package: package_info.CPV,
351 build_targets: List['build_target_lib.BuildTarget'],
352 refs: List[uprev_lib.GitRef],
353 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
Alex Klein87531182019-08-12 15:23:37 -0600354 """Call registered uprev handler function for the package.
355
356 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700357 package: The package being uprevved.
358 build_targets: The build targets to clean on a successful uprev.
359 refs:
360 chroot: The chroot to enter for cleaning.
Alex Klein87531182019-08-12 15:23:37 -0600361
362 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700363 The result.
Alex Klein87531182019-08-12 15:23:37 -0600364 """
365 assert package
366
367 if package.cp not in _UPREV_FUNCS:
368 raise UnknownPackageError(
369 'Package "%s" does not have a registered handler.' % package.cp)
370
Andrew Lambea9a8a22019-12-12 14:03:43 -0700371 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600372
373
Navil Perezf57ba872020-06-04 22:38:37 +0000374@uprevs_versioned_package('media-libs/virglrenderer')
375def uprev_virglrenderer(_build_targets, refs, _chroot):
376 """Updates virglrenderer ebuilds.
377
378 See: uprev_versioned_package.
379
380 Returns:
381 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
382 """
Navil Perezf57ba872020-06-04 22:38:37 +0000383 overlay = os.path.join(constants.SOURCE_ROOT,
384 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600385 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
386 'virglrenderer')
387 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000388
389 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
390 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000391 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
392 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000393 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
394
George Engelbrechte73f2782020-06-10 14:10:46 -0600395 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600396 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000397 result.add_result(refs[0].revision, updated_files)
398 return result
399
Jose Magana03b5a842020-08-19 12:52:59 +1000400@uprevs_versioned_package('chromeos-base/drivefs')
401def uprev_drivefs(_build_targets, refs, chroot):
402 """Updates drivefs ebuilds.
403
Harvey Yang3eee06c2021-03-18 15:47:56 +0800404 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000405 See: uprev_versioned_package.
406
407 Returns:
408 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
409 """
410
Ben Reiche779cf42020-12-15 03:21:31 +0000411 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000412 result = uprev_lib.UprevVersionedPackageResult()
413 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000414
Harvey Yang3eee06c2021-03-18 15:47:56 +0800415 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
416 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000417 if not drivefs_version:
418 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000419 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000420
Ben Reiche779cf42020-12-15 03:21:31 +0000421 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000422
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000423 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000424 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000425 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000426 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800427 chroot,
428 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000429
430 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000431 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000432 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000433 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000434
435 return result
436
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800437@uprevs_versioned_package('chromeos-base/perfetto')
438def uprev_perfetto(_build_targets, refs, chroot):
439 """Updates Perfetto ebuilds.
440
Harvey Yang3eee06c2021-03-18 15:47:56 +0800441 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800442 See: uprev_versioned_package.
443
444 Returns:
445 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
446 """
447 result = uprev_lib.UprevVersionedPackageResult()
448
Harvey Yang3eee06c2021-03-18 15:47:56 +0800449 PERFETTO_REFS_PREFIX = 'refs/tags/v'
450 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800451 if not perfetto_version:
452 # No valid Perfetto version is identified.
453 return result
454
455 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
456
457 # Attempt to uprev perfetto package.
458 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
459
Harvey Yang3eee06c2021-03-18 15:47:56 +0800460 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
461 PERFETTO_PATH,
462 perfetto_version,
463 chroot,
464 allow_downrev=False,
465 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800466
467 if not uprev_result:
468 return result
469
470 result.add_result(perfetto_version, uprev_result.changed_files)
471
472 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000473
Yaakov Shaul395ae832019-09-09 14:45:32 -0600474@uprevs_versioned_package('afdo/kernel-profiles')
475def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600476 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600477
478 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600479
480 Raises:
481 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600482 """
483 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
484 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
485
David Burger92485342019-09-10 17:52:45 -0600486 with open(path, 'r') as f:
487 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600488
Chris McDonald38409112020-09-24 11:24:51 -0600489 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600490 for kernel_pkg, version_info in versions.items():
491 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
492 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600493 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600494 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600495 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600496 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600497 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600498 patch_ebuild_vars(ebuild_path,
499 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600500
501 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600502 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400503 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600504 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600505 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600506 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600507 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600508
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600509 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600510
Yaakov Shaul730814a2019-09-10 13:58:25 -0600511 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
512
513 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600514
515
Trent Begineb624182020-07-14 10:09:45 -0600516@uprevs_versioned_package('chromeos-base/termina-dlc')
Maciek Swiech6b12f662022-01-25 16:51:19 +0000517@uprevs_versioned_package('chromeos-base/termina-tools-dlc')
518def uprev_termina_dlcs(_build_targets, _refs, chroot):
519 """Updates shared termina-dlc and termina-tools-dlc ebuilds.
520
521 termina-dlc - chromeos-base/termina-dlc
522 termina-tools-dlc - chromeos-base/termina-tools-dlc
Trent Beginaf51f1b2020-03-09 17:35:31 -0600523
524 See: uprev_versioned_package.
525 """
Maciek Swiech6b12f662022-01-25 16:51:19 +0000526 termina_dlc_pkg = 'termina-dlc'
527 termina_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
528 'chromeos-base', termina_dlc_pkg)
529 tools_dlc_pkg = 'termina-tools-dlc'
530 tools_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
531 'chromeos-base', tools_dlc_pkg)
Patrick Meiring5897add2020-09-16 16:30:17 +1000532
Maciek Swiech6b12f662022-01-25 16:51:19 +0000533 # termina-dlc and termina-tools-dlc are pinned to the same version.
534 version_pin_src_path = _get_version_pin_src_path(termina_dlc_pkg_path)
Patrick Meiring5897add2020-09-16 16:30:17 +1000535 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
536
Maciek Swiech6b12f662022-01-25 16:51:19 +0000537 result = uprev_lib.uprev_ebuild_from_pin(termina_dlc_pkg_path, version_no_rev,
538 chroot)
539 result += uprev_lib.uprev_ebuild_from_pin(tools_dlc_pkg_path, version_no_rev,
540 chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000541
Maciek Swiech6b12f662022-01-25 16:51:19 +0000542 return result
Patrick Meiring5897add2020-09-16 16:30:17 +1000543
Julio Hurtadof1befec2021-05-05 21:34:26 +0000544@uprevs_versioned_package('chromeos-base/chromeos-lacros')
545def uprev_lacros(_build_targets, refs, chroot):
546 """Updates lacros ebuilds.
547
Julio Hurtadoa994e002021-07-07 17:57:45 +0000548 Version to uprev to is gathered from the QA qualified version tracking file
549 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
550 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000551
552 See: uprev_versioned_package.
553 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000554 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000555 path = os.path.join(
Dennis Kempin257b74c2021-09-28 14:38:17 -0700556 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000557 lacros_version = refs[0].revision
558 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
559 lacros_version,
560 chroot,
561 allow_downrev=False)
562
563 if not uprev_result:
564 return result
565
566 result.add_result(lacros_version, uprev_result.changed_files)
567 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000568
569
Julio Hurtado870ed322021-12-03 18:22:40 +0000570@uprevs_versioned_package('chromeos-base/chromeos-lacros-parallel')
571def uprev_lacros_in_parallel(
572 _build_targets: Optional[List['build_target_lib.BuildTarget']],
573 refs: List[uprev_lib.GitRef],
574 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
575 """Updates lacros ebuilds in parallel with ash-chrome.
576
577 This handler is going to be used temporarily while lacros transitions to being
578 uprevved atomically with ash-chrome. Unlike a standalone lacros uprev, this
579 handler will not need to look at the QA qualified file. Rather, it will
580 function identical to ash-chrome using git tags.
581
582 See: uprev_versioned_package.
583
584 Returns:
585 UprevVersionedPackageResult: The result.
586 """
587 result = uprev_lib.UprevVersionedPackageResult()
588 path = os.path.join(
589 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
590 lacros_version = uprev_lib.get_version_from_refs(refs)
591 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
592 lacros_version,
593 chroot,
594 allow_downrev=False)
595
596 if not uprev_result:
597 return result
598
599 result.add_result(lacros_version, uprev_result.changed_files)
600 return result
601
602
Patrick Meiring5897add2020-09-16 16:30:17 +1000603@uprevs_versioned_package('app-emulation/parallels-desktop')
604def uprev_parallels_desktop(_build_targets, _refs, chroot):
605 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
606
607 See: uprev_versioned_package
608
609 Returns:
610 UprevVersionedPackageResult: The result.
611 """
612 package = 'parallels-desktop'
613 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
614 'app-emulation', package)
615 version_pin_src_path = _get_version_pin_src_path(package_path)
616
617 # Expect a JSON blob like the following:
618 # {
619 # "version": "1.2.3",
620 # "test_image": { "url": "...", "size": 12345678,
621 # "sha256sum": "<32 bytes of hexadecimal>" }
622 # }
623 with open(version_pin_src_path, 'r') as f:
624 pinned = json.load(f)
625
626 if 'version' not in pinned or 'test_image' not in pinned:
627 raise UprevError('VERSION-PIN for %s missing version and/or '
628 'test_image field' % package)
629
630 version = pinned['version']
631 if not isinstance(version, str):
632 raise UprevError('version in VERSION-PIN for %s not a string' % package)
633
634 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600635 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000636
637 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100638 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
639 'local/bundles/crosint/pita/data/'
640 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000641 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
642 with open(test_image_src_path, 'w') as f:
643 json.dump(pinned['test_image'], f, indent=2)
644 result.add_result(version, [test_image_src_path])
645
646 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600647
648
Trent Begin315d9d92019-12-03 21:55:53 -0700649@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600650def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700651 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
652
653 See: uprev_versioned_package.
654 """
655 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700656 package_path = os.path.join('src', 'private-overlays',
657 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000658 version_pin_src_path = _get_version_pin_src_path(package_path)
659 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700660
Chris McDonald38409112020-09-24 11:24:51 -0600661 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700662
663
David Riley8513c1f2021-10-14 17:07:41 -0700664@uprevs_versioned_package('chromeos-base/borealis-dlc')
665def uprev_borealis_dlc(_build_targets, _refs, chroot):
666 """Updates shared borealis-dlc ebuild - chromeos-base/borealis-dlc.
667
668 See: uprev_versioned_package.
669 """
David Rileybc100ba2022-01-10 10:06:59 -0800670 package_path = os.path.join('src', 'private-overlays',
671 'chromeos-partner-overlay', 'chromeos-base',
672 'borealis-dlc')
David Riley8513c1f2021-10-14 17:07:41 -0700673
674 version_pin_src_path = _get_version_pin_src_path(package_path)
675 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
676
677 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
678
679
Patrick Meiring5897add2020-09-16 16:30:17 +1000680def _get_version_pin_src_path(package_path):
681 """Returns the path to the VERSION-PIN file for the given package."""
682 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
683
684
Alex Klein87531182019-08-12 15:23:37 -0600685@uprevs_versioned_package(constants.CHROME_CP)
Alex Klein4e839252022-01-06 13:29:18 -0700686def uprev_chrome_from_ref(build_targets, refs, _chroot):
Alex Klein87531182019-08-12 15:23:37 -0600687 """Uprev chrome and its related packages.
688
689 See: uprev_versioned_package.
690 """
691 # Determine the version from the refs (tags), i.e. the chrome versions are the
692 # tag names.
Julio Hurtado870ed322021-12-03 18:22:40 +0000693 chrome_version = uprev_lib.get_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600694 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600695
Alex Klein4e839252022-01-06 13:29:18 -0700696 return uprev_chrome(chrome_version, build_targets, None)
Alex Kleinf69bd802021-06-22 15:43:49 -0600697
698
Alex Klein9ce3f682021-06-23 15:06:44 -0600699def revbump_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600700 build_targets: List['build_target_lib.BuildTarget'] = None,
Alex Klein9ce3f682021-06-23 15:06:44 -0600701 chroot: Optional['chroot_lib.Chroot'] = None
702) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600703 """Attempt to revbump chrome.
704
705 Revbumps are done by executing an uprev using the current stable version.
706 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
707 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
708 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
709 """
710 chrome_version = uprev_lib.get_stable_chrome_version()
Alex Klein16ea1b32021-10-01 15:48:50 -0600711 return uprev_chrome(chrome_version, build_targets, chroot)
Alex Kleinf69bd802021-06-22 15:43:49 -0600712
713
Alex Klein9ce3f682021-06-23 15:06:44 -0600714def uprev_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600715 chrome_version: str,
716 build_targets: Optional[List['build_target_lib.BuildTarget']],
717 chroot: Optional['chroot_lib.Chroot']
Alex Klein9ce3f682021-06-23 15:06:44 -0600718) -> uprev_lib.UprevVersionedPackageResult:
719 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600720 uprev_manager = uprev_lib.UprevChromeManager(
721 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600722 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600723 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
724 # attempt. The expected behavior is documented in the following table:
725 #
726 # Outcome of Chrome uprev attempt:
727 # NEWER_VERSION_EXISTS:
728 # Do nothing.
729 # SAME_VERSION_EXISTS or REVISION_BUMP:
730 # Uprev followers
731 # Assert not VERSION_BUMP (any other outcome is fine)
732 # VERSION_BUMP or NEW_EBUILD_CREATED:
733 # Uprev followers
734 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600735
736 # Start with chrome itself so we can proceed accordingly.
737 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
738 if chrome_result.newer_version_exists:
739 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600740 return result
Alex Klein87531182019-08-12 15:23:37 -0600741
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600742 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600743 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600744 follower_result = uprev_manager.uprev(package)
745 if chrome_result.stable_version and follower_result.version_bump:
746 logging.warning('%s had a version bump, but no more than a revision bump '
747 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600748
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600749 if uprev_manager.modified_ebuilds:
750 # Record changes when we have them.
751 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
752
753 return result
Alex Klein87531182019-08-12 15:23:37 -0600754
755
Harvey Yang3eee06c2021-03-18 15:47:56 +0800756def _get_latest_version_from_refs(refs_prefix: str,
757 refs: List[uprev_lib.GitRef]) -> str:
758 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000759
Ben Reiche779cf42020-12-15 03:21:31 +0000760 Versions are compared using |distutils.version.LooseVersion| and
761 the latest version is returned.
762
763 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800764 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800765 refs: The tags to parse for the latest Perfetto version.
766
767 Returns:
768 The latest Perfetto version to use.
769 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800770 valid_refs = []
771 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800772 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800773 valid_refs.append(gitiles.ref)
774
775 if not valid_refs:
776 return None
777
778 # Sort by version and take the latest version.
779 target_version_ref = sorted(valid_refs,
780 key=LooseVersion,
781 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800782 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800783
784
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700785def _generate_platform_c_files(
786 replication_config: replication_config_pb2.ReplicationConfig,
787 chroot: 'chroot_lib.Chroot') -> List[str]:
Andrew Lamb9563a152019-12-04 11:42:18 -0700788 """Generates platform C files from a platform JSON payload.
789
790 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700791 replication_config: A ReplicationConfig that has already been run. If it
792 produced a build_config.json file, that file will be used to generate
793 platform C files. Otherwise, nothing will be generated.
794 chroot: The chroot to use to generate.
Andrew Lamb9563a152019-12-04 11:42:18 -0700795
796 Returns:
797 A list of generated files.
798 """
799 # Generate the platform C files from the build config. Note that it would be
800 # more intuitive to generate the platform C files from the platform config;
801 # however, cros_config_schema does not allow this, because the platform config
802 # payload is not always valid input. For example, if a property is both
803 # 'required' and 'build-only', it will fail schema validation. Thus, use the
804 # build config, and use '-f' to filter.
805 build_config_path = [
806 rule.destination_path
807 for rule in replication_config.file_replication_rules
808 if rule.destination_path.endswith('build_config.json')
809 ]
810
811 if not build_config_path:
812 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700813 'No build_config.json found, will not generate platform C files. '
814 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700815 return []
816
817 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700818 raise ValueError('Expected at most one build_config.json destination path. '
819 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700820
821 build_config_path = build_config_path[0]
822
823 # Paths to the build_config.json and dir to output C files to, in the
824 # chroot.
825 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
826 build_config_path)
827 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
828 os.path.dirname(build_config_path))
829
830 command = [
831 'cros_config_schema', '-m', build_config_chroot_path, '-g',
832 generated_output_chroot_dir, '-f', '"TRUE"'
833 ]
834
835 cros_build_lib.run(
836 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
837
838 # A relative (to the source root) path to the generated C files.
839 generated_output_dir = os.path.dirname(build_config_path)
840 generated_files = []
841 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
842 for f in expected_c_files:
843 if os.path.exists(
844 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
845 generated_files.append(os.path.join(generated_output_dir, f))
846
847 if len(expected_c_files) != len(generated_files):
848 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
849
850 return generated_files
851
852
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700853def _get_private_overlay_package_root(ref: uprev_lib.GitRef, package: str):
Andrew Lambe836f222019-12-09 12:27:38 -0700854 """Returns the absolute path to the root of a given private overlay.
855
856 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700857 ref: GitRef for the private overlay.
858 package: Path to the package in the overlay.
Andrew Lambe836f222019-12-09 12:27:38 -0700859 """
860 # There might be a cleaner way to map from package -> path within the source
861 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700862 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700863 match = re.match(private_overlay_ref_pattern, ref.path)
864 if not match:
865 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
866 (private_overlay_ref_pattern, ref))
867
868 overlay = match.group(1)
869
870 return os.path.join(constants.SOURCE_ROOT,
871 'src/private-overlays/overlay-%s-private' % overlay,
872 package)
873
874
Andrew Lambea9a8a22019-12-12 14:03:43 -0700875@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
876def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700877 """Replicate a private cros_config change to the corresponding public config.
878
Alex Kleinad6b48a2020-01-08 16:57:41 -0700879 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700880 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700881 package = 'chromeos-base/chromeos-config-bsp'
882
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700883 if len(refs) != 1:
884 raise ValueError('Expected exactly one ref, actual %s' % refs)
885
886 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700887 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700888 replication_config_path = os.path.join(package_root,
889 'replication_config.jsonpb')
890
891 try:
892 replication_config = json_format.Parse(
893 osutils.ReadFile(replication_config_path),
894 replication_config_pb2.ReplicationConfig())
895 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700896 raise ValueError(
897 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700898
899 replication_lib.Replicate(replication_config)
900
901 modified_files = [
902 rule.destination_path
903 for rule in replication_config.file_replication_rules
904 ]
905
Andrew Lamb9563a152019-12-04 11:42:18 -0700906 # The generated platform C files are not easily filtered by replication rules,
907 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
908 # files cannot. Therefore, replicate and filter the JSON payloads, and then
909 # generate filtered C files from the JSON payload.
910 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700911
912 # Use the private repo's commit hash as the new version.
913 new_private_version = refs[0].revision
914
Andrew Lamb988f4da2019-12-10 10:16:43 -0700915 # modified_files should contain only relative paths at this point, but the
916 # returned UprevVersionedPackageResult must contain only absolute paths.
917 for i, modified_file in enumerate(modified_files):
918 assert not os.path.isabs(modified_file)
919 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
920
Chris McDonald38409112020-09-24 11:24:51 -0600921 return uprev_lib.UprevVersionedPackageResult().add_result(
922 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700923
924
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700925@uprevs_versioned_package('chromeos-base/crosvm')
926def uprev_crosvm(_build_targets, refs, _chroot):
927 """Updates crosvm ebuilds to latest revision
928
929 crosvm is not versioned. We are updating to the latest commit on the main
930 branch.
931
932 See: uprev_versioned_package.
933
934 Returns:
935 UprevVersionedPackageResult: The result of updating crosvm ebuilds.
936 """
937 overlay = os.path.join(constants.SOURCE_ROOT,
938 constants.CHROMIUMOS_OVERLAY_DIR)
939 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'crosvm')
940 manifest = git.ManifestCheckout.Cached(repo_path)
941
942 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
Dennis Kempin257b74c2021-09-28 14:38:17 -0700943 uprev_manager.uprev(
944 package_list=[
945 'chromeos-base/crosvm',
946 'dev-rust/assertions',
947 'dev-rust/cros_async',
948 'dev-rust/cros_fuzz',
949 'dev-rust/data_model',
950 'dev-rust/enumn',
951 'dev-rust/io_uring',
952 'dev-rust/p9',
953 'dev-rust/sync',
954 'dev-rust/sys_util',
955 'dev-rust/tempfile',
956 'media-sound/audio_streams',
957 ],
958 force=True
959 )
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700960
961 updated_files = uprev_manager.modified_ebuilds
962 result = uprev_lib.UprevVersionedPackageResult()
963 result.add_result(refs[0].revision, updated_files)
964 return result
965
966
Alex Klein5caab872021-09-10 11:44:37 -0600967def get_best_visible(
968 atom: str,
969 build_target: Optional['build_target_lib.BuildTarget'] = None
970) -> package_info.PackageInfo:
Alex Kleinbbef2b32019-08-27 10:38:50 -0600971 """Returns the best visible CPV for the given atom.
972
973 Args:
Alex Klein5caab872021-09-10 11:44:37 -0600974 atom: The atom to look up.
975 build_target: The build target whose sysroot should be searched, or the SDK
976 if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700977
978 Returns:
Alex Klein5caab872021-09-10 11:44:37 -0600979 The best visible package, or None if none are visible.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600980 """
David Burger1e0fe232019-07-01 14:52:07 -0600981 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600982
Alex Klein5caab872021-09-10 11:44:37 -0600983 return portage_util.PortageqBestVisible(
984 atom,
985 board=build_target.name if build_target else None,
986 sysroot=build_target.root if build_target else None)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600987
988
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700989def has_prebuilt(
990 atom: str,
991 build_target: 'build_target_lib.BuildTarget' = None,
992 useflags: Union[Iterable[str], str] = None) -> bool:
Alex Kleinda39c6d2019-09-16 14:36:36 -0600993 """Check if a prebuilt exists.
994
995 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700996 atom: The package whose prebuilt is being queried.
997 build_target: The build target whose sysroot should be searched, or the
998 SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700999 useflags: Any additional USE flags that should be set. May be a string
1000 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001001
1002 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001003 True if there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -06001004 """
1005 assert atom
1006
1007 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -07001008 extra_env = None
1009 if useflags:
1010 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -05001011 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -07001012 new_flags = ' '.join(useflags)
1013
1014 existing = os.environ.get('USE', '')
1015 final_flags = '%s %s' % (existing, new_flags)
1016 extra_env = {'USE': final_flags.strip()}
1017 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -06001018
1019
David Burger0f9dd4e2019-10-08 12:33:42 -06001020def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -06001021 """Check if |build_target| builds |atom| (has it in its depgraph)."""
1022 cros_build_lib.AssertInsideChroot()
1023
Alex Kleind8cd4c62020-09-14 13:37:47 -06001024 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -06001025 # TODO(crbug/1081828): Receive and use sysroot.
1026 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -06001027 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -06001028 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001029
1030
Alex Klein6becabc2020-09-11 14:03:05 -06001031def needs_chrome_source(
1032 build_target: 'build_target_lib.BuildTarget',
1033 compile_source=False,
1034 packages: Optional[List[package_info.PackageInfo]] = None,
1035 useflags=None):
1036 """Check if the chrome source is needed.
1037
1038 The chrome source is needed if the build target builds chrome or any of its
1039 follower packages, and can't use a prebuilt for them either because it's not
1040 available, or because we can't use prebuilts because it must build from
1041 source.
1042 """
1043 cros_build_lib.AssertInsideChroot()
1044
1045 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -07001046 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -06001047 builds_chrome = constants.CHROME_CP in graph
1048 builds_follower = {
1049 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
1050 }
1051
Alex Klein9ce3f682021-06-23 15:06:44 -06001052 local_uprev = builds_chrome and revbump_chrome([build_target])
1053
Alex Klein6becabc2020-09-11 14:03:05 -06001054 # When we are compiling source set False since we do not use prebuilts.
1055 # When not compiling from source, start with True, i.e. we have every prebuilt
1056 # we've checked for up to this point.
1057 has_chrome_prebuilt = not compile_source
1058 has_follower_prebuilts = not compile_source
1059 # Save packages that need prebuilts for reporting.
1060 pkgs_needing_prebuilts = []
1061 if compile_source:
1062 # Need everything.
1063 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1064 pkgs_needing_prebuilts.extend(
1065 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
1066 else:
1067 # Check chrome itself.
1068 if builds_chrome:
1069 has_chrome_prebuilt = has_prebuilt(
1070 constants.CHROME_CP, build_target=build_target, useflags=useflags)
1071 if not has_chrome_prebuilt:
1072 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1073 # Check follower packages.
1074 for pkg, builds_pkg in builds_follower.items():
1075 if not builds_pkg:
1076 continue
1077 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
1078 has_follower_prebuilts &= prebuilt
1079 if not prebuilt:
1080 pkgs_needing_prebuilts.append(pkg)
1081 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
1082 # reflect whether we actually have the corresponding prebuilts for the build.
1083
1084 needs_chrome = builds_chrome and not has_chrome_prebuilt
1085 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
1086
1087 return NeedsChromeSourceResult(
Sergey Frolov26ff97b2021-08-14 00:02:11 +00001088 needs_chrome_source=needs_chrome or needs_follower,
Alex Klein6becabc2020-09-11 14:03:05 -06001089 builds_chrome=builds_chrome,
1090 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
1091 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -06001092 missing_follower_prebuilt=not has_follower_prebuilts,
1093 local_uprev=local_uprev,
1094 )
Alex Klein6becabc2020-09-11 14:03:05 -06001095
1096
Alex Klein68a28712021-11-08 11:08:30 -07001097class TargetVersions(NamedTuple):
1098 """Data class for the info that makes up the "target versions"."""
1099 android_version: str
1100 android_branch: str
1101 android_target: str
1102 chrome_version: str
1103 platform_version: str
1104 milestone_version: str
1105 full_version: str
1106
1107
1108def get_target_versions(
1109 build_target: 'build_target_lib.BuildTarget',
1110 packages: List[package_info.PackageInfo] = None
1111) -> TargetVersions:
1112 """Aggregate version info for a few key packages and the OS as a whole."""
1113 # Android version.
1114 android_version = determine_android_version(build_target.name)
1115 logging.info('Found android version: %s', android_version)
1116 # Android branch version.
1117 android_branch = determine_android_branch(build_target.name)
1118 logging.info('Found android branch version: %s', android_branch)
1119 # Android target version.
1120 android_target = determine_android_target(build_target.name)
1121 logging.info('Found android target version: %s', android_target)
1122
1123 # TODO(crbug/1019770): Investigate cases where builds_chrome is true but
1124 # chrome_version is None.
1125
1126 builds_chrome = builds(constants.CHROME_CP, build_target, packages=packages)
1127 chrome_version = None
1128 if builds_chrome:
1129 # Chrome version fetch.
1130 chrome_version = determine_chrome_version(build_target)
1131 logging.info('Found chrome version: %s', chrome_version)
1132
1133 # The ChromeOS version info.
1134 platform_version = determine_platform_version()
1135 milestone_version = determine_milestone_version()
1136 full_version = determine_full_version()
1137
1138 return TargetVersions(android_version, android_branch, android_target,
1139 chrome_version, platform_version, milestone_version,
1140 full_version)
1141
1142
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001143def determine_chrome_version(
1144 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenc2615b72019-10-15 08:12:24 -06001145 """Returns the current Chrome version for the board (or in buildroot).
1146
1147 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001148 build_target: The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001149
1150 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001151 The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -06001152 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001153 # TODO(crbug/1019770): Long term we should not need the try/catch here once
1154 # the builds function above only returns True for chrome when
1155 # determine_chrome_version will succeed.
1156 try:
Alex Klein5caab872021-09-10 11:44:37 -06001157 pkg_info = portage_util.PortageqBestVisible(
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001158 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001159 except cros_build_lib.RunCommandError as e:
1160 # Return None because portage failed when trying to determine the chrome
1161 # version.
1162 logging.warning('Caught exception in determine_chrome_package: %s', e)
1163 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -06001164 # Something like 78.0.3877.4_rc -> 78.0.3877.4
Alex Klein5caab872021-09-10 11:44:37 -06001165 return pkg_info.version.partition('_')[0]
Michael Mortensenc2615b72019-10-15 08:12:24 -06001166
1167
Alex Klein68a28712021-11-08 11:08:30 -07001168@functools.lru_cache()
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001169def determine_android_package(board: str) -> Optional[str]:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001170 """Returns the active Android container package in use by the board.
1171
1172 Args:
1173 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001174
1175 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001176 The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001177 """
Michael Mortensene0f4b542019-10-24 15:30:23 -06001178 try:
1179 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -06001180 except cros_build_lib.RunCommandError as e:
1181 # Return None because a command (likely portage) failed when trying to
1182 # determine the package.
1183 logging.warning('Caught exception in determine_android_package: %s', e)
1184 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001185
Alex Kleinad6b48a2020-01-08 16:57:41 -07001186 # We assume there is only one Android package in the depgraph.
1187 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -04001188 if (package.startswith('chromeos-base/android-container-') or
1189 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -07001190 return package
1191 return None
1192
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001193
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001194def determine_android_version(board: str, package: str = None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001195 """Determine the current Android version in buildroot now and return it.
1196
1197 This uses the typical portage logic to determine which version of Android
1198 is active right now in the buildroot.
1199
1200 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001201 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001202 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001203
1204 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001205 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001206
1207 Raises:
1208 NoAndroidVersionError: if no unique Android version can be determined.
1209 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001210 if not package:
1211 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -05001212 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001213 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -05001214 cpv = package_info.SplitCPV(package)
1215 if not cpv:
1216 raise NoAndroidVersionError(
1217 'Android version could not be determined for %s' % board)
1218 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001219
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001220
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001221def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001222 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001223 if not package:
1224 package = determine_android_package(board)
1225 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001226 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001227 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001228 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +09001229 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +09001230 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001231 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
1232 for target in targets:
1233 if target in ebuild_content:
1234 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
1235 if branch is not None:
1236 return branch.group(1)
1237 raise NoAndroidBranchError(
1238 'Android branch could not be determined for %s (ebuild empty?)' % board)
1239
1240
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001241def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -06001242 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001243 if not package:
1244 package = determine_android_package(board)
1245 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001246 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001247 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001248 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001249 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001250 return 'cheets'
1251
1252 raise NoAndroidTargetError(
1253 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001254 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001255
1256
1257def determine_platform_version():
1258 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001259 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001260 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1261 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001262
1263
1264def determine_milestone_version():
1265 """Returns the platform version from the source root."""
1266 # Milestone version is something like '79'.
1267 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1268 return version.chrome_branch
1269
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001270
Michael Mortensen009cb662019-10-21 11:38:43 -06001271def determine_full_version():
1272 """Returns the full version from the source root."""
1273 # Full version is something like 'R79-12575.0.0'.
1274 milestone_version = determine_milestone_version()
1275 platform_version = determine_platform_version()
1276 full_version = ('R%s-%s' % (milestone_version, platform_version))
1277 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001278
1279
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001280def find_fingerprints(
1281 build_target: 'build_target_lib.BuildTarget') -> List[str]:
Michael Mortensende716a12020-05-15 11:27:00 -06001282 """Returns a list of fingerprints for this build.
1283
1284 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001285 build_target: The build target.
Michael Mortensende716a12020-05-15 11:27:00 -06001286
1287 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001288 List of fingerprint strings.
Michael Mortensende716a12020-05-15 11:27:00 -06001289 """
1290 cros_build_lib.AssertInsideChroot()
1291 fp_file = 'cheets-fingerprint.txt'
1292 fp_path = os.path.join(
1293 image_lib.GetLatestImageLink(build_target.name),
1294 fp_file)
1295 if not os.path.isfile(fp_path):
1296 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001297 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001298 logging.info('Reading fingerprint file: %s', fp_path)
1299 fingerprints = osutils.ReadFile(fp_path).splitlines()
1300 return fingerprints
1301
1302
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001303def get_all_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen59e30872020-05-18 14:12:49 -06001304 """Extract firmware version for all models present.
1305
1306 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001307 build_target: The build target.
Michael Mortensen59e30872020-05-18 14:12:49 -06001308
1309 Returns:
1310 A dict of FirmwareVersions namedtuple instances by model.
1311 Each element will be populated based on whether it was present in the
1312 command output.
1313 """
1314 cros_build_lib.AssertInsideChroot()
1315 result = {}
1316 # Note that example output for _get_firmware_version_cmd_result is available
1317 # in the packages_unittest.py for testing get_all_firmware_versions.
1318 cmd_result = _get_firmware_version_cmd_result(build_target)
1319
Benjamin Shai12c767e2022-01-12 15:17:44 +00001320 if cmd_result:
1321 # There is a blank line between the version info for each model.
1322 firmware_version_payloads = cmd_result.split('\n\n')
1323 for firmware_version_payload in firmware_version_payloads:
1324 if 'BIOS' in firmware_version_payload:
1325 firmware_version = _find_firmware_versions(firmware_version_payload)
1326 result[firmware_version.model] = firmware_version
Michael Mortensen59e30872020-05-18 14:12:49 -06001327 return result
1328
1329
Benjamin Shai0858cd32022-01-10 20:23:49 +00001330class FirmwareVersions(NamedTuple):
1331 """Tuple to hold firmware versions, with truthiness."""
1332 model: Optional[str]
1333 main: Optional[str]
1334 main_rw: Optional[str]
1335 ec: Optional[str]
1336 ec_rw: Optional[str]
1337
1338 def __bool__(self):
1339 return bool(
1340 self.model or self.main or self.main_rw or self.ec or self.ec_rw)
Michael Mortensen71ef5682020-05-07 14:29:24 -06001341
1342
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001343def get_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen71ef5682020-05-07 14:29:24 -06001344 """Extract version information from the firmware updater, if one exists.
1345
1346 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001347 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001348
1349 Returns:
1350 A FirmwareVersions namedtuple instance.
1351 Each element will either be set to the string output by the firmware
1352 updater shellball, or None if there is no firmware updater.
1353 """
1354 cros_build_lib.AssertInsideChroot()
1355 cmd_result = _get_firmware_version_cmd_result(build_target)
1356 if cmd_result:
1357 return _find_firmware_versions(cmd_result)
1358 else:
1359 return FirmwareVersions(None, None, None, None, None)
1360
1361
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001362def _get_firmware_version_cmd_result(
Alex Klein89b58732021-12-23 10:16:03 -07001363 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensen71ef5682020-05-07 14:29:24 -06001364 """Gets the raw result output of the firmware updater version command.
1365
1366 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001367 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001368
1369 Returns:
1370 Command execution result.
1371 """
1372 updater = os.path.join(build_target.root,
1373 'usr/sbin/chromeos-firmwareupdate')
1374 logging.info('Calling updater %s', updater)
1375 # Call the updater using the chroot-based path.
Alex Klein89b58732021-12-23 10:16:03 -07001376 try:
1377 return cros_build_lib.run([updater, '-V'],
1378 capture_output=True, log_output=True,
1379 encoding='utf-8').stdout
1380 except cros_build_lib.RunCommandError:
1381 # Updater probably doesn't exist (e.g. betty).
1382 return None
Michael Mortensen71ef5682020-05-07 14:29:24 -06001383
1384
1385def _find_firmware_versions(cmd_output):
1386 """Finds firmware version output via regex matches against the cmd_output.
1387
1388 Args:
1389 cmd_output: The raw output to search against.
1390
1391 Returns:
1392 FirmwareVersions namedtuple with results.
1393 Each element will either be set to the string output by the firmware
1394 updater shellball, or None if there is no match.
1395 """
1396
1397 # Sometimes a firmware bundle includes a special combination of RO+RW
1398 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1399 # version" field. In other cases, the "(RW) version" field is not present.
1400 # Therefore, search for the "(RW)" fields first and if they aren't present,
1401 # fallback to the other format. e.g. just "BIOS version:".
1402 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1403 main = None
1404 main_rw = None
1405 ec = None
1406 ec_rw = None
1407 model = None
1408
1409 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1410 if match:
1411 main = match.group('version')
1412
1413 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1414 if match:
1415 main_rw = match.group('version')
1416
1417 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1418 if match:
1419 ec = match.group('version')
1420
1421 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1422 if match:
1423 ec_rw = match.group('version')
1424
1425 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1426 if match:
1427 model = match.group('model')
1428
1429 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001430
1431
Benjamin Shai0858cd32022-01-10 20:23:49 +00001432class MainEcFirmwareVersions(NamedTuple):
1433 """Tuple to hold main and ec firmware versions, with truthiness."""
1434 main_fw_version: Optional[str]
1435 ec_fw_version: Optional[str]
1436
1437 def __bool__(self):
1438 return bool(self.main_fw_version or self.ec_fw_version)
1439
Michael Mortensena4af79e2020-05-06 16:18:48 -06001440
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001441def determine_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensena4af79e2020-05-06 16:18:48 -06001442 """Returns a namedtuple with main and ec firmware versions.
1443
1444 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001445 build_target: The build target.
Michael Mortensena4af79e2020-05-06 16:18:48 -06001446
1447 Returns:
1448 MainEcFirmwareVersions namedtuple with results.
1449 """
1450 fw_versions = get_firmware_versions(build_target)
1451 main_fw_version = fw_versions.main_rw or fw_versions.main
1452 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1453
1454 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001455
Benjamin Shai0858cd32022-01-10 20:23:49 +00001456
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001457def determine_kernel_version(
1458 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001459 """Returns a string containing the kernel version for this build target.
1460
1461 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001462 build_target: The build target.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001463
1464 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001465 The kernel versions, or None.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001466 """
1467 try:
1468 packages = portage_util.GetPackageDependencies(build_target.name,
1469 'virtual/linux-sources')
1470 except cros_build_lib.RunCommandError as e:
1471 logging.warning('Unable to get package list for metadata: %s', e)
1472 return None
1473 for package in packages:
1474 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001475 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001476 logging.info('Found active kernel version: %s', kernel_version)
1477 return kernel_version
1478 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001479
1480
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001481def get_models(
1482 build_target: 'build_target_lib.BuildTarget',
1483 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001484 """Obtain a list of models supported by a unified board.
1485
1486 This ignored whitelabel models since GoldenEye has no specific support for
1487 these at present.
1488
1489 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001490 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001491 log_output: Whether to log the output of the cros_config_host invocation.
1492
1493 Returns:
1494 A list of models supported by this board, if it is a unified build; None,
1495 if it is not a unified build.
1496 """
1497 return _run_cros_config_host(build_target, ['list-models'],
1498 log_output=log_output)
1499
1500
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001501def get_key_id(
1502 build_target: 'build_target_lib.BuildTarget',
1503 model: str) -> Optional[str]:
Michael Mortensen359c1f32020-05-28 19:35:42 -06001504 """Obtain the key_id for a model within the build_target.
1505
1506 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001507 build_target: The build target.
1508 model: The model name
Michael Mortensen359c1f32020-05-28 19:35:42 -06001509
1510 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001511 A key_id or None.
Michael Mortensen359c1f32020-05-28 19:35:42 -06001512 """
1513 model_arg = '--model=' + model
1514 key_id_list = _run_cros_config_host(
1515 build_target,
1516 [model_arg, 'get', '/firmware-signing', 'key-id'])
1517 key_id = None
1518 if len(key_id_list) == 1:
1519 key_id = key_id_list[0]
1520 return key_id
1521
1522
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001523def _run_cros_config_host(
1524 build_target: 'build_target_lib.BuildTarget',
1525 args: List[str],
1526 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001527 """Run the cros_config_host tool.
1528
1529 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001530 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001531 args: List of arguments to pass.
1532 log_output: Whether to log the output of the cros_config_host.
1533
1534 Returns:
1535 Output of the tool
1536 """
1537 cros_build_lib.AssertInsideChroot()
1538 tool = '/usr/bin/cros_config_host'
1539 if not os.path.isfile(tool):
1540 return None
1541
1542 config_fname = build_target.full_path(
1543 'usr/share/chromeos-config/yaml/config.yaml')
1544
1545 result = cros_build_lib.run(
1546 [tool, '-c', config_fname] + args,
1547 capture_output=True,
1548 encoding='utf-8',
1549 log_output=log_output,
1550 check=False)
1551 if result.returncode:
1552 # Show the output for debugging purposes.
1553 if 'No such file or directory' not in result.error:
1554 logging.error('cros_config_host failed: %s\n', result.error)
1555 return None
1556 return result.output.strip().splitlines()