blob: e1f906c3ecff96879b8607e9a0390bd50a3f759f [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
Mike Frysinger68796b52019-08-25 00:04:27 -040033
Alex Klein5caab872021-09-10 11:44:37 -060034if TYPE_CHECKING:
35 from chromite.lib import build_target_lib
Alex Klein16ea1b32021-10-01 15:48:50 -060036 from chromite.lib import chroot_lib
Chris McDonaldf7c03d42021-07-21 11:54:26 -060037
Alex Klein36b117f2019-09-30 15:13:46 -060038if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060039 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060040 from chromite.service import dependency
41
Alex Klein87531182019-08-12 15:23:37 -060042# Registered handlers for uprevving versioned packages.
43_UPREV_FUNCS = {}
44
Alex Kleineb77ffa2019-05-28 14:47:44 -060045
46class Error(Exception):
47 """Module's base error class."""
48
49
Alex Klein4de25e82019-08-05 15:58:39 -060050class UnknownPackageError(Error):
51 """Uprev attempted for a package without a registered handler."""
52
53
Alex Kleineb77ffa2019-05-28 14:47:44 -060054class UprevError(Error):
55 """An error occurred while uprevving packages."""
56
57
Michael Mortensenb70e8a82019-10-10 18:43:41 -060058class NoAndroidVersionError(Error):
59 """An error occurred while trying to determine the android version."""
60
61
62class NoAndroidBranchError(Error):
63 """An error occurred while trying to determine the android branch."""
64
65
66class NoAndroidTargetError(Error):
67 """An error occurred while trying to determine the android target."""
68
69
Alex Klein4de25e82019-08-05 15:58:39 -060070class AndroidIsPinnedUprevError(UprevError):
71 """Raised when we try to uprev while Android is pinned."""
72
73 def __init__(self, new_android_atom):
74 """Initialize a AndroidIsPinnedUprevError.
75
76 Args:
77 new_android_atom: The Android atom that we failed to
78 uprev to, due to Android being pinned.
79 """
80 assert new_android_atom
81 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
82 new_android_atom)
Jae Hoon Kimad176b82021-07-26 19:29:29 +000083 super().__init__(msg)
Alex Klein4de25e82019-08-05 15:58:39 -060084 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060085
86
Andrew Lamb9563a152019-12-04 11:42:18 -070087class GeneratedCrosConfigFilesError(Error):
88 """Error when cros_config_schema does not produce expected files"""
89
90 def __init__(self, expected_files, found_files):
91 msg = ('Expected to find generated C files: %s. Actually found: %s' %
92 (expected_files, found_files))
Jae Hoon Kimad176b82021-07-26 19:29:29 +000093 super().__init__(msg)
Andrew Lamb9563a152019-12-04 11:42:18 -070094
Alex Klein7a3a7dd2020-01-08 16:44:38 -070095
Alex Klein6becabc2020-09-11 14:03:05 -060096NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
97 'needs_chrome_source',
98 'builds_chrome',
99 'packages',
100 'missing_chrome_prebuilt',
101 'missing_follower_prebuilt',
Alex Klein9ce3f682021-06-23 15:06:44 -0600102 'local_uprev',
Alex Klein6becabc2020-09-11 14:03:05 -0600103))
104
105
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600106def patch_ebuild_vars(ebuild_path, variables):
107 """Updates variables in ebuild.
108
109 Use this function rather than portage_util.EBuild.UpdateEBuild when you
110 want to preserve the variable position and quotes within the ebuild.
111
112 Args:
113 ebuild_path: The path of the ebuild.
114 variables: Dictionary of variables to update in ebuild.
115 """
116 try:
117 for line in fileinput.input(ebuild_path, inplace=1):
Madeleine Hardt8ae7f102022-03-24 20:26:11 +0000118 for var, value in variables.items():
119 line = re.sub(fr'\b{var}=\S+', f'{var}="{value}"', line)
120 sys.stdout.write(line)
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600121 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 Lee84bf9a22021-11-19 17:42:11 +0900142class UprevAndroidResult(NamedTuple):
143 """Results of an Android uprev."""
144 revved: bool
145 android_atom: str = None
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900146 modified_files: List[str] = None
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900147
148
149def uprev_android(
150 android_package: str,
151 chroot: 'chroot_lib.Chroot',
152 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
153 android_build_branch: Optional[str] = None,
154 android_version: Optional[str] = None,
155 skip_commit: bool = False) -> UprevAndroidResult:
156 """Performs an Android uprev by calling cros_mark_android_as_stable.
157
158 Args:
159 android_package: The Android package to uprev.
160 chroot: The chroot to enter.
161 build_targets: List of build targets to cleanup after uprev.
162 android_build_branch: Override the default Android branch corresponding to
163 the package.
164 android_version: Uprev to the particular version. By default the latest
165 available version is used.
166 skip_commit: Whether to skip committing the change after a successful uprev.
167
168 Returns:
169 The uprev result containing:
170 revved: Whether an uprev happened.
171 android_atom: If revved, the portage atom for the revved Android ebuild.
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900172 modified_files: If revved, list of files being modified.
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900173 """
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700174 command = [
175 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900176 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700177 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600178 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900179 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900180 if android_build_branch:
181 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600182 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900183 command.append(f'--force_version={android_version}')
184 if skip_commit:
185 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600186
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700187 result = cros_build_lib.run(
188 command,
189 stdout=True,
190 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500191 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700192 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600193
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900194 # cros_mark_android_as_stable prints the uprev result to stdout as JSON in a
195 # single line. We only take the last line from stdout to make sure no junk
196 # output is included (e.g. messages from bashrc scripts that run upon entering
197 # the chroot.)
198 output = json.loads(result.stdout.strip().splitlines()[-1])
199
200 if not output['revved']:
Alex Klein4de25e82019-08-05 15:58:39 -0600201 logging.info('Found nothing to rev.')
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900202 return UprevAndroidResult(revved=False)
203
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900204 android_atom = output['android_atom']
Alex Klein4de25e82019-08-05 15:58:39 -0600205
206 for target in build_targets or []:
207 # Sanity check: We should always be able to merge the version of
208 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900209 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600210 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700211 cros_build_lib.run(
212 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600213 except cros_build_lib.RunCommandError:
214 logging.error(
215 'Cannot emerge-%s =%s\nIs Android pinned to an older '
216 'version?', target, android_atom)
217 raise AndroidIsPinnedUprevError(android_atom)
218
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900219 return UprevAndroidResult(revved=True,
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900220 android_atom=android_atom,
221 modified_files=output['modified_files'])
222
223
224def uprev_android_lkgb(android_package: str,
225 build_targets: List['build_target_lib.BuildTarget'],
226 chroot: 'chroot_lib.Chroot'
227 ) -> uprev_lib.UprevVersionedPackageResult:
228 """Uprevs an Android package to the version specified in the LKGB file.
229
230 This is the PUpr handler for Android packages, triggered whenever the
231 corresponding LKGB file is being updated.
232
233 PUpr for Android does not test the uprev change in CQ; instead we run separate
234 jobs to test new Android versions, and we write the latest vetted version to
235 the LKGB file. Find the design at go/android-uprev-recipes.
236
237 Args:
238 android_package: The Android package to uprev.
239 build_targets: List of build targets to cleanup after uprev.
240 chroot: The chroot to enter.
241
242 Returns:
243 An uprev_lib.UprevVersionedPackageResult containing the new version and a
244 list of modified files.
245 """
Shao-Chuan Lee0e787d22021-12-13 21:33:35 +0900246 android_package_dir = android.GetAndroidPackageDir(android_package)
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900247 android_version = android.ReadLKGB(android_package_dir)
248
249 result = uprev_lib.UprevVersionedPackageResult()
250 uprev_result = uprev_android(android_package, chroot,
251 build_targets=build_targets,
252 android_version=android_version,
253 skip_commit=True)
254 if not uprev_result.revved:
255 return result
256
Shao-Chuan Lee0e787d22021-12-13 21:33:35 +0900257 # cros_mark_android_as_stable returns paths relative to |android.OVERLAY_DIR|.
258 result.add_result(android_version,
259 [os.path.join(android.OVERLAY_DIR, f)
260 for f in uprev_result.modified_files])
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900261 return result
262
263
264def define_uprev_android_lkgb_handlers():
265 """Dynamically define uprev handlers for each Android package"""
266
267 def define_handler(android_package):
268 """Defines the uprev handler for an Android package."""
269 full_package_name = 'chromeos-base/' + android_package
270
271 @uprevs_versioned_package(full_package_name)
272 def _handler(build_targets, _refs, chroot):
273 return uprev_android_lkgb(android_package, build_targets, chroot)
274
275 for android_package in constants.ANDROID_ALL_PACKAGES:
276 define_handler(android_package)
277
278
279define_uprev_android_lkgb_handlers()
Alex Klein4de25e82019-08-05 15:58:39 -0600280
281
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700282def uprev_build_targets(
283 build_targets: Optional[List['build_target_lib.BuildTarget']],
284 overlay_type: str,
285 chroot: 'chroot_lib.Chroot' = None,
286 output_dir: Optional[str] = None):
Alex Kleineb77ffa2019-05-28 14:47:44 -0600287 """Uprev the set provided build targets, or all if not specified.
288
289 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700290 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600291 whose overlays should be uprevved, empty or None for all.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700292 overlay_type: One of the valid overlay types except None (see
Alex Kleineb77ffa2019-05-28 14:47:44 -0600293 constants.VALID_OVERLAYS).
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700294 chroot: The chroot to clean, if desired.
295 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600296 """
297 # Need a valid overlay, but exclude None.
298 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
299
300 if build_targets:
301 overlays = portage_util.FindOverlaysForBoards(
302 overlay_type, boards=[t.name for t in build_targets])
303 else:
304 overlays = portage_util.FindOverlays(overlay_type)
305
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700306 return uprev_overlays(
307 overlays,
308 build_targets=build_targets,
309 chroot=chroot,
310 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600311
312
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700313def uprev_overlays(
314 overlays: List[str],
315 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
316 chroot: Optional['chroot_lib.Chroot'] = None,
317 output_dir: Optional[str] = None) -> List[str]:
Alex Kleineb77ffa2019-05-28 14:47:44 -0600318 """Uprev the given overlays.
319
320 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700321 overlays: The list of overlay paths.
322 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600323 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700324 chroot: The chroot to clean, if desired.
325 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600326
327 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700328 The paths to all of the modified ebuild files. This includes the new files
329 that were added (i.e. the new versions) and all of the removed files
330 (i.e. the old versions).
Alex Kleineb77ffa2019-05-28 14:47:44 -0600331 """
332 assert overlays
333
334 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
335
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700336 uprev_manager = uprev_lib.UprevOverlayManager(
337 overlays,
338 manifest,
339 build_targets=build_targets,
340 chroot=chroot,
341 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600342 uprev_manager.uprev()
343
Dhanya Ganeshd03a4162021-08-25 00:21:50 +0000344 return uprev_manager.modified_ebuilds, uprev_manager.revved_packages
Alex Kleineb77ffa2019-05-28 14:47:44 -0600345
346
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700347def uprev_versioned_package(
348 package: package_info.CPV,
349 build_targets: List['build_target_lib.BuildTarget'],
350 refs: List[uprev_lib.GitRef],
351 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
Alex Klein87531182019-08-12 15:23:37 -0600352 """Call registered uprev handler function for the package.
353
354 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700355 package: The package being uprevved.
356 build_targets: The build targets to clean on a successful uprev.
357 refs:
358 chroot: The chroot to enter for cleaning.
Alex Klein87531182019-08-12 15:23:37 -0600359
360 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700361 The result.
Alex Klein87531182019-08-12 15:23:37 -0600362 """
363 assert package
364
365 if package.cp not in _UPREV_FUNCS:
366 raise UnknownPackageError(
367 'Package "%s" does not have a registered handler.' % package.cp)
368
Andrew Lambea9a8a22019-12-12 14:03:43 -0700369 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600370
371
Navil Perezf57ba872020-06-04 22:38:37 +0000372@uprevs_versioned_package('media-libs/virglrenderer')
373def uprev_virglrenderer(_build_targets, refs, _chroot):
374 """Updates virglrenderer ebuilds.
375
376 See: uprev_versioned_package.
377
378 Returns:
379 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
380 """
Navil Perezf57ba872020-06-04 22:38:37 +0000381 overlay = os.path.join(constants.SOURCE_ROOT,
382 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600383 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
384 'virglrenderer')
385 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000386
387 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
388 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000389 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
390 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000391 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
392
George Engelbrechte73f2782020-06-10 14:10:46 -0600393 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600394 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000395 result.add_result(refs[0].revision, updated_files)
396 return result
397
Jose Magana03b5a842020-08-19 12:52:59 +1000398@uprevs_versioned_package('chromeos-base/drivefs')
399def uprev_drivefs(_build_targets, refs, chroot):
400 """Updates drivefs ebuilds.
401
Harvey Yang3eee06c2021-03-18 15:47:56 +0800402 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000403 See: uprev_versioned_package.
404
405 Returns:
406 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
407 """
408
Ben Reiche779cf42020-12-15 03:21:31 +0000409 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000410 result = uprev_lib.UprevVersionedPackageResult()
411 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000412
Harvey Yang3eee06c2021-03-18 15:47:56 +0800413 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
414 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000415 if not drivefs_version:
416 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000417 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000418
Ben Reiche779cf42020-12-15 03:21:31 +0000419 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000420
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000421 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000422 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000423 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000424 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800425 chroot,
426 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000427
428 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000429 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000430 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000431 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000432
433 return result
434
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800435@uprevs_versioned_package('chromeos-base/perfetto')
436def uprev_perfetto(_build_targets, refs, chroot):
437 """Updates Perfetto ebuilds.
438
Harvey Yang3eee06c2021-03-18 15:47:56 +0800439 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800440 See: uprev_versioned_package.
441
442 Returns:
443 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
444 """
445 result = uprev_lib.UprevVersionedPackageResult()
446
Harvey Yang3eee06c2021-03-18 15:47:56 +0800447 PERFETTO_REFS_PREFIX = 'refs/tags/v'
448 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800449 if not perfetto_version:
450 # No valid Perfetto version is identified.
451 return result
452
453 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
454
455 # Attempt to uprev perfetto package.
456 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
457
Harvey Yang3eee06c2021-03-18 15:47:56 +0800458 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
459 PERFETTO_PATH,
460 perfetto_version,
461 chroot,
462 allow_downrev=False,
463 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800464
465 if not uprev_result:
466 return result
467
468 result.add_result(perfetto_version, uprev_result.changed_files)
469
470 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000471
Yaakov Shaul395ae832019-09-09 14:45:32 -0600472@uprevs_versioned_package('afdo/kernel-profiles')
473def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600474 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600475
476 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600477
478 Raises:
479 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600480 """
481 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
482 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
483
David Burger92485342019-09-10 17:52:45 -0600484 with open(path, 'r') as f:
485 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600486
Chris McDonald38409112020-09-24 11:24:51 -0600487 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600488 for kernel_pkg, version_info in versions.items():
489 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
490 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600491 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600492 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600493 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600494 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600495 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600496 patch_ebuild_vars(ebuild_path,
497 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600498
499 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600500 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400501 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600502 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600503 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600504 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600505 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600506
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600507 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600508
Yaakov Shaul730814a2019-09-10 13:58:25 -0600509 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
510
511 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600512
513
Trent Begineb624182020-07-14 10:09:45 -0600514@uprevs_versioned_package('chromeos-base/termina-dlc')
Maciek Swiech6b12f662022-01-25 16:51:19 +0000515@uprevs_versioned_package('chromeos-base/termina-tools-dlc')
516def uprev_termina_dlcs(_build_targets, _refs, chroot):
517 """Updates shared termina-dlc and termina-tools-dlc ebuilds.
518
519 termina-dlc - chromeos-base/termina-dlc
520 termina-tools-dlc - chromeos-base/termina-tools-dlc
Trent Beginaf51f1b2020-03-09 17:35:31 -0600521
522 See: uprev_versioned_package.
523 """
Maciek Swiech6b12f662022-01-25 16:51:19 +0000524 termina_dlc_pkg = 'termina-dlc'
525 termina_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
526 'chromeos-base', termina_dlc_pkg)
527 tools_dlc_pkg = 'termina-tools-dlc'
528 tools_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
529 'chromeos-base', tools_dlc_pkg)
Patrick Meiring5897add2020-09-16 16:30:17 +1000530
Maciek Swiech6b12f662022-01-25 16:51:19 +0000531 # termina-dlc and termina-tools-dlc are pinned to the same version.
532 version_pin_src_path = _get_version_pin_src_path(termina_dlc_pkg_path)
Patrick Meiring5897add2020-09-16 16:30:17 +1000533 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
534
Maciek Swiech6b12f662022-01-25 16:51:19 +0000535 result = uprev_lib.uprev_ebuild_from_pin(termina_dlc_pkg_path, version_no_rev,
536 chroot)
537 result += uprev_lib.uprev_ebuild_from_pin(tools_dlc_pkg_path, version_no_rev,
538 chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000539
Maciek Swiech6b12f662022-01-25 16:51:19 +0000540 return result
Patrick Meiring5897add2020-09-16 16:30:17 +1000541
Julio Hurtadof1befec2021-05-05 21:34:26 +0000542@uprevs_versioned_package('chromeos-base/chromeos-lacros')
543def uprev_lacros(_build_targets, refs, chroot):
544 """Updates lacros ebuilds.
545
Julio Hurtadoa994e002021-07-07 17:57:45 +0000546 Version to uprev to is gathered from the QA qualified version tracking file
547 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
548 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000549
550 See: uprev_versioned_package.
551 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000552 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000553 path = os.path.join(
Dennis Kempin257b74c2021-09-28 14:38:17 -0700554 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000555 lacros_version = refs[0].revision
556 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
557 lacros_version,
558 chroot,
559 allow_downrev=False)
560
561 if not uprev_result:
562 return result
563
564 result.add_result(lacros_version, uprev_result.changed_files)
565 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000566
567
Julio Hurtado870ed322021-12-03 18:22:40 +0000568@uprevs_versioned_package('chromeos-base/chromeos-lacros-parallel')
569def uprev_lacros_in_parallel(
570 _build_targets: Optional[List['build_target_lib.BuildTarget']],
571 refs: List[uprev_lib.GitRef],
572 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
573 """Updates lacros ebuilds in parallel with ash-chrome.
574
575 This handler is going to be used temporarily while lacros transitions to being
576 uprevved atomically with ash-chrome. Unlike a standalone lacros uprev, this
577 handler will not need to look at the QA qualified file. Rather, it will
578 function identical to ash-chrome using git tags.
579
580 See: uprev_versioned_package.
581
582 Returns:
583 UprevVersionedPackageResult: The result.
584 """
585 result = uprev_lib.UprevVersionedPackageResult()
586 path = os.path.join(
587 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
588 lacros_version = uprev_lib.get_version_from_refs(refs)
589 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
590 lacros_version,
591 chroot,
592 allow_downrev=False)
593
594 if not uprev_result:
595 return result
596
597 result.add_result(lacros_version, uprev_result.changed_files)
598 return result
599
600
Patrick Meiring5897add2020-09-16 16:30:17 +1000601@uprevs_versioned_package('app-emulation/parallels-desktop')
602def uprev_parallels_desktop(_build_targets, _refs, chroot):
603 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
604
605 See: uprev_versioned_package
606
607 Returns:
608 UprevVersionedPackageResult: The result.
609 """
610 package = 'parallels-desktop'
611 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
612 'app-emulation', package)
613 version_pin_src_path = _get_version_pin_src_path(package_path)
614
615 # Expect a JSON blob like the following:
616 # {
617 # "version": "1.2.3",
618 # "test_image": { "url": "...", "size": 12345678,
619 # "sha256sum": "<32 bytes of hexadecimal>" }
620 # }
621 with open(version_pin_src_path, 'r') as f:
622 pinned = json.load(f)
623
624 if 'version' not in pinned or 'test_image' not in pinned:
625 raise UprevError('VERSION-PIN for %s missing version and/or '
626 'test_image field' % package)
627
628 version = pinned['version']
629 if not isinstance(version, str):
630 raise UprevError('version in VERSION-PIN for %s not a string' % package)
631
632 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600633 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000634
635 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100636 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
637 'local/bundles/crosint/pita/data/'
638 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000639 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
640 with open(test_image_src_path, 'w') as f:
641 json.dump(pinned['test_image'], f, indent=2)
642 result.add_result(version, [test_image_src_path])
643
644 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600645
646
Trent Begin315d9d92019-12-03 21:55:53 -0700647@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600648def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700649 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
650
651 See: uprev_versioned_package.
652 """
653 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700654 package_path = os.path.join('src', 'private-overlays',
655 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000656 version_pin_src_path = _get_version_pin_src_path(package_path)
657 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700658
Chris McDonald38409112020-09-24 11:24:51 -0600659 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700660
661
David Riley8513c1f2021-10-14 17:07:41 -0700662@uprevs_versioned_package('chromeos-base/borealis-dlc')
663def uprev_borealis_dlc(_build_targets, _refs, chroot):
664 """Updates shared borealis-dlc ebuild - chromeos-base/borealis-dlc.
665
666 See: uprev_versioned_package.
667 """
David Rileybc100ba2022-01-10 10:06:59 -0800668 package_path = os.path.join('src', 'private-overlays',
669 'chromeos-partner-overlay', 'chromeos-base',
670 'borealis-dlc')
David Riley8513c1f2021-10-14 17:07:41 -0700671
672 version_pin_src_path = _get_version_pin_src_path(package_path)
673 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
674
675 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
676
677
Patrick Meiring5897add2020-09-16 16:30:17 +1000678def _get_version_pin_src_path(package_path):
679 """Returns the path to the VERSION-PIN file for the given package."""
680 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
681
682
Alex Klein87531182019-08-12 15:23:37 -0600683@uprevs_versioned_package(constants.CHROME_CP)
Alex Klein4e839252022-01-06 13:29:18 -0700684def uprev_chrome_from_ref(build_targets, refs, _chroot):
Alex Klein87531182019-08-12 15:23:37 -0600685 """Uprev chrome and its related packages.
686
687 See: uprev_versioned_package.
688 """
689 # Determine the version from the refs (tags), i.e. the chrome versions are the
690 # tag names.
Julio Hurtado870ed322021-12-03 18:22:40 +0000691 chrome_version = uprev_lib.get_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600692 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600693
Alex Klein4e839252022-01-06 13:29:18 -0700694 return uprev_chrome(chrome_version, build_targets, None)
Alex Kleinf69bd802021-06-22 15:43:49 -0600695
696
Alex Klein9ce3f682021-06-23 15:06:44 -0600697def revbump_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600698 build_targets: List['build_target_lib.BuildTarget'] = None,
Alex Klein9ce3f682021-06-23 15:06:44 -0600699 chroot: Optional['chroot_lib.Chroot'] = None
700) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600701 """Attempt to revbump chrome.
702
703 Revbumps are done by executing an uprev using the current stable version.
704 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
705 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
706 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
707 """
708 chrome_version = uprev_lib.get_stable_chrome_version()
Alex Klein16ea1b32021-10-01 15:48:50 -0600709 return uprev_chrome(chrome_version, build_targets, chroot)
Alex Kleinf69bd802021-06-22 15:43:49 -0600710
711
Alex Klein9ce3f682021-06-23 15:06:44 -0600712def uprev_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600713 chrome_version: str,
714 build_targets: Optional[List['build_target_lib.BuildTarget']],
715 chroot: Optional['chroot_lib.Chroot']
Alex Klein9ce3f682021-06-23 15:06:44 -0600716) -> uprev_lib.UprevVersionedPackageResult:
717 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600718 uprev_manager = uprev_lib.UprevChromeManager(
719 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600720 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600721 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
722 # attempt. The expected behavior is documented in the following table:
723 #
724 # Outcome of Chrome uprev attempt:
725 # NEWER_VERSION_EXISTS:
726 # Do nothing.
727 # SAME_VERSION_EXISTS or REVISION_BUMP:
728 # Uprev followers
729 # Assert not VERSION_BUMP (any other outcome is fine)
730 # VERSION_BUMP or NEW_EBUILD_CREATED:
731 # Uprev followers
732 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600733
734 # Start with chrome itself so we can proceed accordingly.
735 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
736 if chrome_result.newer_version_exists:
737 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600738 return result
Alex Klein87531182019-08-12 15:23:37 -0600739
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600740 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600741 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600742 follower_result = uprev_manager.uprev(package)
743 if chrome_result.stable_version and follower_result.version_bump:
744 logging.warning('%s had a version bump, but no more than a revision bump '
745 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600746
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600747 if uprev_manager.modified_ebuilds:
748 # Record changes when we have them.
749 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
750
751 return result
Alex Klein87531182019-08-12 15:23:37 -0600752
753
Harvey Yang3eee06c2021-03-18 15:47:56 +0800754def _get_latest_version_from_refs(refs_prefix: str,
755 refs: List[uprev_lib.GitRef]) -> str:
756 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000757
Ben Reiche779cf42020-12-15 03:21:31 +0000758 Versions are compared using |distutils.version.LooseVersion| and
759 the latest version is returned.
760
761 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800762 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800763 refs: The tags to parse for the latest Perfetto version.
764
765 Returns:
766 The latest Perfetto version to use.
767 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800768 valid_refs = []
769 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800770 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800771 valid_refs.append(gitiles.ref)
772
773 if not valid_refs:
774 return None
775
776 # Sort by version and take the latest version.
777 target_version_ref = sorted(valid_refs,
778 key=LooseVersion,
779 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800780 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800781
782
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700783def _generate_platform_c_files(
784 replication_config: replication_config_pb2.ReplicationConfig,
785 chroot: 'chroot_lib.Chroot') -> List[str]:
Andrew Lamb9563a152019-12-04 11:42:18 -0700786 """Generates platform C files from a platform JSON payload.
787
788 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700789 replication_config: A ReplicationConfig that has already been run. If it
790 produced a build_config.json file, that file will be used to generate
791 platform C files. Otherwise, nothing will be generated.
792 chroot: The chroot to use to generate.
Andrew Lamb9563a152019-12-04 11:42:18 -0700793
794 Returns:
795 A list of generated files.
796 """
797 # Generate the platform C files from the build config. Note that it would be
798 # more intuitive to generate the platform C files from the platform config;
799 # however, cros_config_schema does not allow this, because the platform config
800 # payload is not always valid input. For example, if a property is both
801 # 'required' and 'build-only', it will fail schema validation. Thus, use the
802 # build config, and use '-f' to filter.
803 build_config_path = [
804 rule.destination_path
805 for rule in replication_config.file_replication_rules
806 if rule.destination_path.endswith('build_config.json')
807 ]
808
809 if not build_config_path:
810 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700811 'No build_config.json found, will not generate platform C files. '
812 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700813 return []
814
815 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700816 raise ValueError('Expected at most one build_config.json destination path. '
817 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700818
819 build_config_path = build_config_path[0]
820
821 # Paths to the build_config.json and dir to output C files to, in the
822 # chroot.
823 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
824 build_config_path)
825 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
826 os.path.dirname(build_config_path))
827
828 command = [
829 'cros_config_schema', '-m', build_config_chroot_path, '-g',
830 generated_output_chroot_dir, '-f', '"TRUE"'
831 ]
832
833 cros_build_lib.run(
834 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
835
836 # A relative (to the source root) path to the generated C files.
837 generated_output_dir = os.path.dirname(build_config_path)
838 generated_files = []
839 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
840 for f in expected_c_files:
841 if os.path.exists(
842 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
843 generated_files.append(os.path.join(generated_output_dir, f))
844
845 if len(expected_c_files) != len(generated_files):
846 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
847
848 return generated_files
849
850
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700851def _get_private_overlay_package_root(ref: uprev_lib.GitRef, package: str):
Andrew Lambe836f222019-12-09 12:27:38 -0700852 """Returns the absolute path to the root of a given private overlay.
853
854 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700855 ref: GitRef for the private overlay.
856 package: Path to the package in the overlay.
Andrew Lambe836f222019-12-09 12:27:38 -0700857 """
858 # There might be a cleaner way to map from package -> path within the source
859 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700860 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700861 match = re.match(private_overlay_ref_pattern, ref.path)
862 if not match:
863 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
864 (private_overlay_ref_pattern, ref))
865
866 overlay = match.group(1)
867
868 return os.path.join(constants.SOURCE_ROOT,
869 'src/private-overlays/overlay-%s-private' % overlay,
870 package)
871
872
Andrew Lambea9a8a22019-12-12 14:03:43 -0700873@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
874def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700875 """Replicate a private cros_config change to the corresponding public config.
876
Alex Kleinad6b48a2020-01-08 16:57:41 -0700877 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700878 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700879 package = 'chromeos-base/chromeos-config-bsp'
880
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700881 if len(refs) != 1:
882 raise ValueError('Expected exactly one ref, actual %s' % refs)
883
884 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700885 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700886 replication_config_path = os.path.join(package_root,
887 'replication_config.jsonpb')
888
889 try:
890 replication_config = json_format.Parse(
891 osutils.ReadFile(replication_config_path),
892 replication_config_pb2.ReplicationConfig())
893 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700894 raise ValueError(
895 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700896
897 replication_lib.Replicate(replication_config)
898
899 modified_files = [
900 rule.destination_path
901 for rule in replication_config.file_replication_rules
902 ]
903
Andrew Lamb9563a152019-12-04 11:42:18 -0700904 # The generated platform C files are not easily filtered by replication rules,
905 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
906 # files cannot. Therefore, replicate and filter the JSON payloads, and then
907 # generate filtered C files from the JSON payload.
908 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700909
910 # Use the private repo's commit hash as the new version.
911 new_private_version = refs[0].revision
912
Andrew Lamb988f4da2019-12-10 10:16:43 -0700913 # modified_files should contain only relative paths at this point, but the
914 # returned UprevVersionedPackageResult must contain only absolute paths.
915 for i, modified_file in enumerate(modified_files):
916 assert not os.path.isabs(modified_file)
917 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
918
Chris McDonald38409112020-09-24 11:24:51 -0600919 return uprev_lib.UprevVersionedPackageResult().add_result(
920 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700921
922
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700923@uprevs_versioned_package('chromeos-base/crosvm')
924def uprev_crosvm(_build_targets, refs, _chroot):
925 """Updates crosvm ebuilds to latest revision
926
927 crosvm is not versioned. We are updating to the latest commit on the main
928 branch.
929
930 See: uprev_versioned_package.
931
932 Returns:
933 UprevVersionedPackageResult: The result of updating crosvm ebuilds.
934 """
935 overlay = os.path.join(constants.SOURCE_ROOT,
936 constants.CHROMIUMOS_OVERLAY_DIR)
937 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'crosvm')
938 manifest = git.ManifestCheckout.Cached(repo_path)
939
940 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
Dennis Kempin257b74c2021-09-28 14:38:17 -0700941 uprev_manager.uprev(
942 package_list=[
943 'chromeos-base/crosvm',
944 'dev-rust/assertions',
945 'dev-rust/cros_async',
946 'dev-rust/cros_fuzz',
947 'dev-rust/data_model',
948 'dev-rust/enumn',
949 'dev-rust/io_uring',
950 'dev-rust/p9',
951 'dev-rust/sync',
952 'dev-rust/sys_util',
953 'dev-rust/tempfile',
954 'media-sound/audio_streams',
955 ],
956 force=True
957 )
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700958
959 updated_files = uprev_manager.modified_ebuilds
960 result = uprev_lib.UprevVersionedPackageResult()
961 result.add_result(refs[0].revision, updated_files)
962 return result
963
964
Alex Klein5caab872021-09-10 11:44:37 -0600965def get_best_visible(
966 atom: str,
967 build_target: Optional['build_target_lib.BuildTarget'] = None
968) -> package_info.PackageInfo:
Alex Kleinbbef2b32019-08-27 10:38:50 -0600969 """Returns the best visible CPV for the given atom.
970
971 Args:
Alex Klein5caab872021-09-10 11:44:37 -0600972 atom: The atom to look up.
973 build_target: The build target whose sysroot should be searched, or the SDK
974 if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700975
976 Returns:
Alex Klein5caab872021-09-10 11:44:37 -0600977 The best visible package, or None if none are visible.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600978 """
David Burger1e0fe232019-07-01 14:52:07 -0600979 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600980
Alex Klein5caab872021-09-10 11:44:37 -0600981 return portage_util.PortageqBestVisible(
982 atom,
983 board=build_target.name if build_target else None,
984 sysroot=build_target.root if build_target else None)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600985
986
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700987def has_prebuilt(
988 atom: str,
989 build_target: 'build_target_lib.BuildTarget' = None,
990 useflags: Union[Iterable[str], str] = None) -> bool:
Alex Kleinda39c6d2019-09-16 14:36:36 -0600991 """Check if a prebuilt exists.
992
993 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700994 atom: The package whose prebuilt is being queried.
995 build_target: The build target whose sysroot should be searched, or the
996 SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700997 useflags: Any additional USE flags that should be set. May be a string
998 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700999
1000 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001001 True if there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -06001002 """
1003 assert atom
1004
1005 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -07001006 extra_env = None
1007 if useflags:
1008 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -05001009 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -07001010 new_flags = ' '.join(useflags)
1011
1012 existing = os.environ.get('USE', '')
1013 final_flags = '%s %s' % (existing, new_flags)
1014 extra_env = {'USE': final_flags.strip()}
1015 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -06001016
1017
David Burger0f9dd4e2019-10-08 12:33:42 -06001018def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -06001019 """Check if |build_target| builds |atom| (has it in its depgraph)."""
1020 cros_build_lib.AssertInsideChroot()
1021
Alex Kleind8cd4c62020-09-14 13:37:47 -06001022 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -06001023 # TODO(crbug/1081828): Receive and use sysroot.
1024 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -06001025 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -06001026 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001027
1028
Alex Klein6becabc2020-09-11 14:03:05 -06001029def needs_chrome_source(
1030 build_target: 'build_target_lib.BuildTarget',
1031 compile_source=False,
1032 packages: Optional[List[package_info.PackageInfo]] = None,
1033 useflags=None):
1034 """Check if the chrome source is needed.
1035
1036 The chrome source is needed if the build target builds chrome or any of its
1037 follower packages, and can't use a prebuilt for them either because it's not
1038 available, or because we can't use prebuilts because it must build from
1039 source.
1040 """
1041 cros_build_lib.AssertInsideChroot()
1042
1043 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -07001044 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -06001045 builds_chrome = constants.CHROME_CP in graph
1046 builds_follower = {
1047 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
1048 }
1049
Alex Klein9ce3f682021-06-23 15:06:44 -06001050 local_uprev = builds_chrome and revbump_chrome([build_target])
1051
Alex Klein6becabc2020-09-11 14:03:05 -06001052 # When we are compiling source set False since we do not use prebuilts.
1053 # When not compiling from source, start with True, i.e. we have every prebuilt
1054 # we've checked for up to this point.
1055 has_chrome_prebuilt = not compile_source
1056 has_follower_prebuilts = not compile_source
1057 # Save packages that need prebuilts for reporting.
1058 pkgs_needing_prebuilts = []
1059 if compile_source:
1060 # Need everything.
1061 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1062 pkgs_needing_prebuilts.extend(
1063 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
1064 else:
1065 # Check chrome itself.
1066 if builds_chrome:
1067 has_chrome_prebuilt = has_prebuilt(
1068 constants.CHROME_CP, build_target=build_target, useflags=useflags)
1069 if not has_chrome_prebuilt:
1070 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1071 # Check follower packages.
1072 for pkg, builds_pkg in builds_follower.items():
1073 if not builds_pkg:
1074 continue
1075 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
1076 has_follower_prebuilts &= prebuilt
1077 if not prebuilt:
1078 pkgs_needing_prebuilts.append(pkg)
1079 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
1080 # reflect whether we actually have the corresponding prebuilts for the build.
1081
1082 needs_chrome = builds_chrome and not has_chrome_prebuilt
1083 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
1084
1085 return NeedsChromeSourceResult(
Sergey Frolov26ff97b2021-08-14 00:02:11 +00001086 needs_chrome_source=needs_chrome or needs_follower,
Alex Klein6becabc2020-09-11 14:03:05 -06001087 builds_chrome=builds_chrome,
1088 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
1089 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -06001090 missing_follower_prebuilt=not has_follower_prebuilts,
1091 local_uprev=local_uprev,
1092 )
Alex Klein6becabc2020-09-11 14:03:05 -06001093
1094
Alex Klein68a28712021-11-08 11:08:30 -07001095class TargetVersions(NamedTuple):
1096 """Data class for the info that makes up the "target versions"."""
1097 android_version: str
1098 android_branch: str
1099 android_target: str
1100 chrome_version: str
1101 platform_version: str
1102 milestone_version: str
1103 full_version: str
1104
1105
1106def get_target_versions(
1107 build_target: 'build_target_lib.BuildTarget',
1108 packages: List[package_info.PackageInfo] = None
1109) -> TargetVersions:
1110 """Aggregate version info for a few key packages and the OS as a whole."""
1111 # Android version.
1112 android_version = determine_android_version(build_target.name)
1113 logging.info('Found android version: %s', android_version)
1114 # Android branch version.
1115 android_branch = determine_android_branch(build_target.name)
1116 logging.info('Found android branch version: %s', android_branch)
1117 # Android target version.
1118 android_target = determine_android_target(build_target.name)
1119 logging.info('Found android target version: %s', android_target)
1120
1121 # TODO(crbug/1019770): Investigate cases where builds_chrome is true but
1122 # chrome_version is None.
1123
1124 builds_chrome = builds(constants.CHROME_CP, build_target, packages=packages)
1125 chrome_version = None
1126 if builds_chrome:
1127 # Chrome version fetch.
1128 chrome_version = determine_chrome_version(build_target)
1129 logging.info('Found chrome version: %s', chrome_version)
1130
1131 # The ChromeOS version info.
1132 platform_version = determine_platform_version()
1133 milestone_version = determine_milestone_version()
1134 full_version = determine_full_version()
1135
1136 return TargetVersions(android_version, android_branch, android_target,
1137 chrome_version, platform_version, milestone_version,
1138 full_version)
1139
1140
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001141def determine_chrome_version(
1142 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenc2615b72019-10-15 08:12:24 -06001143 """Returns the current Chrome version for the board (or in buildroot).
1144
1145 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001146 build_target: The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001147
1148 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001149 The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -06001150 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001151 # TODO(crbug/1019770): Long term we should not need the try/catch here once
1152 # the builds function above only returns True for chrome when
1153 # determine_chrome_version will succeed.
1154 try:
Alex Klein5caab872021-09-10 11:44:37 -06001155 pkg_info = portage_util.PortageqBestVisible(
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001156 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001157 except cros_build_lib.RunCommandError as e:
1158 # Return None because portage failed when trying to determine the chrome
1159 # version.
1160 logging.warning('Caught exception in determine_chrome_package: %s', e)
1161 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -06001162 # Something like 78.0.3877.4_rc -> 78.0.3877.4
Alex Klein5caab872021-09-10 11:44:37 -06001163 return pkg_info.version.partition('_')[0]
Michael Mortensenc2615b72019-10-15 08:12:24 -06001164
1165
Alex Klein68a28712021-11-08 11:08:30 -07001166@functools.lru_cache()
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001167def determine_android_package(board: str) -> Optional[str]:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001168 """Returns the active Android container package in use by the board.
1169
1170 Args:
1171 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001172
1173 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001174 The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001175 """
Michael Mortensene0f4b542019-10-24 15:30:23 -06001176 try:
Mike Frysingerdfa223c2022-04-27 11:02:27 -04001177 packages = portage_util.GetPackageDependencies(
1178 'virtual/target-os', board=board)
Michael Mortensene0f4b542019-10-24 15:30:23 -06001179 except cros_build_lib.RunCommandError as e:
1180 # Return None because a command (likely portage) failed when trying to
1181 # determine the package.
1182 logging.warning('Caught exception in determine_android_package: %s', e)
1183 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001184
Alex Kleinad6b48a2020-01-08 16:57:41 -07001185 # We assume there is only one Android package in the depgraph.
1186 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -04001187 if (package.startswith('chromeos-base/android-container-') or
1188 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -07001189 return package
1190 return None
1191
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001192
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001193def determine_android_version(board: str, package: str = None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001194 """Determine the current Android version in buildroot now and return it.
1195
1196 This uses the typical portage logic to determine which version of Android
1197 is active right now in the buildroot.
1198
1199 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001200 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001201 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001202
1203 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001204 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001205
1206 Raises:
1207 NoAndroidVersionError: if no unique Android version can be determined.
1208 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001209 if not package:
1210 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -05001211 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001212 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -05001213 cpv = package_info.SplitCPV(package)
1214 if not cpv:
1215 raise NoAndroidVersionError(
1216 'Android version could not be determined for %s' % board)
1217 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001218
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001219
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001220def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001221 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001222 if not package:
1223 package = determine_android_package(board)
1224 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001225 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001226 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001227 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +09001228 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +09001229 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001230 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
1231 for target in targets:
1232 if target in ebuild_content:
1233 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
1234 if branch is not None:
1235 return branch.group(1)
1236 raise NoAndroidBranchError(
1237 'Android branch could not be determined for %s (ebuild empty?)' % board)
1238
1239
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001240def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -06001241 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001242 if not package:
1243 package = determine_android_package(board)
1244 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001245 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001246 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001247 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001248 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001249 return 'cheets'
1250
1251 raise NoAndroidTargetError(
1252 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001253 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001254
1255
1256def determine_platform_version():
1257 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001258 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001259 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1260 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001261
1262
1263def determine_milestone_version():
1264 """Returns the platform version from the source root."""
1265 # Milestone version is something like '79'.
1266 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1267 return version.chrome_branch
1268
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001269
Michael Mortensen009cb662019-10-21 11:38:43 -06001270def determine_full_version():
1271 """Returns the full version from the source root."""
1272 # Full version is something like 'R79-12575.0.0'.
1273 milestone_version = determine_milestone_version()
1274 platform_version = determine_platform_version()
1275 full_version = ('R%s-%s' % (milestone_version, platform_version))
1276 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001277
1278
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001279def find_fingerprints(
1280 build_target: 'build_target_lib.BuildTarget') -> List[str]:
Michael Mortensende716a12020-05-15 11:27:00 -06001281 """Returns a list of fingerprints for this build.
1282
1283 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001284 build_target: The build target.
Michael Mortensende716a12020-05-15 11:27:00 -06001285
1286 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001287 List of fingerprint strings.
Michael Mortensende716a12020-05-15 11:27:00 -06001288 """
1289 cros_build_lib.AssertInsideChroot()
1290 fp_file = 'cheets-fingerprint.txt'
1291 fp_path = os.path.join(
1292 image_lib.GetLatestImageLink(build_target.name),
1293 fp_file)
1294 if not os.path.isfile(fp_path):
1295 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001296 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001297 logging.info('Reading fingerprint file: %s', fp_path)
1298 fingerprints = osutils.ReadFile(fp_path).splitlines()
1299 return fingerprints
1300
1301
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001302def get_all_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen59e30872020-05-18 14:12:49 -06001303 """Extract firmware version for all models present.
1304
1305 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001306 build_target: The build target.
Michael Mortensen59e30872020-05-18 14:12:49 -06001307
1308 Returns:
1309 A dict of FirmwareVersions namedtuple instances by model.
1310 Each element will be populated based on whether it was present in the
1311 command output.
1312 """
1313 cros_build_lib.AssertInsideChroot()
1314 result = {}
1315 # Note that example output for _get_firmware_version_cmd_result is available
1316 # in the packages_unittest.py for testing get_all_firmware_versions.
1317 cmd_result = _get_firmware_version_cmd_result(build_target)
1318
Benjamin Shai12c767e2022-01-12 15:17:44 +00001319 if cmd_result:
1320 # There is a blank line between the version info for each model.
1321 firmware_version_payloads = cmd_result.split('\n\n')
1322 for firmware_version_payload in firmware_version_payloads:
1323 if 'BIOS' in firmware_version_payload:
1324 firmware_version = _find_firmware_versions(firmware_version_payload)
1325 result[firmware_version.model] = firmware_version
Michael Mortensen59e30872020-05-18 14:12:49 -06001326 return result
1327
1328
Benjamin Shai0858cd32022-01-10 20:23:49 +00001329class FirmwareVersions(NamedTuple):
1330 """Tuple to hold firmware versions, with truthiness."""
1331 model: Optional[str]
1332 main: Optional[str]
1333 main_rw: Optional[str]
1334 ec: Optional[str]
1335 ec_rw: Optional[str]
1336
1337 def __bool__(self):
1338 return bool(
1339 self.model or self.main or self.main_rw or self.ec or self.ec_rw)
Michael Mortensen71ef5682020-05-07 14:29:24 -06001340
1341
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001342def get_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen71ef5682020-05-07 14:29:24 -06001343 """Extract version information from the firmware updater, if one exists.
1344
1345 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001346 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001347
1348 Returns:
1349 A FirmwareVersions namedtuple instance.
1350 Each element will either be set to the string output by the firmware
1351 updater shellball, or None if there is no firmware updater.
1352 """
1353 cros_build_lib.AssertInsideChroot()
1354 cmd_result = _get_firmware_version_cmd_result(build_target)
1355 if cmd_result:
1356 return _find_firmware_versions(cmd_result)
1357 else:
1358 return FirmwareVersions(None, None, None, None, None)
1359
1360
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001361def _get_firmware_version_cmd_result(
Alex Klein89b58732021-12-23 10:16:03 -07001362 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensen71ef5682020-05-07 14:29:24 -06001363 """Gets the raw result output of the firmware updater version command.
1364
1365 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001366 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001367
1368 Returns:
1369 Command execution result.
1370 """
1371 updater = os.path.join(build_target.root,
1372 'usr/sbin/chromeos-firmwareupdate')
1373 logging.info('Calling updater %s', updater)
1374 # Call the updater using the chroot-based path.
Alex Klein89b58732021-12-23 10:16:03 -07001375 try:
1376 return cros_build_lib.run([updater, '-V'],
1377 capture_output=True, log_output=True,
1378 encoding='utf-8').stdout
1379 except cros_build_lib.RunCommandError:
1380 # Updater probably doesn't exist (e.g. betty).
1381 return None
Michael Mortensen71ef5682020-05-07 14:29:24 -06001382
1383
1384def _find_firmware_versions(cmd_output):
1385 """Finds firmware version output via regex matches against the cmd_output.
1386
1387 Args:
1388 cmd_output: The raw output to search against.
1389
1390 Returns:
1391 FirmwareVersions namedtuple with results.
1392 Each element will either be set to the string output by the firmware
1393 updater shellball, or None if there is no match.
1394 """
1395
1396 # Sometimes a firmware bundle includes a special combination of RO+RW
1397 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1398 # version" field. In other cases, the "(RW) version" field is not present.
1399 # Therefore, search for the "(RW)" fields first and if they aren't present,
1400 # fallback to the other format. e.g. just "BIOS version:".
1401 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1402 main = None
1403 main_rw = None
1404 ec = None
1405 ec_rw = None
1406 model = None
1407
1408 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1409 if match:
1410 main = match.group('version')
1411
1412 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1413 if match:
1414 main_rw = match.group('version')
1415
1416 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1417 if match:
1418 ec = match.group('version')
1419
1420 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1421 if match:
1422 ec_rw = match.group('version')
1423
1424 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1425 if match:
1426 model = match.group('model')
1427
1428 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001429
1430
Benjamin Shai0858cd32022-01-10 20:23:49 +00001431class MainEcFirmwareVersions(NamedTuple):
1432 """Tuple to hold main and ec firmware versions, with truthiness."""
1433 main_fw_version: Optional[str]
1434 ec_fw_version: Optional[str]
1435
1436 def __bool__(self):
1437 return bool(self.main_fw_version or self.ec_fw_version)
1438
Michael Mortensena4af79e2020-05-06 16:18:48 -06001439
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001440def determine_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensena4af79e2020-05-06 16:18:48 -06001441 """Returns a namedtuple with main and ec firmware versions.
1442
1443 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001444 build_target: The build target.
Michael Mortensena4af79e2020-05-06 16:18:48 -06001445
1446 Returns:
1447 MainEcFirmwareVersions namedtuple with results.
1448 """
1449 fw_versions = get_firmware_versions(build_target)
1450 main_fw_version = fw_versions.main_rw or fw_versions.main
1451 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1452
1453 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001454
Benjamin Shai0858cd32022-01-10 20:23:49 +00001455
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001456def determine_kernel_version(
Benjamin Shai5ce11a22022-05-06 14:10:53 +00001457 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001458 """Returns a string containing the kernel version for this build target.
1459
1460 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001461 build_target: The build target.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001462
1463 Returns:
Benjamin Shai5ce11a22022-05-06 14:10:53 +00001464 The kernel versions, or None.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001465 """
1466 try:
Benjamin Shai5ce11a22022-05-06 14:10:53 +00001467 packages = portage_util.GetPackageDependencies(
1468 'virtual/linux-sources', board=build_target.name)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001469 except cros_build_lib.RunCommandError as e:
1470 logging.warning('Unable to get package list for metadata: %s', e)
Benjamin Shai5ce11a22022-05-06 14:10:53 +00001471 return None
1472 for package in packages:
1473 if package.startswith('sys-kernel/chromeos-kernel-'):
1474 kernel_version = package_info.SplitCPV(package).version
1475 logging.info('Found active kernel version: %s', kernel_version)
1476 return kernel_version
1477 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001478
1479
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001480def get_models(
1481 build_target: 'build_target_lib.BuildTarget',
1482 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001483 """Obtain a list of models supported by a unified board.
1484
1485 This ignored whitelabel models since GoldenEye has no specific support for
1486 these at present.
1487
1488 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001489 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001490 log_output: Whether to log the output of the cros_config_host invocation.
1491
1492 Returns:
1493 A list of models supported by this board, if it is a unified build; None,
1494 if it is not a unified build.
1495 """
1496 return _run_cros_config_host(build_target, ['list-models'],
1497 log_output=log_output)
1498
1499
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001500def get_key_id(
1501 build_target: 'build_target_lib.BuildTarget',
1502 model: str) -> Optional[str]:
Michael Mortensen359c1f32020-05-28 19:35:42 -06001503 """Obtain the key_id for a model within the build_target.
1504
1505 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001506 build_target: The build target.
1507 model: The model name
Michael Mortensen359c1f32020-05-28 19:35:42 -06001508
1509 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001510 A key_id or None.
Michael Mortensen359c1f32020-05-28 19:35:42 -06001511 """
1512 model_arg = '--model=' + model
1513 key_id_list = _run_cros_config_host(
1514 build_target,
1515 [model_arg, 'get', '/firmware-signing', 'key-id'])
1516 key_id = None
1517 if len(key_id_list) == 1:
1518 key_id = key_id_list[0]
1519 return key_id
1520
1521
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001522def _run_cros_config_host(
1523 build_target: 'build_target_lib.BuildTarget',
1524 args: List[str],
1525 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001526 """Run the cros_config_host tool.
1527
1528 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001529 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001530 args: List of arguments to pass.
1531 log_output: Whether to log the output of the cros_config_host.
1532
1533 Returns:
1534 Output of the tool
1535 """
1536 cros_build_lib.AssertInsideChroot()
1537 tool = '/usr/bin/cros_config_host'
1538 if not os.path.isfile(tool):
1539 return None
1540
1541 config_fname = build_target.full_path(
1542 'usr/share/chromeos-config/yaml/config.yaml')
1543
1544 result = cros_build_lib.run(
1545 [tool, '-c', config_fname] + args,
1546 capture_output=True,
1547 encoding='utf-8',
1548 log_output=log_output,
1549 check=False)
1550 if result.returncode:
1551 # Show the output for debugging purposes.
1552 if 'No such file or directory' not in result.error:
1553 logging.error('cros_config_host failed: %s\n', result.error)
1554 return None
1555 return result.output.strip().splitlines()