blob: d1e75f342370ea5de62394a68125e59387e76461 [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):
Madeleine Hardt8ae7f102022-03-24 20:26:11 +0000117 for var, value in variables.items():
118 line = re.sub(fr'\b{var}=\S+', f'{var}="{value}"', line)
119 sys.stdout.write(line)
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600120 finally:
121 fileinput.close()
122
123
Alex Klein87531182019-08-12 15:23:37 -0600124def uprevs_versioned_package(package):
125 """Decorator to register package uprev handlers."""
126 assert package
127
128 def register(func):
129 """Registers |func| as a handler for |package|."""
130 _UPREV_FUNCS[package] = func
131
132 @functools.wraps(func)
133 def pass_through(*args, **kwargs):
134 return func(*args, **kwargs)
135
136 return pass_through
137
138 return register
139
140
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900141class UprevAndroidResult(NamedTuple):
142 """Results of an Android uprev."""
143 revved: bool
144 android_atom: str = None
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900145 modified_files: List[str] = None
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900146
147
148def uprev_android(
149 android_package: str,
150 chroot: 'chroot_lib.Chroot',
151 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
152 android_build_branch: Optional[str] = None,
153 android_version: Optional[str] = None,
154 skip_commit: bool = False) -> UprevAndroidResult:
155 """Performs an Android uprev by calling cros_mark_android_as_stable.
156
157 Args:
158 android_package: The Android package to uprev.
159 chroot: The chroot to enter.
160 build_targets: List of build targets to cleanup after uprev.
161 android_build_branch: Override the default Android branch corresponding to
162 the package.
163 android_version: Uprev to the particular version. By default the latest
164 available version is used.
165 skip_commit: Whether to skip committing the change after a successful uprev.
166
167 Returns:
168 The uprev result containing:
169 revved: Whether an uprev happened.
170 android_atom: If revved, the portage atom for the revved Android ebuild.
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900171 modified_files: If revved, list of files being modified.
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900172 """
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700173 command = [
174 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900175 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700176 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600177 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900178 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900179 if android_build_branch:
180 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600181 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900182 command.append(f'--force_version={android_version}')
183 if skip_commit:
184 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600185
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700186 result = cros_build_lib.run(
187 command,
188 stdout=True,
189 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500190 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700191 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600192
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900193 # cros_mark_android_as_stable prints the uprev result to stdout as JSON in a
194 # single line. We only take the last line from stdout to make sure no junk
195 # output is included (e.g. messages from bashrc scripts that run upon entering
196 # the chroot.)
197 output = json.loads(result.stdout.strip().splitlines()[-1])
198
199 if not output['revved']:
Alex Klein4de25e82019-08-05 15:58:39 -0600200 logging.info('Found nothing to rev.')
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900201 return UprevAndroidResult(revved=False)
202
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900203 android_atom = output['android_atom']
Alex Klein4de25e82019-08-05 15:58:39 -0600204
205 for target in build_targets or []:
206 # Sanity check: We should always be able to merge the version of
207 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900208 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600209 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700210 cros_build_lib.run(
211 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600212 except cros_build_lib.RunCommandError:
213 logging.error(
214 'Cannot emerge-%s =%s\nIs Android pinned to an older '
215 'version?', target, android_atom)
216 raise AndroidIsPinnedUprevError(android_atom)
217
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900218 return UprevAndroidResult(revved=True,
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900219 android_atom=android_atom,
220 modified_files=output['modified_files'])
221
222
223def uprev_android_lkgb(android_package: str,
224 build_targets: List['build_target_lib.BuildTarget'],
225 chroot: 'chroot_lib.Chroot'
226 ) -> uprev_lib.UprevVersionedPackageResult:
227 """Uprevs an Android package to the version specified in the LKGB file.
228
229 This is the PUpr handler for Android packages, triggered whenever the
230 corresponding LKGB file is being updated.
231
232 PUpr for Android does not test the uprev change in CQ; instead we run separate
233 jobs to test new Android versions, and we write the latest vetted version to
234 the LKGB file. Find the design at go/android-uprev-recipes.
235
236 Args:
237 android_package: The Android package to uprev.
238 build_targets: List of build targets to cleanup after uprev.
239 chroot: The chroot to enter.
240
241 Returns:
242 An uprev_lib.UprevVersionedPackageResult containing the new version and a
243 list of modified files.
244 """
Shao-Chuan Lee0e787d22021-12-13 21:33:35 +0900245 android_package_dir = android.GetAndroidPackageDir(android_package)
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900246 android_version = android.ReadLKGB(android_package_dir)
247
248 result = uprev_lib.UprevVersionedPackageResult()
249 uprev_result = uprev_android(android_package, chroot,
250 build_targets=build_targets,
251 android_version=android_version,
252 skip_commit=True)
253 if not uprev_result.revved:
254 return result
255
Shao-Chuan Lee0e787d22021-12-13 21:33:35 +0900256 # cros_mark_android_as_stable returns paths relative to |android.OVERLAY_DIR|.
257 result.add_result(android_version,
258 [os.path.join(android.OVERLAY_DIR, f)
259 for f in uprev_result.modified_files])
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900260 return result
261
262
263def define_uprev_android_lkgb_handlers():
264 """Dynamically define uprev handlers for each Android package"""
265
266 def define_handler(android_package):
267 """Defines the uprev handler for an Android package."""
268 full_package_name = 'chromeos-base/' + android_package
269
270 @uprevs_versioned_package(full_package_name)
271 def _handler(build_targets, _refs, chroot):
272 return uprev_android_lkgb(android_package, build_targets, chroot)
273
274 for android_package in constants.ANDROID_ALL_PACKAGES:
275 define_handler(android_package)
276
277
278define_uprev_android_lkgb_handlers()
Alex Klein4de25e82019-08-05 15:58:39 -0600279
280
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700281def uprev_build_targets(
282 build_targets: Optional[List['build_target_lib.BuildTarget']],
283 overlay_type: str,
284 chroot: 'chroot_lib.Chroot' = None,
285 output_dir: Optional[str] = None):
Alex Kleineb77ffa2019-05-28 14:47:44 -0600286 """Uprev the set provided build targets, or all if not specified.
287
288 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700289 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600290 whose overlays should be uprevved, empty or None for all.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700291 overlay_type: One of the valid overlay types except None (see
Alex Kleineb77ffa2019-05-28 14:47:44 -0600292 constants.VALID_OVERLAYS).
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700293 chroot: The chroot to clean, if desired.
294 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600295 """
296 # Need a valid overlay, but exclude None.
297 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
298
299 if build_targets:
300 overlays = portage_util.FindOverlaysForBoards(
301 overlay_type, boards=[t.name for t in build_targets])
302 else:
303 overlays = portage_util.FindOverlays(overlay_type)
304
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700305 return uprev_overlays(
306 overlays,
307 build_targets=build_targets,
308 chroot=chroot,
309 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600310
311
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700312def uprev_overlays(
313 overlays: List[str],
314 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
315 chroot: Optional['chroot_lib.Chroot'] = None,
316 output_dir: Optional[str] = None) -> List[str]:
Alex Kleineb77ffa2019-05-28 14:47:44 -0600317 """Uprev the given overlays.
318
319 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700320 overlays: The list of overlay paths.
321 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600322 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700323 chroot: The chroot to clean, if desired.
324 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600325
326 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700327 The paths to all of the modified ebuild files. This includes the new files
328 that were added (i.e. the new versions) and all of the removed files
329 (i.e. the old versions).
Alex Kleineb77ffa2019-05-28 14:47:44 -0600330 """
331 assert overlays
332
333 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
334
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700335 uprev_manager = uprev_lib.UprevOverlayManager(
336 overlays,
337 manifest,
338 build_targets=build_targets,
339 chroot=chroot,
340 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600341 uprev_manager.uprev()
342
Dhanya Ganeshd03a4162021-08-25 00:21:50 +0000343 return uprev_manager.modified_ebuilds, uprev_manager.revved_packages
Alex Kleineb77ffa2019-05-28 14:47:44 -0600344
345
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700346def uprev_versioned_package(
347 package: package_info.CPV,
348 build_targets: List['build_target_lib.BuildTarget'],
349 refs: List[uprev_lib.GitRef],
350 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
Alex Klein87531182019-08-12 15:23:37 -0600351 """Call registered uprev handler function for the package.
352
353 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700354 package: The package being uprevved.
355 build_targets: The build targets to clean on a successful uprev.
356 refs:
357 chroot: The chroot to enter for cleaning.
Alex Klein87531182019-08-12 15:23:37 -0600358
359 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700360 The result.
Alex Klein87531182019-08-12 15:23:37 -0600361 """
362 assert package
363
364 if package.cp not in _UPREV_FUNCS:
365 raise UnknownPackageError(
366 'Package "%s" does not have a registered handler.' % package.cp)
367
Andrew Lambea9a8a22019-12-12 14:03:43 -0700368 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600369
370
Navil Perezf57ba872020-06-04 22:38:37 +0000371@uprevs_versioned_package('media-libs/virglrenderer')
372def uprev_virglrenderer(_build_targets, refs, _chroot):
373 """Updates virglrenderer ebuilds.
374
375 See: uprev_versioned_package.
376
377 Returns:
378 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
379 """
Navil Perezf57ba872020-06-04 22:38:37 +0000380 overlay = os.path.join(constants.SOURCE_ROOT,
381 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600382 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
383 'virglrenderer')
384 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000385
386 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
387 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000388 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
389 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000390 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
391
George Engelbrechte73f2782020-06-10 14:10:46 -0600392 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600393 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000394 result.add_result(refs[0].revision, updated_files)
395 return result
396
Jose Magana03b5a842020-08-19 12:52:59 +1000397@uprevs_versioned_package('chromeos-base/drivefs')
398def uprev_drivefs(_build_targets, refs, chroot):
399 """Updates drivefs ebuilds.
400
Harvey Yang3eee06c2021-03-18 15:47:56 +0800401 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000402 See: uprev_versioned_package.
403
404 Returns:
405 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
406 """
407
Ben Reiche779cf42020-12-15 03:21:31 +0000408 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000409 result = uprev_lib.UprevVersionedPackageResult()
410 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000411
Harvey Yang3eee06c2021-03-18 15:47:56 +0800412 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
413 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000414 if not drivefs_version:
415 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000416 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000417
Ben Reiche779cf42020-12-15 03:21:31 +0000418 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000419
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000420 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000421 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000422 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000423 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800424 chroot,
425 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000426
427 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000428 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000429 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000430 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000431
432 return result
433
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800434@uprevs_versioned_package('chromeos-base/perfetto')
435def uprev_perfetto(_build_targets, refs, chroot):
436 """Updates Perfetto ebuilds.
437
Harvey Yang3eee06c2021-03-18 15:47:56 +0800438 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800439 See: uprev_versioned_package.
440
441 Returns:
442 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
443 """
444 result = uprev_lib.UprevVersionedPackageResult()
445
Harvey Yang3eee06c2021-03-18 15:47:56 +0800446 PERFETTO_REFS_PREFIX = 'refs/tags/v'
447 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800448 if not perfetto_version:
449 # No valid Perfetto version is identified.
450 return result
451
452 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
453
454 # Attempt to uprev perfetto package.
455 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
456
Harvey Yang3eee06c2021-03-18 15:47:56 +0800457 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
458 PERFETTO_PATH,
459 perfetto_version,
460 chroot,
461 allow_downrev=False,
462 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800463
464 if not uprev_result:
465 return result
466
467 result.add_result(perfetto_version, uprev_result.changed_files)
468
469 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000470
Yaakov Shaul395ae832019-09-09 14:45:32 -0600471@uprevs_versioned_package('afdo/kernel-profiles')
472def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600473 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600474
475 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600476
477 Raises:
478 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600479 """
480 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
481 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
482
David Burger92485342019-09-10 17:52:45 -0600483 with open(path, 'r') as f:
484 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600485
Chris McDonald38409112020-09-24 11:24:51 -0600486 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600487 for kernel_pkg, version_info in versions.items():
488 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
489 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600490 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600491 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600492 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600493 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600494 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600495 patch_ebuild_vars(ebuild_path,
496 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600497
498 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600499 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400500 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600501 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600502 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600503 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600504 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600505
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600506 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600507
Yaakov Shaul730814a2019-09-10 13:58:25 -0600508 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
509
510 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600511
512
Trent Begineb624182020-07-14 10:09:45 -0600513@uprevs_versioned_package('chromeos-base/termina-dlc')
Maciek Swiech6b12f662022-01-25 16:51:19 +0000514@uprevs_versioned_package('chromeos-base/termina-tools-dlc')
515def uprev_termina_dlcs(_build_targets, _refs, chroot):
516 """Updates shared termina-dlc and termina-tools-dlc ebuilds.
517
518 termina-dlc - chromeos-base/termina-dlc
519 termina-tools-dlc - chromeos-base/termina-tools-dlc
Trent Beginaf51f1b2020-03-09 17:35:31 -0600520
521 See: uprev_versioned_package.
522 """
Maciek Swiech6b12f662022-01-25 16:51:19 +0000523 termina_dlc_pkg = 'termina-dlc'
524 termina_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
525 'chromeos-base', termina_dlc_pkg)
526 tools_dlc_pkg = 'termina-tools-dlc'
527 tools_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
528 'chromeos-base', tools_dlc_pkg)
Patrick Meiring5897add2020-09-16 16:30:17 +1000529
Maciek Swiech6b12f662022-01-25 16:51:19 +0000530 # termina-dlc and termina-tools-dlc are pinned to the same version.
531 version_pin_src_path = _get_version_pin_src_path(termina_dlc_pkg_path)
Patrick Meiring5897add2020-09-16 16:30:17 +1000532 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
533
Maciek Swiech6b12f662022-01-25 16:51:19 +0000534 result = uprev_lib.uprev_ebuild_from_pin(termina_dlc_pkg_path, version_no_rev,
535 chroot)
536 result += uprev_lib.uprev_ebuild_from_pin(tools_dlc_pkg_path, version_no_rev,
537 chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000538
Maciek Swiech6b12f662022-01-25 16:51:19 +0000539 return result
Patrick Meiring5897add2020-09-16 16:30:17 +1000540
Julio Hurtadof1befec2021-05-05 21:34:26 +0000541@uprevs_versioned_package('chromeos-base/chromeos-lacros')
542def uprev_lacros(_build_targets, refs, chroot):
543 """Updates lacros ebuilds.
544
Julio Hurtadoa994e002021-07-07 17:57:45 +0000545 Version to uprev to is gathered from the QA qualified version tracking file
546 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
547 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000548
549 See: uprev_versioned_package.
550 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000551 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000552 path = os.path.join(
Dennis Kempin257b74c2021-09-28 14:38:17 -0700553 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000554 lacros_version = refs[0].revision
555 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
556 lacros_version,
557 chroot,
558 allow_downrev=False)
559
560 if not uprev_result:
561 return result
562
563 result.add_result(lacros_version, uprev_result.changed_files)
564 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000565
566
Julio Hurtado870ed322021-12-03 18:22:40 +0000567@uprevs_versioned_package('chromeos-base/chromeos-lacros-parallel')
568def uprev_lacros_in_parallel(
569 _build_targets: Optional[List['build_target_lib.BuildTarget']],
570 refs: List[uprev_lib.GitRef],
571 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
572 """Updates lacros ebuilds in parallel with ash-chrome.
573
574 This handler is going to be used temporarily while lacros transitions to being
575 uprevved atomically with ash-chrome. Unlike a standalone lacros uprev, this
576 handler will not need to look at the QA qualified file. Rather, it will
577 function identical to ash-chrome using git tags.
578
579 See: uprev_versioned_package.
580
581 Returns:
582 UprevVersionedPackageResult: The result.
583 """
584 result = uprev_lib.UprevVersionedPackageResult()
585 path = os.path.join(
586 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
587 lacros_version = uprev_lib.get_version_from_refs(refs)
588 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
589 lacros_version,
590 chroot,
591 allow_downrev=False)
592
593 if not uprev_result:
594 return result
595
596 result.add_result(lacros_version, uprev_result.changed_files)
597 return result
598
599
Patrick Meiring5897add2020-09-16 16:30:17 +1000600@uprevs_versioned_package('app-emulation/parallels-desktop')
601def uprev_parallels_desktop(_build_targets, _refs, chroot):
602 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
603
604 See: uprev_versioned_package
605
606 Returns:
607 UprevVersionedPackageResult: The result.
608 """
609 package = 'parallels-desktop'
610 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
611 'app-emulation', package)
612 version_pin_src_path = _get_version_pin_src_path(package_path)
613
614 # Expect a JSON blob like the following:
615 # {
616 # "version": "1.2.3",
617 # "test_image": { "url": "...", "size": 12345678,
618 # "sha256sum": "<32 bytes of hexadecimal>" }
619 # }
620 with open(version_pin_src_path, 'r') as f:
621 pinned = json.load(f)
622
623 if 'version' not in pinned or 'test_image' not in pinned:
624 raise UprevError('VERSION-PIN for %s missing version and/or '
625 'test_image field' % package)
626
627 version = pinned['version']
628 if not isinstance(version, str):
629 raise UprevError('version in VERSION-PIN for %s not a string' % package)
630
631 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600632 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000633
634 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100635 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
636 'local/bundles/crosint/pita/data/'
637 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000638 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
639 with open(test_image_src_path, 'w') as f:
640 json.dump(pinned['test_image'], f, indent=2)
641 result.add_result(version, [test_image_src_path])
642
643 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600644
645
Trent Begin315d9d92019-12-03 21:55:53 -0700646@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600647def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700648 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
649
650 See: uprev_versioned_package.
651 """
652 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700653 package_path = os.path.join('src', 'private-overlays',
654 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000655 version_pin_src_path = _get_version_pin_src_path(package_path)
656 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700657
Chris McDonald38409112020-09-24 11:24:51 -0600658 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700659
660
David Riley8513c1f2021-10-14 17:07:41 -0700661@uprevs_versioned_package('chromeos-base/borealis-dlc')
662def uprev_borealis_dlc(_build_targets, _refs, chroot):
663 """Updates shared borealis-dlc ebuild - chromeos-base/borealis-dlc.
664
665 See: uprev_versioned_package.
666 """
David Rileybc100ba2022-01-10 10:06:59 -0800667 package_path = os.path.join('src', 'private-overlays',
668 'chromeos-partner-overlay', 'chromeos-base',
669 'borealis-dlc')
David Riley8513c1f2021-10-14 17:07:41 -0700670
671 version_pin_src_path = _get_version_pin_src_path(package_path)
672 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
673
674 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
675
676
Patrick Meiring5897add2020-09-16 16:30:17 +1000677def _get_version_pin_src_path(package_path):
678 """Returns the path to the VERSION-PIN file for the given package."""
679 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
680
681
Alex Klein87531182019-08-12 15:23:37 -0600682@uprevs_versioned_package(constants.CHROME_CP)
Alex Klein4e839252022-01-06 13:29:18 -0700683def uprev_chrome_from_ref(build_targets, refs, _chroot):
Alex Klein87531182019-08-12 15:23:37 -0600684 """Uprev chrome and its related packages.
685
686 See: uprev_versioned_package.
687 """
688 # Determine the version from the refs (tags), i.e. the chrome versions are the
689 # tag names.
Julio Hurtado870ed322021-12-03 18:22:40 +0000690 chrome_version = uprev_lib.get_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600691 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600692
Alex Klein4e839252022-01-06 13:29:18 -0700693 return uprev_chrome(chrome_version, build_targets, None)
Alex Kleinf69bd802021-06-22 15:43:49 -0600694
695
Alex Klein9ce3f682021-06-23 15:06:44 -0600696def revbump_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600697 build_targets: List['build_target_lib.BuildTarget'] = None,
Alex Klein9ce3f682021-06-23 15:06:44 -0600698 chroot: Optional['chroot_lib.Chroot'] = None
699) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600700 """Attempt to revbump chrome.
701
702 Revbumps are done by executing an uprev using the current stable version.
703 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
704 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
705 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
706 """
707 chrome_version = uprev_lib.get_stable_chrome_version()
Alex Klein16ea1b32021-10-01 15:48:50 -0600708 return uprev_chrome(chrome_version, build_targets, chroot)
Alex Kleinf69bd802021-06-22 15:43:49 -0600709
710
Alex Klein9ce3f682021-06-23 15:06:44 -0600711def uprev_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600712 chrome_version: str,
713 build_targets: Optional[List['build_target_lib.BuildTarget']],
714 chroot: Optional['chroot_lib.Chroot']
Alex Klein9ce3f682021-06-23 15:06:44 -0600715) -> uprev_lib.UprevVersionedPackageResult:
716 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600717 uprev_manager = uprev_lib.UprevChromeManager(
718 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600719 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600720 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
721 # attempt. The expected behavior is documented in the following table:
722 #
723 # Outcome of Chrome uprev attempt:
724 # NEWER_VERSION_EXISTS:
725 # Do nothing.
726 # SAME_VERSION_EXISTS or REVISION_BUMP:
727 # Uprev followers
728 # Assert not VERSION_BUMP (any other outcome is fine)
729 # VERSION_BUMP or NEW_EBUILD_CREATED:
730 # Uprev followers
731 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600732
733 # Start with chrome itself so we can proceed accordingly.
734 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
735 if chrome_result.newer_version_exists:
736 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600737 return result
Alex Klein87531182019-08-12 15:23:37 -0600738
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600739 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600740 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600741 follower_result = uprev_manager.uprev(package)
742 if chrome_result.stable_version and follower_result.version_bump:
743 logging.warning('%s had a version bump, but no more than a revision bump '
744 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600745
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600746 if uprev_manager.modified_ebuilds:
747 # Record changes when we have them.
748 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
749
750 return result
Alex Klein87531182019-08-12 15:23:37 -0600751
752
Harvey Yang3eee06c2021-03-18 15:47:56 +0800753def _get_latest_version_from_refs(refs_prefix: str,
754 refs: List[uprev_lib.GitRef]) -> str:
755 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000756
Ben Reiche779cf42020-12-15 03:21:31 +0000757 Versions are compared using |distutils.version.LooseVersion| and
758 the latest version is returned.
759
760 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800761 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800762 refs: The tags to parse for the latest Perfetto version.
763
764 Returns:
765 The latest Perfetto version to use.
766 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800767 valid_refs = []
768 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800769 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800770 valid_refs.append(gitiles.ref)
771
772 if not valid_refs:
773 return None
774
775 # Sort by version and take the latest version.
776 target_version_ref = sorted(valid_refs,
777 key=LooseVersion,
778 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800779 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800780
781
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700782def _generate_platform_c_files(
783 replication_config: replication_config_pb2.ReplicationConfig,
784 chroot: 'chroot_lib.Chroot') -> List[str]:
Andrew Lamb9563a152019-12-04 11:42:18 -0700785 """Generates platform C files from a platform JSON payload.
786
787 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700788 replication_config: A ReplicationConfig that has already been run. If it
789 produced a build_config.json file, that file will be used to generate
790 platform C files. Otherwise, nothing will be generated.
791 chroot: The chroot to use to generate.
Andrew Lamb9563a152019-12-04 11:42:18 -0700792
793 Returns:
794 A list of generated files.
795 """
796 # Generate the platform C files from the build config. Note that it would be
797 # more intuitive to generate the platform C files from the platform config;
798 # however, cros_config_schema does not allow this, because the platform config
799 # payload is not always valid input. For example, if a property is both
800 # 'required' and 'build-only', it will fail schema validation. Thus, use the
801 # build config, and use '-f' to filter.
802 build_config_path = [
803 rule.destination_path
804 for rule in replication_config.file_replication_rules
805 if rule.destination_path.endswith('build_config.json')
806 ]
807
808 if not build_config_path:
809 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700810 'No build_config.json found, will not generate platform C files. '
811 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700812 return []
813
814 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700815 raise ValueError('Expected at most one build_config.json destination path. '
816 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700817
818 build_config_path = build_config_path[0]
819
820 # Paths to the build_config.json and dir to output C files to, in the
821 # chroot.
822 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
823 build_config_path)
824 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
825 os.path.dirname(build_config_path))
826
827 command = [
828 'cros_config_schema', '-m', build_config_chroot_path, '-g',
829 generated_output_chroot_dir, '-f', '"TRUE"'
830 ]
831
832 cros_build_lib.run(
833 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
834
835 # A relative (to the source root) path to the generated C files.
836 generated_output_dir = os.path.dirname(build_config_path)
837 generated_files = []
838 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
839 for f in expected_c_files:
840 if os.path.exists(
841 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
842 generated_files.append(os.path.join(generated_output_dir, f))
843
844 if len(expected_c_files) != len(generated_files):
845 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
846
847 return generated_files
848
849
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700850def _get_private_overlay_package_root(ref: uprev_lib.GitRef, package: str):
Andrew Lambe836f222019-12-09 12:27:38 -0700851 """Returns the absolute path to the root of a given private overlay.
852
853 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700854 ref: GitRef for the private overlay.
855 package: Path to the package in the overlay.
Andrew Lambe836f222019-12-09 12:27:38 -0700856 """
857 # There might be a cleaner way to map from package -> path within the source
858 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700859 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700860 match = re.match(private_overlay_ref_pattern, ref.path)
861 if not match:
862 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
863 (private_overlay_ref_pattern, ref))
864
865 overlay = match.group(1)
866
867 return os.path.join(constants.SOURCE_ROOT,
868 'src/private-overlays/overlay-%s-private' % overlay,
869 package)
870
871
Andrew Lambea9a8a22019-12-12 14:03:43 -0700872@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
873def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700874 """Replicate a private cros_config change to the corresponding public config.
875
Alex Kleinad6b48a2020-01-08 16:57:41 -0700876 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700877 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700878 package = 'chromeos-base/chromeos-config-bsp'
879
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700880 if len(refs) != 1:
881 raise ValueError('Expected exactly one ref, actual %s' % refs)
882
883 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700884 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700885 replication_config_path = os.path.join(package_root,
886 'replication_config.jsonpb')
887
888 try:
889 replication_config = json_format.Parse(
890 osutils.ReadFile(replication_config_path),
891 replication_config_pb2.ReplicationConfig())
892 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700893 raise ValueError(
894 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700895
896 replication_lib.Replicate(replication_config)
897
898 modified_files = [
899 rule.destination_path
900 for rule in replication_config.file_replication_rules
901 ]
902
Andrew Lamb9563a152019-12-04 11:42:18 -0700903 # The generated platform C files are not easily filtered by replication rules,
904 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
905 # files cannot. Therefore, replicate and filter the JSON payloads, and then
906 # generate filtered C files from the JSON payload.
907 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700908
909 # Use the private repo's commit hash as the new version.
910 new_private_version = refs[0].revision
911
Andrew Lamb988f4da2019-12-10 10:16:43 -0700912 # modified_files should contain only relative paths at this point, but the
913 # returned UprevVersionedPackageResult must contain only absolute paths.
914 for i, modified_file in enumerate(modified_files):
915 assert not os.path.isabs(modified_file)
916 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
917
Chris McDonald38409112020-09-24 11:24:51 -0600918 return uprev_lib.UprevVersionedPackageResult().add_result(
919 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700920
921
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700922@uprevs_versioned_package('chromeos-base/crosvm')
923def uprev_crosvm(_build_targets, refs, _chroot):
924 """Updates crosvm ebuilds to latest revision
925
926 crosvm is not versioned. We are updating to the latest commit on the main
927 branch.
928
929 See: uprev_versioned_package.
930
931 Returns:
932 UprevVersionedPackageResult: The result of updating crosvm ebuilds.
933 """
934 overlay = os.path.join(constants.SOURCE_ROOT,
935 constants.CHROMIUMOS_OVERLAY_DIR)
936 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'crosvm')
937 manifest = git.ManifestCheckout.Cached(repo_path)
938
939 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
Dennis Kempin257b74c2021-09-28 14:38:17 -0700940 uprev_manager.uprev(
941 package_list=[
942 'chromeos-base/crosvm',
943 'dev-rust/assertions',
944 'dev-rust/cros_async',
945 'dev-rust/cros_fuzz',
946 'dev-rust/data_model',
947 'dev-rust/enumn',
948 'dev-rust/io_uring',
949 'dev-rust/p9',
950 'dev-rust/sync',
951 'dev-rust/sys_util',
952 'dev-rust/tempfile',
953 'media-sound/audio_streams',
954 ],
955 force=True
956 )
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700957
958 updated_files = uprev_manager.modified_ebuilds
959 result = uprev_lib.UprevVersionedPackageResult()
960 result.add_result(refs[0].revision, updated_files)
961 return result
962
963
Alex Klein5caab872021-09-10 11:44:37 -0600964def get_best_visible(
965 atom: str,
966 build_target: Optional['build_target_lib.BuildTarget'] = None
967) -> package_info.PackageInfo:
Alex Kleinbbef2b32019-08-27 10:38:50 -0600968 """Returns the best visible CPV for the given atom.
969
970 Args:
Alex Klein5caab872021-09-10 11:44:37 -0600971 atom: The atom to look up.
972 build_target: The build target whose sysroot should be searched, or the SDK
973 if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700974
975 Returns:
Alex Klein5caab872021-09-10 11:44:37 -0600976 The best visible package, or None if none are visible.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600977 """
David Burger1e0fe232019-07-01 14:52:07 -0600978 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600979
Alex Klein5caab872021-09-10 11:44:37 -0600980 return portage_util.PortageqBestVisible(
981 atom,
982 board=build_target.name if build_target else None,
983 sysroot=build_target.root if build_target else None)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600984
985
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700986def has_prebuilt(
987 atom: str,
988 build_target: 'build_target_lib.BuildTarget' = None,
989 useflags: Union[Iterable[str], str] = None) -> bool:
Alex Kleinda39c6d2019-09-16 14:36:36 -0600990 """Check if a prebuilt exists.
991
992 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700993 atom: The package whose prebuilt is being queried.
994 build_target: The build target whose sysroot should be searched, or the
995 SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700996 useflags: Any additional USE flags that should be set. May be a string
997 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700998
999 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001000 True if there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -06001001 """
1002 assert atom
1003
1004 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -07001005 extra_env = None
1006 if useflags:
1007 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -05001008 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -07001009 new_flags = ' '.join(useflags)
1010
1011 existing = os.environ.get('USE', '')
1012 final_flags = '%s %s' % (existing, new_flags)
1013 extra_env = {'USE': final_flags.strip()}
1014 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -06001015
1016
David Burger0f9dd4e2019-10-08 12:33:42 -06001017def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -06001018 """Check if |build_target| builds |atom| (has it in its depgraph)."""
1019 cros_build_lib.AssertInsideChroot()
1020
Alex Kleind8cd4c62020-09-14 13:37:47 -06001021 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -06001022 # TODO(crbug/1081828): Receive and use sysroot.
1023 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -06001024 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -06001025 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001026
1027
Alex Klein6becabc2020-09-11 14:03:05 -06001028def needs_chrome_source(
1029 build_target: 'build_target_lib.BuildTarget',
1030 compile_source=False,
1031 packages: Optional[List[package_info.PackageInfo]] = None,
1032 useflags=None):
1033 """Check if the chrome source is needed.
1034
1035 The chrome source is needed if the build target builds chrome or any of its
1036 follower packages, and can't use a prebuilt for them either because it's not
1037 available, or because we can't use prebuilts because it must build from
1038 source.
1039 """
1040 cros_build_lib.AssertInsideChroot()
1041
1042 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -07001043 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -06001044 builds_chrome = constants.CHROME_CP in graph
1045 builds_follower = {
1046 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
1047 }
1048
Alex Klein9ce3f682021-06-23 15:06:44 -06001049 local_uprev = builds_chrome and revbump_chrome([build_target])
1050
Alex Klein6becabc2020-09-11 14:03:05 -06001051 # When we are compiling source set False since we do not use prebuilts.
1052 # When not compiling from source, start with True, i.e. we have every prebuilt
1053 # we've checked for up to this point.
1054 has_chrome_prebuilt = not compile_source
1055 has_follower_prebuilts = not compile_source
1056 # Save packages that need prebuilts for reporting.
1057 pkgs_needing_prebuilts = []
1058 if compile_source:
1059 # Need everything.
1060 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1061 pkgs_needing_prebuilts.extend(
1062 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
1063 else:
1064 # Check chrome itself.
1065 if builds_chrome:
1066 has_chrome_prebuilt = has_prebuilt(
1067 constants.CHROME_CP, build_target=build_target, useflags=useflags)
1068 if not has_chrome_prebuilt:
1069 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1070 # Check follower packages.
1071 for pkg, builds_pkg in builds_follower.items():
1072 if not builds_pkg:
1073 continue
1074 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
1075 has_follower_prebuilts &= prebuilt
1076 if not prebuilt:
1077 pkgs_needing_prebuilts.append(pkg)
1078 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
1079 # reflect whether we actually have the corresponding prebuilts for the build.
1080
1081 needs_chrome = builds_chrome and not has_chrome_prebuilt
1082 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
1083
1084 return NeedsChromeSourceResult(
Sergey Frolov26ff97b2021-08-14 00:02:11 +00001085 needs_chrome_source=needs_chrome or needs_follower,
Alex Klein6becabc2020-09-11 14:03:05 -06001086 builds_chrome=builds_chrome,
1087 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
1088 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -06001089 missing_follower_prebuilt=not has_follower_prebuilts,
1090 local_uprev=local_uprev,
1091 )
Alex Klein6becabc2020-09-11 14:03:05 -06001092
1093
Alex Klein68a28712021-11-08 11:08:30 -07001094class TargetVersions(NamedTuple):
1095 """Data class for the info that makes up the "target versions"."""
1096 android_version: str
1097 android_branch: str
1098 android_target: str
1099 chrome_version: str
1100 platform_version: str
1101 milestone_version: str
1102 full_version: str
1103
1104
1105def get_target_versions(
1106 build_target: 'build_target_lib.BuildTarget',
1107 packages: List[package_info.PackageInfo] = None
1108) -> TargetVersions:
1109 """Aggregate version info for a few key packages and the OS as a whole."""
1110 # Android version.
1111 android_version = determine_android_version(build_target.name)
1112 logging.info('Found android version: %s', android_version)
1113 # Android branch version.
1114 android_branch = determine_android_branch(build_target.name)
1115 logging.info('Found android branch version: %s', android_branch)
1116 # Android target version.
1117 android_target = determine_android_target(build_target.name)
1118 logging.info('Found android target version: %s', android_target)
1119
1120 # TODO(crbug/1019770): Investigate cases where builds_chrome is true but
1121 # chrome_version is None.
1122
1123 builds_chrome = builds(constants.CHROME_CP, build_target, packages=packages)
1124 chrome_version = None
1125 if builds_chrome:
1126 # Chrome version fetch.
1127 chrome_version = determine_chrome_version(build_target)
1128 logging.info('Found chrome version: %s', chrome_version)
1129
1130 # The ChromeOS version info.
1131 platform_version = determine_platform_version()
1132 milestone_version = determine_milestone_version()
1133 full_version = determine_full_version()
1134
1135 return TargetVersions(android_version, android_branch, android_target,
1136 chrome_version, platform_version, milestone_version,
1137 full_version)
1138
1139
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001140def determine_chrome_version(
1141 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenc2615b72019-10-15 08:12:24 -06001142 """Returns the current Chrome version for the board (or in buildroot).
1143
1144 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001145 build_target: The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001146
1147 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001148 The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -06001149 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001150 # TODO(crbug/1019770): Long term we should not need the try/catch here once
1151 # the builds function above only returns True for chrome when
1152 # determine_chrome_version will succeed.
1153 try:
Alex Klein5caab872021-09-10 11:44:37 -06001154 pkg_info = portage_util.PortageqBestVisible(
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001155 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001156 except cros_build_lib.RunCommandError as e:
1157 # Return None because portage failed when trying to determine the chrome
1158 # version.
1159 logging.warning('Caught exception in determine_chrome_package: %s', e)
1160 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -06001161 # Something like 78.0.3877.4_rc -> 78.0.3877.4
Alex Klein5caab872021-09-10 11:44:37 -06001162 return pkg_info.version.partition('_')[0]
Michael Mortensenc2615b72019-10-15 08:12:24 -06001163
1164
Alex Klein68a28712021-11-08 11:08:30 -07001165@functools.lru_cache()
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001166def determine_android_package(board: str) -> Optional[str]:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001167 """Returns the active Android container package in use by the board.
1168
1169 Args:
1170 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001171
1172 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001173 The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001174 """
Michael Mortensene0f4b542019-10-24 15:30:23 -06001175 try:
Mike Frysingerdfa223c2022-04-27 11:02:27 -04001176 packages = portage_util.GetPackageDependencies(
1177 'virtual/target-os', board=board)
Michael Mortensene0f4b542019-10-24 15:30:23 -06001178 except cros_build_lib.RunCommandError as e:
1179 # Return None because a command (likely portage) failed when trying to
1180 # determine the package.
1181 logging.warning('Caught exception in determine_android_package: %s', e)
1182 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001183
Alex Kleinad6b48a2020-01-08 16:57:41 -07001184 # We assume there is only one Android package in the depgraph.
1185 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -04001186 if (package.startswith('chromeos-base/android-container-') or
1187 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -07001188 return package
1189 return None
1190
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001191
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001192def determine_android_version(board: str, package: str = None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001193 """Determine the current Android version in buildroot now and return it.
1194
1195 This uses the typical portage logic to determine which version of Android
1196 is active right now in the buildroot.
1197
1198 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001199 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001200 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001201
1202 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001203 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001204
1205 Raises:
1206 NoAndroidVersionError: if no unique Android version can be determined.
1207 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001208 if not package:
1209 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -05001210 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001211 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -05001212 cpv = package_info.SplitCPV(package)
1213 if not cpv:
1214 raise NoAndroidVersionError(
1215 'Android version could not be determined for %s' % board)
1216 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001217
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001218
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001219def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001220 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001221 if not package:
1222 package = determine_android_package(board)
1223 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001224 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001225 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001226 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +09001227 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +09001228 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001229 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
1230 for target in targets:
1231 if target in ebuild_content:
1232 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
1233 if branch is not None:
1234 return branch.group(1)
1235 raise NoAndroidBranchError(
1236 'Android branch could not be determined for %s (ebuild empty?)' % board)
1237
1238
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001239def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -06001240 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001241 if not package:
1242 package = determine_android_package(board)
1243 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001244 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001245 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001246 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001247 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001248 return 'cheets'
1249
1250 raise NoAndroidTargetError(
1251 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001252 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001253
1254
1255def determine_platform_version():
1256 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001257 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001258 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1259 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001260
1261
1262def determine_milestone_version():
1263 """Returns the platform version from the source root."""
1264 # Milestone version is something like '79'.
1265 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1266 return version.chrome_branch
1267
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001268
Michael Mortensen009cb662019-10-21 11:38:43 -06001269def determine_full_version():
1270 """Returns the full version from the source root."""
1271 # Full version is something like 'R79-12575.0.0'.
1272 milestone_version = determine_milestone_version()
1273 platform_version = determine_platform_version()
1274 full_version = ('R%s-%s' % (milestone_version, platform_version))
1275 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001276
1277
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001278def find_fingerprints(
1279 build_target: 'build_target_lib.BuildTarget') -> List[str]:
Michael Mortensende716a12020-05-15 11:27:00 -06001280 """Returns a list of fingerprints for this build.
1281
1282 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001283 build_target: The build target.
Michael Mortensende716a12020-05-15 11:27:00 -06001284
1285 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001286 List of fingerprint strings.
Michael Mortensende716a12020-05-15 11:27:00 -06001287 """
1288 cros_build_lib.AssertInsideChroot()
1289 fp_file = 'cheets-fingerprint.txt'
1290 fp_path = os.path.join(
1291 image_lib.GetLatestImageLink(build_target.name),
1292 fp_file)
1293 if not os.path.isfile(fp_path):
1294 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001295 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001296 logging.info('Reading fingerprint file: %s', fp_path)
1297 fingerprints = osutils.ReadFile(fp_path).splitlines()
1298 return fingerprints
1299
1300
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001301def get_all_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen59e30872020-05-18 14:12:49 -06001302 """Extract firmware version for all models present.
1303
1304 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001305 build_target: The build target.
Michael Mortensen59e30872020-05-18 14:12:49 -06001306
1307 Returns:
1308 A dict of FirmwareVersions namedtuple instances by model.
1309 Each element will be populated based on whether it was present in the
1310 command output.
1311 """
1312 cros_build_lib.AssertInsideChroot()
1313 result = {}
1314 # Note that example output for _get_firmware_version_cmd_result is available
1315 # in the packages_unittest.py for testing get_all_firmware_versions.
1316 cmd_result = _get_firmware_version_cmd_result(build_target)
1317
Benjamin Shai12c767e2022-01-12 15:17:44 +00001318 if cmd_result:
1319 # There is a blank line between the version info for each model.
1320 firmware_version_payloads = cmd_result.split('\n\n')
1321 for firmware_version_payload in firmware_version_payloads:
1322 if 'BIOS' in firmware_version_payload:
1323 firmware_version = _find_firmware_versions(firmware_version_payload)
1324 result[firmware_version.model] = firmware_version
Michael Mortensen59e30872020-05-18 14:12:49 -06001325 return result
1326
1327
Benjamin Shai0858cd32022-01-10 20:23:49 +00001328class FirmwareVersions(NamedTuple):
1329 """Tuple to hold firmware versions, with truthiness."""
1330 model: Optional[str]
1331 main: Optional[str]
1332 main_rw: Optional[str]
1333 ec: Optional[str]
1334 ec_rw: Optional[str]
1335
1336 def __bool__(self):
1337 return bool(
1338 self.model or self.main or self.main_rw or self.ec or self.ec_rw)
Michael Mortensen71ef5682020-05-07 14:29:24 -06001339
1340
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001341def get_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen71ef5682020-05-07 14:29:24 -06001342 """Extract version information from the firmware updater, if one exists.
1343
1344 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001345 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001346
1347 Returns:
1348 A FirmwareVersions namedtuple instance.
1349 Each element will either be set to the string output by the firmware
1350 updater shellball, or None if there is no firmware updater.
1351 """
1352 cros_build_lib.AssertInsideChroot()
1353 cmd_result = _get_firmware_version_cmd_result(build_target)
1354 if cmd_result:
1355 return _find_firmware_versions(cmd_result)
1356 else:
1357 return FirmwareVersions(None, None, None, None, None)
1358
1359
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001360def _get_firmware_version_cmd_result(
Alex Klein89b58732021-12-23 10:16:03 -07001361 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensen71ef5682020-05-07 14:29:24 -06001362 """Gets the raw result output of the firmware updater version command.
1363
1364 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001365 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001366
1367 Returns:
1368 Command execution result.
1369 """
1370 updater = os.path.join(build_target.root,
1371 'usr/sbin/chromeos-firmwareupdate')
1372 logging.info('Calling updater %s', updater)
1373 # Call the updater using the chroot-based path.
Alex Klein89b58732021-12-23 10:16:03 -07001374 try:
1375 return cros_build_lib.run([updater, '-V'],
1376 capture_output=True, log_output=True,
1377 encoding='utf-8').stdout
1378 except cros_build_lib.RunCommandError:
1379 # Updater probably doesn't exist (e.g. betty).
1380 return None
Michael Mortensen71ef5682020-05-07 14:29:24 -06001381
1382
1383def _find_firmware_versions(cmd_output):
1384 """Finds firmware version output via regex matches against the cmd_output.
1385
1386 Args:
1387 cmd_output: The raw output to search against.
1388
1389 Returns:
1390 FirmwareVersions namedtuple with results.
1391 Each element will either be set to the string output by the firmware
1392 updater shellball, or None if there is no match.
1393 """
1394
1395 # Sometimes a firmware bundle includes a special combination of RO+RW
1396 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1397 # version" field. In other cases, the "(RW) version" field is not present.
1398 # Therefore, search for the "(RW)" fields first and if they aren't present,
1399 # fallback to the other format. e.g. just "BIOS version:".
1400 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1401 main = None
1402 main_rw = None
1403 ec = None
1404 ec_rw = None
1405 model = None
1406
1407 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1408 if match:
1409 main = match.group('version')
1410
1411 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1412 if match:
1413 main_rw = match.group('version')
1414
1415 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1416 if match:
1417 ec = match.group('version')
1418
1419 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1420 if match:
1421 ec_rw = match.group('version')
1422
1423 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1424 if match:
1425 model = match.group('model')
1426
1427 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001428
1429
Benjamin Shai0858cd32022-01-10 20:23:49 +00001430class MainEcFirmwareVersions(NamedTuple):
1431 """Tuple to hold main and ec firmware versions, with truthiness."""
1432 main_fw_version: Optional[str]
1433 ec_fw_version: Optional[str]
1434
1435 def __bool__(self):
1436 return bool(self.main_fw_version or self.ec_fw_version)
1437
Michael Mortensena4af79e2020-05-06 16:18:48 -06001438
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001439def determine_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensena4af79e2020-05-06 16:18:48 -06001440 """Returns a namedtuple with main and ec firmware versions.
1441
1442 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001443 build_target: The build target.
Michael Mortensena4af79e2020-05-06 16:18:48 -06001444
1445 Returns:
1446 MainEcFirmwareVersions namedtuple with results.
1447 """
1448 fw_versions = get_firmware_versions(build_target)
1449 main_fw_version = fw_versions.main_rw or fw_versions.main
1450 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1451
1452 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001453
Benjamin Shai0858cd32022-01-10 20:23:49 +00001454
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001455def determine_kernel_version(
1456 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001457 """Returns a string containing the kernel version for this build target.
1458
1459 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001460 build_target: The build target.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001461
1462 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001463 The kernel versions, or None.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001464 """
1465 try:
Mike Frysingerdfa223c2022-04-27 11:02:27 -04001466 packages = portage_util.GetPackageDependencies(
1467 'virtual/linux-sources', board=build_target.name)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001468 except cros_build_lib.RunCommandError as e:
1469 logging.warning('Unable to get package list for metadata: %s', e)
1470 return None
1471 for package in packages:
1472 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001473 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001474 logging.info('Found active kernel version: %s', kernel_version)
1475 return kernel_version
1476 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001477
1478
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001479def get_models(
1480 build_target: 'build_target_lib.BuildTarget',
1481 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001482 """Obtain a list of models supported by a unified board.
1483
1484 This ignored whitelabel models since GoldenEye has no specific support for
1485 these at present.
1486
1487 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001488 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001489 log_output: Whether to log the output of the cros_config_host invocation.
1490
1491 Returns:
1492 A list of models supported by this board, if it is a unified build; None,
1493 if it is not a unified build.
1494 """
1495 return _run_cros_config_host(build_target, ['list-models'],
1496 log_output=log_output)
1497
1498
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001499def get_key_id(
1500 build_target: 'build_target_lib.BuildTarget',
1501 model: str) -> Optional[str]:
Michael Mortensen359c1f32020-05-28 19:35:42 -06001502 """Obtain the key_id for a model within the build_target.
1503
1504 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001505 build_target: The build target.
1506 model: The model name
Michael Mortensen359c1f32020-05-28 19:35:42 -06001507
1508 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001509 A key_id or None.
Michael Mortensen359c1f32020-05-28 19:35:42 -06001510 """
1511 model_arg = '--model=' + model
1512 key_id_list = _run_cros_config_host(
1513 build_target,
1514 [model_arg, 'get', '/firmware-signing', 'key-id'])
1515 key_id = None
1516 if len(key_id_list) == 1:
1517 key_id = key_id_list[0]
1518 return key_id
1519
1520
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001521def _run_cros_config_host(
1522 build_target: 'build_target_lib.BuildTarget',
1523 args: List[str],
1524 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001525 """Run the cros_config_host tool.
1526
1527 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001528 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001529 args: List of arguments to pass.
1530 log_output: Whether to log the output of the cros_config_host.
1531
1532 Returns:
1533 Output of the tool
1534 """
1535 cros_build_lib.AssertInsideChroot()
1536 tool = '/usr/bin/cros_config_host'
1537 if not os.path.isfile(tool):
1538 return None
1539
1540 config_fname = build_target.full_path(
1541 'usr/share/chromeos-config/yaml/config.yaml')
1542
1543 result = cros_build_lib.run(
1544 [tool, '-c', config_fname] + args,
1545 capture_output=True,
1546 encoding='utf-8',
1547 log_output=log_output,
1548 check=False)
1549 if result.returncode:
1550 # Show the output for debugging purposes.
1551 if 'No such file or directory' not in result.error:
1552 logging.error('cros_config_host failed: %s\n', result.error)
1553 return None
1554 return result.output.strip().splitlines()