blob: 71ccaea1d1250ec5841e89d417f98275d99f2289 [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Package utility functionality."""
6
Yaakov Shaul730814a2019-09-10 13:58:25 -06007import collections
Ben Reiche779cf42020-12-15 03:21:31 +00008from distutils.version import LooseVersion
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -06009import fileinput
Alex Klein87531182019-08-12 15:23:37 -060010import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060011import json
Chris McDonaldf7c03d42021-07-21 11:54:26 -060012import logging
Evan Hernandezb51f1522019-08-15 11:29:40 -060013import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060014import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060015import sys
Alex Klein68a28712021-11-08 11:08:30 -070016from typing import Iterable, List, NamedTuple, Optional, TYPE_CHECKING, Union
Alex Klein87531182019-08-12 15:23:37 -060017
Mike Frysinger2c024062021-05-22 15:43:22 -040018from chromite.third_party.google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060019
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060021from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060022from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060023from chromite.lib import cros_build_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060025from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060026from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070028from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060029from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060030from chromite.lib.parser import package_info
Shao-Chuan Lee05e51142021-11-24 12:27:37 +090031from chromite.service import android
Alex Kleineb77ffa2019-05-28 14:47:44 -060032
Alex Klein5caab872021-09-10 11:44:37 -060033if TYPE_CHECKING:
34 from chromite.lib import build_target_lib
Alex Klein16ea1b32021-10-01 15:48:50 -060035 from chromite.lib import chroot_lib
Chris McDonaldf7c03d42021-07-21 11:54:26 -060036
Alex Klein36b117f2019-09-30 15:13:46 -060037if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060038 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060039 from chromite.service import dependency
40
Alex Klein87531182019-08-12 15:23:37 -060041# Registered handlers for uprevving versioned packages.
42_UPREV_FUNCS = {}
43
Alex Kleineb77ffa2019-05-28 14:47:44 -060044
45class Error(Exception):
46 """Module's base error class."""
47
48
Alex Klein4de25e82019-08-05 15:58:39 -060049class UnknownPackageError(Error):
50 """Uprev attempted for a package without a registered handler."""
51
52
Alex Kleineb77ffa2019-05-28 14:47:44 -060053class UprevError(Error):
54 """An error occurred while uprevving packages."""
55
56
Michael Mortensenb70e8a82019-10-10 18:43:41 -060057class NoAndroidVersionError(Error):
58 """An error occurred while trying to determine the android version."""
59
60
61class NoAndroidBranchError(Error):
62 """An error occurred while trying to determine the android branch."""
63
64
65class NoAndroidTargetError(Error):
66 """An error occurred while trying to determine the android target."""
67
68
Alex Klein4de25e82019-08-05 15:58:39 -060069class AndroidIsPinnedUprevError(UprevError):
70 """Raised when we try to uprev while Android is pinned."""
71
72 def __init__(self, new_android_atom):
73 """Initialize a AndroidIsPinnedUprevError.
74
75 Args:
76 new_android_atom: The Android atom that we failed to
77 uprev to, due to Android being pinned.
78 """
79 assert new_android_atom
80 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
81 new_android_atom)
Jae Hoon Kimad176b82021-07-26 19:29:29 +000082 super().__init__(msg)
Alex Klein4de25e82019-08-05 15:58:39 -060083 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060084
85
Andrew Lamb9563a152019-12-04 11:42:18 -070086class GeneratedCrosConfigFilesError(Error):
87 """Error when cros_config_schema does not produce expected files"""
88
89 def __init__(self, expected_files, found_files):
90 msg = ('Expected to find generated C files: %s. Actually found: %s' %
91 (expected_files, found_files))
Jae Hoon Kimad176b82021-07-26 19:29:29 +000092 super().__init__(msg)
Andrew Lamb9563a152019-12-04 11:42:18 -070093
Alex Klein7a3a7dd2020-01-08 16:44:38 -070094
Alex Klein6becabc2020-09-11 14:03:05 -060095NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
96 'needs_chrome_source',
97 'builds_chrome',
98 'packages',
99 'missing_chrome_prebuilt',
100 'missing_follower_prebuilt',
Alex Klein9ce3f682021-06-23 15:06:44 -0600101 'local_uprev',
Alex Klein6becabc2020-09-11 14:03:05 -0600102))
103
104
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600105def patch_ebuild_vars(ebuild_path, variables):
106 """Updates variables in ebuild.
107
108 Use this function rather than portage_util.EBuild.UpdateEBuild when you
109 want to preserve the variable position and quotes within the ebuild.
110
111 Args:
112 ebuild_path: The path of the ebuild.
113 variables: Dictionary of variables to update in ebuild.
114 """
115 try:
116 for line in fileinput.input(ebuild_path, inplace=1):
117 varname, eq, _ = line.partition('=')
118 if eq == '=' and varname.strip() in variables:
119 value = variables[varname]
120 sys.stdout.write('%s="%s"\n' % (varname, value))
121 else:
122 sys.stdout.write(line)
123 finally:
124 fileinput.close()
125
126
Alex Klein87531182019-08-12 15:23:37 -0600127def uprevs_versioned_package(package):
128 """Decorator to register package uprev handlers."""
129 assert package
130
131 def register(func):
132 """Registers |func| as a handler for |package|."""
133 _UPREV_FUNCS[package] = func
134
135 @functools.wraps(func)
136 def pass_through(*args, **kwargs):
137 return func(*args, **kwargs)
138
139 return pass_through
140
141 return register
142
143
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900144class UprevAndroidResult(NamedTuple):
145 """Results of an Android uprev."""
146 revved: bool
147 android_atom: str = None
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900148 modified_files: List[str] = None
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900149
150
151def uprev_android(
152 android_package: str,
153 chroot: 'chroot_lib.Chroot',
154 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
155 android_build_branch: Optional[str] = None,
156 android_version: Optional[str] = None,
157 skip_commit: bool = False) -> UprevAndroidResult:
158 """Performs an Android uprev by calling cros_mark_android_as_stable.
159
160 Args:
161 android_package: The Android package to uprev.
162 chroot: The chroot to enter.
163 build_targets: List of build targets to cleanup after uprev.
164 android_build_branch: Override the default Android branch corresponding to
165 the package.
166 android_version: Uprev to the particular version. By default the latest
167 available version is used.
168 skip_commit: Whether to skip committing the change after a successful uprev.
169
170 Returns:
171 The uprev result containing:
172 revved: Whether an uprev happened.
173 android_atom: If revved, the portage atom for the revved Android ebuild.
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900174 modified_files: If revved, list of files being modified.
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900175 """
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700176 command = [
177 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900178 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700179 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600180 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900181 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900182 if android_build_branch:
183 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600184 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900185 command.append(f'--force_version={android_version}')
186 if skip_commit:
187 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600188
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700189 result = cros_build_lib.run(
190 command,
191 stdout=True,
192 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500193 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700194 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600195
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900196 output = result.stdout.strip()
197 if not output:
Alex Klein4de25e82019-08-05 15:58:39 -0600198 logging.info('Found nothing to rev.')
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900199 return UprevAndroidResult(revved=False)
200
201 output = json.loads(output)
202 android_atom = output['android_atom']
Alex Klein4de25e82019-08-05 15:58:39 -0600203
204 for target in build_targets or []:
205 # Sanity check: We should always be able to merge the version of
206 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900207 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600208 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700209 cros_build_lib.run(
210 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600211 except cros_build_lib.RunCommandError:
212 logging.error(
213 'Cannot emerge-%s =%s\nIs Android pinned to an older '
214 'version?', target, android_atom)
215 raise AndroidIsPinnedUprevError(android_atom)
216
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900217 return UprevAndroidResult(revved=True,
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900218 android_atom=android_atom,
219 modified_files=output['modified_files'])
220
221
222def uprev_android_lkgb(android_package: str,
223 build_targets: List['build_target_lib.BuildTarget'],
224 chroot: 'chroot_lib.Chroot'
225 ) -> uprev_lib.UprevVersionedPackageResult:
226 """Uprevs an Android package to the version specified in the LKGB file.
227
228 This is the PUpr handler for Android packages, triggered whenever the
229 corresponding LKGB file is being updated.
230
231 PUpr for Android does not test the uprev change in CQ; instead we run separate
232 jobs to test new Android versions, and we write the latest vetted version to
233 the LKGB file. Find the design at go/android-uprev-recipes.
234
235 Args:
236 android_package: The Android package to uprev.
237 build_targets: List of build targets to cleanup after uprev.
238 chroot: The chroot to enter.
239
240 Returns:
241 An uprev_lib.UprevVersionedPackageResult containing the new version and a
242 list of modified files.
243 """
244 android_package_dir = os.path.join(constants.SOURCE_ROOT, 'src',
245 'private-overlays',
246 'project-cheets-private', 'chromeos-base',
247 android_package)
248 android_version = android.ReadLKGB(android_package_dir)
249
250 result = uprev_lib.UprevVersionedPackageResult()
251 uprev_result = uprev_android(android_package, chroot,
252 build_targets=build_targets,
253 android_version=android_version,
254 skip_commit=True)
255 if not uprev_result.revved:
256 return result
257
258 result.add_result(android_version, uprev_result.modified_files)
259 return result
260
261
262def define_uprev_android_lkgb_handlers():
263 """Dynamically define uprev handlers for each Android package"""
264
265 def define_handler(android_package):
266 """Defines the uprev handler for an Android package."""
267 full_package_name = 'chromeos-base/' + android_package
268
269 @uprevs_versioned_package(full_package_name)
270 def _handler(build_targets, _refs, chroot):
271 return uprev_android_lkgb(android_package, build_targets, chroot)
272
273 for android_package in constants.ANDROID_ALL_PACKAGES:
274 define_handler(android_package)
275
276
277define_uprev_android_lkgb_handlers()
Alex Klein4de25e82019-08-05 15:58:39 -0600278
279
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700280def uprev_build_targets(
281 build_targets: Optional[List['build_target_lib.BuildTarget']],
282 overlay_type: str,
283 chroot: 'chroot_lib.Chroot' = None,
284 output_dir: Optional[str] = None):
Alex Kleineb77ffa2019-05-28 14:47:44 -0600285 """Uprev the set provided build targets, or all if not specified.
286
287 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700288 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600289 whose overlays should be uprevved, empty or None for all.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700290 overlay_type: One of the valid overlay types except None (see
Alex Kleineb77ffa2019-05-28 14:47:44 -0600291 constants.VALID_OVERLAYS).
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700292 chroot: The chroot to clean, if desired.
293 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600294 """
295 # Need a valid overlay, but exclude None.
296 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
297
298 if build_targets:
299 overlays = portage_util.FindOverlaysForBoards(
300 overlay_type, boards=[t.name for t in build_targets])
301 else:
302 overlays = portage_util.FindOverlays(overlay_type)
303
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700304 return uprev_overlays(
305 overlays,
306 build_targets=build_targets,
307 chroot=chroot,
308 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600309
310
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700311def uprev_overlays(
312 overlays: List[str],
313 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
314 chroot: Optional['chroot_lib.Chroot'] = None,
315 output_dir: Optional[str] = None) -> List[str]:
Alex Kleineb77ffa2019-05-28 14:47:44 -0600316 """Uprev the given overlays.
317
318 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700319 overlays: The list of overlay paths.
320 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600321 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700322 chroot: The chroot to clean, if desired.
323 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600324
325 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700326 The paths to all of the modified ebuild files. This includes the new files
327 that were added (i.e. the new versions) and all of the removed files
328 (i.e. the old versions).
Alex Kleineb77ffa2019-05-28 14:47:44 -0600329 """
330 assert overlays
331
332 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
333
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700334 uprev_manager = uprev_lib.UprevOverlayManager(
335 overlays,
336 manifest,
337 build_targets=build_targets,
338 chroot=chroot,
339 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600340 uprev_manager.uprev()
341
Dhanya Ganeshd03a4162021-08-25 00:21:50 +0000342 return uprev_manager.modified_ebuilds, uprev_manager.revved_packages
Alex Kleineb77ffa2019-05-28 14:47:44 -0600343
344
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700345def uprev_versioned_package(
346 package: package_info.CPV,
347 build_targets: List['build_target_lib.BuildTarget'],
348 refs: List[uprev_lib.GitRef],
349 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
Alex Klein87531182019-08-12 15:23:37 -0600350 """Call registered uprev handler function for the package.
351
352 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700353 package: The package being uprevved.
354 build_targets: The build targets to clean on a successful uprev.
355 refs:
356 chroot: The chroot to enter for cleaning.
Alex Klein87531182019-08-12 15:23:37 -0600357
358 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700359 The result.
Alex Klein87531182019-08-12 15:23:37 -0600360 """
361 assert package
362
363 if package.cp not in _UPREV_FUNCS:
364 raise UnknownPackageError(
365 'Package "%s" does not have a registered handler.' % package.cp)
366
Andrew Lambea9a8a22019-12-12 14:03:43 -0700367 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600368
369
Navil Perezf57ba872020-06-04 22:38:37 +0000370@uprevs_versioned_package('media-libs/virglrenderer')
371def uprev_virglrenderer(_build_targets, refs, _chroot):
372 """Updates virglrenderer ebuilds.
373
374 See: uprev_versioned_package.
375
376 Returns:
377 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
378 """
Navil Perezf57ba872020-06-04 22:38:37 +0000379 overlay = os.path.join(constants.SOURCE_ROOT,
380 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600381 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
382 'virglrenderer')
383 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000384
385 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
386 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000387 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
388 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000389 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
390
George Engelbrechte73f2782020-06-10 14:10:46 -0600391 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600392 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000393 result.add_result(refs[0].revision, updated_files)
394 return result
395
Jose Magana03b5a842020-08-19 12:52:59 +1000396@uprevs_versioned_package('chromeos-base/drivefs')
397def uprev_drivefs(_build_targets, refs, chroot):
398 """Updates drivefs ebuilds.
399
Harvey Yang3eee06c2021-03-18 15:47:56 +0800400 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000401 See: uprev_versioned_package.
402
403 Returns:
404 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
405 """
406
Ben Reiche779cf42020-12-15 03:21:31 +0000407 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000408 result = uprev_lib.UprevVersionedPackageResult()
409 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000410
Harvey Yang3eee06c2021-03-18 15:47:56 +0800411 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
412 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000413 if not drivefs_version:
414 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000415 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000416
Ben Reiche779cf42020-12-15 03:21:31 +0000417 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000418
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000419 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000420 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000421 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000422 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800423 chroot,
424 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000425
426 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000427 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000428 all_changed_files.extend(uprev_result.changed_files)
429
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000430 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000431 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000432 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000433 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800434 chroot,
435 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000436
437 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000438 logging.warning(
439 'drivefs package has changed files %s but drivefs-ipc does not',
440 all_changed_files)
441 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000442
443 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000444 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000445
446 return result
447
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800448@uprevs_versioned_package('chromeos-base/perfetto')
449def uprev_perfetto(_build_targets, refs, chroot):
450 """Updates Perfetto ebuilds.
451
Harvey Yang3eee06c2021-03-18 15:47:56 +0800452 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800453 See: uprev_versioned_package.
454
455 Returns:
456 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
457 """
458 result = uprev_lib.UprevVersionedPackageResult()
459
Harvey Yang3eee06c2021-03-18 15:47:56 +0800460 PERFETTO_REFS_PREFIX = 'refs/tags/v'
461 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800462 if not perfetto_version:
463 # No valid Perfetto version is identified.
464 return result
465
466 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
467
468 # Attempt to uprev perfetto package.
469 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
470
Harvey Yang3eee06c2021-03-18 15:47:56 +0800471 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
472 PERFETTO_PATH,
473 perfetto_version,
474 chroot,
475 allow_downrev=False,
476 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800477
478 if not uprev_result:
479 return result
480
481 result.add_result(perfetto_version, uprev_result.changed_files)
482
483 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000484
Yaakov Shaul395ae832019-09-09 14:45:32 -0600485@uprevs_versioned_package('afdo/kernel-profiles')
486def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600487 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600488
489 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600490
491 Raises:
492 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600493 """
494 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
495 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
496
David Burger92485342019-09-10 17:52:45 -0600497 with open(path, 'r') as f:
498 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600499
Chris McDonald38409112020-09-24 11:24:51 -0600500 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600501 for kernel_pkg, version_info in versions.items():
502 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
503 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600504 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600505 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600506 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600507 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600508 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600509 patch_ebuild_vars(ebuild_path,
510 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600511
512 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600513 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400514 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600515 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600516 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600517 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600518 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600519
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600520 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600521
Yaakov Shaul730814a2019-09-10 13:58:25 -0600522 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
523
524 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600525
526
Trent Begineb624182020-07-14 10:09:45 -0600527@uprevs_versioned_package('chromeos-base/termina-dlc')
528def uprev_termina_dlc(_build_targets, _refs, chroot):
529 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600530
531 See: uprev_versioned_package.
532 """
Trent Begineb624182020-07-14 10:09:45 -0600533 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600534 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
535 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000536
537 version_pin_src_path = _get_version_pin_src_path(package_path)
538 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
539
Chris McDonald38409112020-09-24 11:24:51 -0600540 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000541
542
Julio Hurtadof1befec2021-05-05 21:34:26 +0000543@uprevs_versioned_package('chromeos-base/chromeos-lacros')
544def uprev_lacros(_build_targets, refs, chroot):
545 """Updates lacros ebuilds.
546
Julio Hurtadoa994e002021-07-07 17:57:45 +0000547 Version to uprev to is gathered from the QA qualified version tracking file
548 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
549 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000550
551 See: uprev_versioned_package.
552 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000553 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000554 path = os.path.join(
Dennis Kempin257b74c2021-09-28 14:38:17 -0700555 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000556 lacros_version = refs[0].revision
557 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
558 lacros_version,
559 chroot,
560 allow_downrev=False)
561
562 if not uprev_result:
563 return result
564
565 result.add_result(lacros_version, uprev_result.changed_files)
566 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000567
568
Patrick Meiring5897add2020-09-16 16:30:17 +1000569@uprevs_versioned_package('app-emulation/parallels-desktop')
570def uprev_parallels_desktop(_build_targets, _refs, chroot):
571 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
572
573 See: uprev_versioned_package
574
575 Returns:
576 UprevVersionedPackageResult: The result.
577 """
578 package = 'parallels-desktop'
579 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
580 'app-emulation', package)
581 version_pin_src_path = _get_version_pin_src_path(package_path)
582
583 # Expect a JSON blob like the following:
584 # {
585 # "version": "1.2.3",
586 # "test_image": { "url": "...", "size": 12345678,
587 # "sha256sum": "<32 bytes of hexadecimal>" }
588 # }
589 with open(version_pin_src_path, 'r') as f:
590 pinned = json.load(f)
591
592 if 'version' not in pinned or 'test_image' not in pinned:
593 raise UprevError('VERSION-PIN for %s missing version and/or '
594 'test_image field' % package)
595
596 version = pinned['version']
597 if not isinstance(version, str):
598 raise UprevError('version in VERSION-PIN for %s not a string' % package)
599
600 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600601 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000602
603 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100604 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
605 'local/bundles/crosint/pita/data/'
606 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000607 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
608 with open(test_image_src_path, 'w') as f:
609 json.dump(pinned['test_image'], f, indent=2)
610 result.add_result(version, [test_image_src_path])
611
612 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600613
614
Trent Begin315d9d92019-12-03 21:55:53 -0700615@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600616def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700617 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
618
619 See: uprev_versioned_package.
620 """
621 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700622 package_path = os.path.join('src', 'private-overlays',
623 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000624 version_pin_src_path = _get_version_pin_src_path(package_path)
625 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700626
Chris McDonald38409112020-09-24 11:24:51 -0600627 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700628
629
David Riley8513c1f2021-10-14 17:07:41 -0700630@uprevs_versioned_package('chromeos-base/borealis-dlc')
631def uprev_borealis_dlc(_build_targets, _refs, chroot):
632 """Updates shared borealis-dlc ebuild - chromeos-base/borealis-dlc.
633
634 See: uprev_versioned_package.
635 """
636 package_path = os.path.join('src', 'private-overlays', 'chromeos-overlay',
637 'chromeos-base', 'borealis-dlc')
638
639 version_pin_src_path = _get_version_pin_src_path(package_path)
640 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
641
642 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
643
644
Patrick Meiring5897add2020-09-16 16:30:17 +1000645def _get_version_pin_src_path(package_path):
646 """Returns the path to the VERSION-PIN file for the given package."""
647 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
648
649
Alex Klein87531182019-08-12 15:23:37 -0600650@uprevs_versioned_package(constants.CHROME_CP)
Alex Kleinf69bd802021-06-22 15:43:49 -0600651def uprev_chrome_from_ref(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600652 """Uprev chrome and its related packages.
653
654 See: uprev_versioned_package.
655 """
656 # Determine the version from the refs (tags), i.e. the chrome versions are the
657 # tag names.
658 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600659 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600660
Alex Klein16ea1b32021-10-01 15:48:50 -0600661 return uprev_chrome(chrome_version, build_targets, chroot)
Alex Kleinf69bd802021-06-22 15:43:49 -0600662
663
Alex Klein9ce3f682021-06-23 15:06:44 -0600664def revbump_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600665 build_targets: List['build_target_lib.BuildTarget'] = None,
Alex Klein9ce3f682021-06-23 15:06:44 -0600666 chroot: Optional['chroot_lib.Chroot'] = None
667) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600668 """Attempt to revbump chrome.
669
670 Revbumps are done by executing an uprev using the current stable version.
671 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
672 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
673 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
674 """
675 chrome_version = uprev_lib.get_stable_chrome_version()
Alex Klein16ea1b32021-10-01 15:48:50 -0600676 return uprev_chrome(chrome_version, build_targets, chroot)
Alex Kleinf69bd802021-06-22 15:43:49 -0600677
678
Alex Klein9ce3f682021-06-23 15:06:44 -0600679def uprev_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600680 chrome_version: str,
681 build_targets: Optional[List['build_target_lib.BuildTarget']],
682 chroot: Optional['chroot_lib.Chroot']
Alex Klein9ce3f682021-06-23 15:06:44 -0600683) -> uprev_lib.UprevVersionedPackageResult:
684 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600685 uprev_manager = uprev_lib.UprevChromeManager(
686 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600687 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600688 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
689 # attempt. The expected behavior is documented in the following table:
690 #
691 # Outcome of Chrome uprev attempt:
692 # NEWER_VERSION_EXISTS:
693 # Do nothing.
694 # SAME_VERSION_EXISTS or REVISION_BUMP:
695 # Uprev followers
696 # Assert not VERSION_BUMP (any other outcome is fine)
697 # VERSION_BUMP or NEW_EBUILD_CREATED:
698 # Uprev followers
699 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600700
701 # Start with chrome itself so we can proceed accordingly.
702 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
703 if chrome_result.newer_version_exists:
704 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600705 return result
Alex Klein87531182019-08-12 15:23:37 -0600706
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600707 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600708 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600709 follower_result = uprev_manager.uprev(package)
710 if chrome_result.stable_version and follower_result.version_bump:
711 logging.warning('%s had a version bump, but no more than a revision bump '
712 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600713
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600714 if uprev_manager.modified_ebuilds:
715 # Record changes when we have them.
716 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
717
718 return result
Alex Klein87531182019-08-12 15:23:37 -0600719
720
Harvey Yang3eee06c2021-03-18 15:47:56 +0800721def _get_latest_version_from_refs(refs_prefix: str,
722 refs: List[uprev_lib.GitRef]) -> str:
723 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000724
Ben Reiche779cf42020-12-15 03:21:31 +0000725 Versions are compared using |distutils.version.LooseVersion| and
726 the latest version is returned.
727
728 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800729 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800730 refs: The tags to parse for the latest Perfetto version.
731
732 Returns:
733 The latest Perfetto version to use.
734 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800735 valid_refs = []
736 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800737 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800738 valid_refs.append(gitiles.ref)
739
740 if not valid_refs:
741 return None
742
743 # Sort by version and take the latest version.
744 target_version_ref = sorted(valid_refs,
745 key=LooseVersion,
746 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800747 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800748
749
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700750def _generate_platform_c_files(
751 replication_config: replication_config_pb2.ReplicationConfig,
752 chroot: 'chroot_lib.Chroot') -> List[str]:
Andrew Lamb9563a152019-12-04 11:42:18 -0700753 """Generates platform C files from a platform JSON payload.
754
755 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700756 replication_config: A ReplicationConfig that has already been run. If it
757 produced a build_config.json file, that file will be used to generate
758 platform C files. Otherwise, nothing will be generated.
759 chroot: The chroot to use to generate.
Andrew Lamb9563a152019-12-04 11:42:18 -0700760
761 Returns:
762 A list of generated files.
763 """
764 # Generate the platform C files from the build config. Note that it would be
765 # more intuitive to generate the platform C files from the platform config;
766 # however, cros_config_schema does not allow this, because the platform config
767 # payload is not always valid input. For example, if a property is both
768 # 'required' and 'build-only', it will fail schema validation. Thus, use the
769 # build config, and use '-f' to filter.
770 build_config_path = [
771 rule.destination_path
772 for rule in replication_config.file_replication_rules
773 if rule.destination_path.endswith('build_config.json')
774 ]
775
776 if not build_config_path:
777 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700778 'No build_config.json found, will not generate platform C files. '
779 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700780 return []
781
782 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700783 raise ValueError('Expected at most one build_config.json destination path. '
784 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700785
786 build_config_path = build_config_path[0]
787
788 # Paths to the build_config.json and dir to output C files to, in the
789 # chroot.
790 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
791 build_config_path)
792 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
793 os.path.dirname(build_config_path))
794
795 command = [
796 'cros_config_schema', '-m', build_config_chroot_path, '-g',
797 generated_output_chroot_dir, '-f', '"TRUE"'
798 ]
799
800 cros_build_lib.run(
801 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
802
803 # A relative (to the source root) path to the generated C files.
804 generated_output_dir = os.path.dirname(build_config_path)
805 generated_files = []
806 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
807 for f in expected_c_files:
808 if os.path.exists(
809 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
810 generated_files.append(os.path.join(generated_output_dir, f))
811
812 if len(expected_c_files) != len(generated_files):
813 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
814
815 return generated_files
816
817
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700818def _get_private_overlay_package_root(ref: uprev_lib.GitRef, package: str):
Andrew Lambe836f222019-12-09 12:27:38 -0700819 """Returns the absolute path to the root of a given private overlay.
820
821 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700822 ref: GitRef for the private overlay.
823 package: Path to the package in the overlay.
Andrew Lambe836f222019-12-09 12:27:38 -0700824 """
825 # There might be a cleaner way to map from package -> path within the source
826 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700827 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700828 match = re.match(private_overlay_ref_pattern, ref.path)
829 if not match:
830 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
831 (private_overlay_ref_pattern, ref))
832
833 overlay = match.group(1)
834
835 return os.path.join(constants.SOURCE_ROOT,
836 'src/private-overlays/overlay-%s-private' % overlay,
837 package)
838
839
Andrew Lambea9a8a22019-12-12 14:03:43 -0700840@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
841def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700842 """Replicate a private cros_config change to the corresponding public config.
843
Alex Kleinad6b48a2020-01-08 16:57:41 -0700844 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700845 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700846 package = 'chromeos-base/chromeos-config-bsp'
847
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700848 if len(refs) != 1:
849 raise ValueError('Expected exactly one ref, actual %s' % refs)
850
851 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700852 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700853 replication_config_path = os.path.join(package_root,
854 'replication_config.jsonpb')
855
856 try:
857 replication_config = json_format.Parse(
858 osutils.ReadFile(replication_config_path),
859 replication_config_pb2.ReplicationConfig())
860 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700861 raise ValueError(
862 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700863
864 replication_lib.Replicate(replication_config)
865
866 modified_files = [
867 rule.destination_path
868 for rule in replication_config.file_replication_rules
869 ]
870
Andrew Lamb9563a152019-12-04 11:42:18 -0700871 # The generated platform C files are not easily filtered by replication rules,
872 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
873 # files cannot. Therefore, replicate and filter the JSON payloads, and then
874 # generate filtered C files from the JSON payload.
875 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700876
877 # Use the private repo's commit hash as the new version.
878 new_private_version = refs[0].revision
879
Andrew Lamb988f4da2019-12-10 10:16:43 -0700880 # modified_files should contain only relative paths at this point, but the
881 # returned UprevVersionedPackageResult must contain only absolute paths.
882 for i, modified_file in enumerate(modified_files):
883 assert not os.path.isabs(modified_file)
884 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
885
Chris McDonald38409112020-09-24 11:24:51 -0600886 return uprev_lib.UprevVersionedPackageResult().add_result(
887 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700888
889
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700890@uprevs_versioned_package('chromeos-base/crosvm')
891def uprev_crosvm(_build_targets, refs, _chroot):
892 """Updates crosvm ebuilds to latest revision
893
894 crosvm is not versioned. We are updating to the latest commit on the main
895 branch.
896
897 See: uprev_versioned_package.
898
899 Returns:
900 UprevVersionedPackageResult: The result of updating crosvm ebuilds.
901 """
902 overlay = os.path.join(constants.SOURCE_ROOT,
903 constants.CHROMIUMOS_OVERLAY_DIR)
904 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'crosvm')
905 manifest = git.ManifestCheckout.Cached(repo_path)
906
907 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
Dennis Kempin257b74c2021-09-28 14:38:17 -0700908 uprev_manager.uprev(
909 package_list=[
910 'chromeos-base/crosvm',
911 'dev-rust/assertions',
912 'dev-rust/cros_async',
913 'dev-rust/cros_fuzz',
914 'dev-rust/data_model',
915 'dev-rust/enumn',
916 'dev-rust/io_uring',
917 'dev-rust/p9',
918 'dev-rust/sync',
919 'dev-rust/sys_util',
920 'dev-rust/tempfile',
921 'media-sound/audio_streams',
922 ],
923 force=True
924 )
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700925
926 updated_files = uprev_manager.modified_ebuilds
927 result = uprev_lib.UprevVersionedPackageResult()
928 result.add_result(refs[0].revision, updated_files)
929 return result
930
931
Alex Klein5caab872021-09-10 11:44:37 -0600932def get_best_visible(
933 atom: str,
934 build_target: Optional['build_target_lib.BuildTarget'] = None
935) -> package_info.PackageInfo:
Alex Kleinbbef2b32019-08-27 10:38:50 -0600936 """Returns the best visible CPV for the given atom.
937
938 Args:
Alex Klein5caab872021-09-10 11:44:37 -0600939 atom: The atom to look up.
940 build_target: The build target whose sysroot should be searched, or the SDK
941 if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700942
943 Returns:
Alex Klein5caab872021-09-10 11:44:37 -0600944 The best visible package, or None if none are visible.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600945 """
David Burger1e0fe232019-07-01 14:52:07 -0600946 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600947
Alex Klein5caab872021-09-10 11:44:37 -0600948 return portage_util.PortageqBestVisible(
949 atom,
950 board=build_target.name if build_target else None,
951 sysroot=build_target.root if build_target else None)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600952
953
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700954def has_prebuilt(
955 atom: str,
956 build_target: 'build_target_lib.BuildTarget' = None,
957 useflags: Union[Iterable[str], str] = None) -> bool:
Alex Kleinda39c6d2019-09-16 14:36:36 -0600958 """Check if a prebuilt exists.
959
960 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700961 atom: The package whose prebuilt is being queried.
962 build_target: The build target whose sysroot should be searched, or the
963 SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700964 useflags: Any additional USE flags that should be set. May be a string
965 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700966
967 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700968 True if there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600969 """
970 assert atom
971
972 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700973 extra_env = None
974 if useflags:
975 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500976 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700977 new_flags = ' '.join(useflags)
978
979 existing = os.environ.get('USE', '')
980 final_flags = '%s %s' % (existing, new_flags)
981 extra_env = {'USE': final_flags.strip()}
982 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600983
984
David Burger0f9dd4e2019-10-08 12:33:42 -0600985def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600986 """Check if |build_target| builds |atom| (has it in its depgraph)."""
987 cros_build_lib.AssertInsideChroot()
988
Alex Kleind8cd4c62020-09-14 13:37:47 -0600989 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600990 # TODO(crbug/1081828): Receive and use sysroot.
991 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600992 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600993 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600994
995
Alex Klein6becabc2020-09-11 14:03:05 -0600996def needs_chrome_source(
997 build_target: 'build_target_lib.BuildTarget',
998 compile_source=False,
999 packages: Optional[List[package_info.PackageInfo]] = None,
1000 useflags=None):
1001 """Check if the chrome source is needed.
1002
1003 The chrome source is needed if the build target builds chrome or any of its
1004 follower packages, and can't use a prebuilt for them either because it's not
1005 available, or because we can't use prebuilts because it must build from
1006 source.
1007 """
1008 cros_build_lib.AssertInsideChroot()
1009
1010 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -07001011 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -06001012 builds_chrome = constants.CHROME_CP in graph
1013 builds_follower = {
1014 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
1015 }
1016
Alex Klein9ce3f682021-06-23 15:06:44 -06001017 local_uprev = builds_chrome and revbump_chrome([build_target])
1018
Alex Klein6becabc2020-09-11 14:03:05 -06001019 # When we are compiling source set False since we do not use prebuilts.
1020 # When not compiling from source, start with True, i.e. we have every prebuilt
1021 # we've checked for up to this point.
1022 has_chrome_prebuilt = not compile_source
1023 has_follower_prebuilts = not compile_source
1024 # Save packages that need prebuilts for reporting.
1025 pkgs_needing_prebuilts = []
1026 if compile_source:
1027 # Need everything.
1028 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1029 pkgs_needing_prebuilts.extend(
1030 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
1031 else:
1032 # Check chrome itself.
1033 if builds_chrome:
1034 has_chrome_prebuilt = has_prebuilt(
1035 constants.CHROME_CP, build_target=build_target, useflags=useflags)
1036 if not has_chrome_prebuilt:
1037 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1038 # Check follower packages.
1039 for pkg, builds_pkg in builds_follower.items():
1040 if not builds_pkg:
1041 continue
1042 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
1043 has_follower_prebuilts &= prebuilt
1044 if not prebuilt:
1045 pkgs_needing_prebuilts.append(pkg)
1046 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
1047 # reflect whether we actually have the corresponding prebuilts for the build.
1048
1049 needs_chrome = builds_chrome and not has_chrome_prebuilt
1050 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
1051
1052 return NeedsChromeSourceResult(
Sergey Frolov26ff97b2021-08-14 00:02:11 +00001053 needs_chrome_source=needs_chrome or needs_follower,
Alex Klein6becabc2020-09-11 14:03:05 -06001054 builds_chrome=builds_chrome,
1055 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
1056 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -06001057 missing_follower_prebuilt=not has_follower_prebuilts,
1058 local_uprev=local_uprev,
1059 )
Alex Klein6becabc2020-09-11 14:03:05 -06001060
1061
Alex Klein68a28712021-11-08 11:08:30 -07001062class TargetVersions(NamedTuple):
1063 """Data class for the info that makes up the "target versions"."""
1064 android_version: str
1065 android_branch: str
1066 android_target: str
1067 chrome_version: str
1068 platform_version: str
1069 milestone_version: str
1070 full_version: str
1071
1072
1073def get_target_versions(
1074 build_target: 'build_target_lib.BuildTarget',
1075 packages: List[package_info.PackageInfo] = None
1076) -> TargetVersions:
1077 """Aggregate version info for a few key packages and the OS as a whole."""
1078 # Android version.
1079 android_version = determine_android_version(build_target.name)
1080 logging.info('Found android version: %s', android_version)
1081 # Android branch version.
1082 android_branch = determine_android_branch(build_target.name)
1083 logging.info('Found android branch version: %s', android_branch)
1084 # Android target version.
1085 android_target = determine_android_target(build_target.name)
1086 logging.info('Found android target version: %s', android_target)
1087
1088 # TODO(crbug/1019770): Investigate cases where builds_chrome is true but
1089 # chrome_version is None.
1090
1091 builds_chrome = builds(constants.CHROME_CP, build_target, packages=packages)
1092 chrome_version = None
1093 if builds_chrome:
1094 # Chrome version fetch.
1095 chrome_version = determine_chrome_version(build_target)
1096 logging.info('Found chrome version: %s', chrome_version)
1097
1098 # The ChromeOS version info.
1099 platform_version = determine_platform_version()
1100 milestone_version = determine_milestone_version()
1101 full_version = determine_full_version()
1102
1103 return TargetVersions(android_version, android_branch, android_target,
1104 chrome_version, platform_version, milestone_version,
1105 full_version)
1106
1107
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001108def determine_chrome_version(
1109 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenc2615b72019-10-15 08:12:24 -06001110 """Returns the current Chrome version for the board (or in buildroot).
1111
1112 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001113 build_target: The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001114
1115 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001116 The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -06001117 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001118 # TODO(crbug/1019770): Long term we should not need the try/catch here once
1119 # the builds function above only returns True for chrome when
1120 # determine_chrome_version will succeed.
1121 try:
Alex Klein5caab872021-09-10 11:44:37 -06001122 pkg_info = portage_util.PortageqBestVisible(
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001123 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001124 except cros_build_lib.RunCommandError as e:
1125 # Return None because portage failed when trying to determine the chrome
1126 # version.
1127 logging.warning('Caught exception in determine_chrome_package: %s', e)
1128 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -06001129 # Something like 78.0.3877.4_rc -> 78.0.3877.4
Alex Klein5caab872021-09-10 11:44:37 -06001130 return pkg_info.version.partition('_')[0]
Michael Mortensenc2615b72019-10-15 08:12:24 -06001131
1132
Alex Klein68a28712021-11-08 11:08:30 -07001133@functools.lru_cache()
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001134def determine_android_package(board: str) -> Optional[str]:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001135 """Returns the active Android container package in use by the board.
1136
1137 Args:
1138 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001139
1140 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001141 The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001142 """
Michael Mortensene0f4b542019-10-24 15:30:23 -06001143 try:
1144 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -06001145 except cros_build_lib.RunCommandError as e:
1146 # Return None because a command (likely portage) failed when trying to
1147 # determine the package.
1148 logging.warning('Caught exception in determine_android_package: %s', e)
1149 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001150
Alex Kleinad6b48a2020-01-08 16:57:41 -07001151 # We assume there is only one Android package in the depgraph.
1152 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -04001153 if (package.startswith('chromeos-base/android-container-') or
1154 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -07001155 return package
1156 return None
1157
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001158
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001159def determine_android_version(board: str, package: str = None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001160 """Determine the current Android version in buildroot now and return it.
1161
1162 This uses the typical portage logic to determine which version of Android
1163 is active right now in the buildroot.
1164
1165 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001166 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001167 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001168
1169 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001170 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001171
1172 Raises:
1173 NoAndroidVersionError: if no unique Android version can be determined.
1174 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001175 if not package:
1176 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -05001177 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001178 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -05001179 cpv = package_info.SplitCPV(package)
1180 if not cpv:
1181 raise NoAndroidVersionError(
1182 'Android version could not be determined for %s' % board)
1183 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001184
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001185
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001186def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001187 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001188 if not package:
1189 package = determine_android_package(board)
1190 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001191 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001192 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001193 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +09001194 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +09001195 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001196 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
1197 for target in targets:
1198 if target in ebuild_content:
1199 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
1200 if branch is not None:
1201 return branch.group(1)
1202 raise NoAndroidBranchError(
1203 'Android branch could not be determined for %s (ebuild empty?)' % board)
1204
1205
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001206def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -06001207 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001208 if not package:
1209 package = determine_android_package(board)
1210 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001211 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001212 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001213 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001214 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001215 return 'cheets'
1216
1217 raise NoAndroidTargetError(
1218 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001219 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001220
1221
1222def determine_platform_version():
1223 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001224 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001225 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1226 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001227
1228
1229def determine_milestone_version():
1230 """Returns the platform version from the source root."""
1231 # Milestone version is something like '79'.
1232 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1233 return version.chrome_branch
1234
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001235
Michael Mortensen009cb662019-10-21 11:38:43 -06001236def determine_full_version():
1237 """Returns the full version from the source root."""
1238 # Full version is something like 'R79-12575.0.0'.
1239 milestone_version = determine_milestone_version()
1240 platform_version = determine_platform_version()
1241 full_version = ('R%s-%s' % (milestone_version, platform_version))
1242 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001243
1244
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001245def find_fingerprints(
1246 build_target: 'build_target_lib.BuildTarget') -> List[str]:
Michael Mortensende716a12020-05-15 11:27:00 -06001247 """Returns a list of fingerprints for this build.
1248
1249 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001250 build_target: The build target.
Michael Mortensende716a12020-05-15 11:27:00 -06001251
1252 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001253 List of fingerprint strings.
Michael Mortensende716a12020-05-15 11:27:00 -06001254 """
1255 cros_build_lib.AssertInsideChroot()
1256 fp_file = 'cheets-fingerprint.txt'
1257 fp_path = os.path.join(
1258 image_lib.GetLatestImageLink(build_target.name),
1259 fp_file)
1260 if not os.path.isfile(fp_path):
1261 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001262 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001263 logging.info('Reading fingerprint file: %s', fp_path)
1264 fingerprints = osutils.ReadFile(fp_path).splitlines()
1265 return fingerprints
1266
1267
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001268def get_all_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen59e30872020-05-18 14:12:49 -06001269 """Extract firmware version for all models present.
1270
1271 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001272 build_target: The build target.
Michael Mortensen59e30872020-05-18 14:12:49 -06001273
1274 Returns:
1275 A dict of FirmwareVersions namedtuple instances by model.
1276 Each element will be populated based on whether it was present in the
1277 command output.
1278 """
1279 cros_build_lib.AssertInsideChroot()
1280 result = {}
1281 # Note that example output for _get_firmware_version_cmd_result is available
1282 # in the packages_unittest.py for testing get_all_firmware_versions.
1283 cmd_result = _get_firmware_version_cmd_result(build_target)
1284
1285 # There is a blank line between the version info for each model.
1286 firmware_version_payloads = cmd_result.split('\n\n')
1287 for firmware_version_payload in firmware_version_payloads:
1288 if 'BIOS' in firmware_version_payload:
1289 firmware_version = _find_firmware_versions(firmware_version_payload)
1290 result[firmware_version.model] = firmware_version
1291 return result
1292
1293
Michael Mortensen71ef5682020-05-07 14:29:24 -06001294FirmwareVersions = collections.namedtuple(
1295 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1296
1297
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001298def get_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen71ef5682020-05-07 14:29:24 -06001299 """Extract version information from the firmware updater, if one exists.
1300
1301 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001302 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001303
1304 Returns:
1305 A FirmwareVersions namedtuple instance.
1306 Each element will either be set to the string output by the firmware
1307 updater shellball, or None if there is no firmware updater.
1308 """
1309 cros_build_lib.AssertInsideChroot()
1310 cmd_result = _get_firmware_version_cmd_result(build_target)
1311 if cmd_result:
1312 return _find_firmware_versions(cmd_result)
1313 else:
1314 return FirmwareVersions(None, None, None, None, None)
1315
1316
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001317def _get_firmware_version_cmd_result(
1318 build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen71ef5682020-05-07 14:29:24 -06001319 """Gets the raw result output of the firmware updater version command.
1320
1321 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001322 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001323
1324 Returns:
1325 Command execution result.
1326 """
1327 updater = os.path.join(build_target.root,
1328 'usr/sbin/chromeos-firmwareupdate')
1329 logging.info('Calling updater %s', updater)
1330 # Call the updater using the chroot-based path.
1331 return cros_build_lib.run([updater, '-V'],
1332 capture_output=True, log_output=True,
1333 encoding='utf-8').stdout
1334
1335
1336def _find_firmware_versions(cmd_output):
1337 """Finds firmware version output via regex matches against the cmd_output.
1338
1339 Args:
1340 cmd_output: The raw output to search against.
1341
1342 Returns:
1343 FirmwareVersions namedtuple with results.
1344 Each element will either be set to the string output by the firmware
1345 updater shellball, or None if there is no match.
1346 """
1347
1348 # Sometimes a firmware bundle includes a special combination of RO+RW
1349 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1350 # version" field. In other cases, the "(RW) version" field is not present.
1351 # Therefore, search for the "(RW)" fields first and if they aren't present,
1352 # fallback to the other format. e.g. just "BIOS version:".
1353 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1354 main = None
1355 main_rw = None
1356 ec = None
1357 ec_rw = None
1358 model = None
1359
1360 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1361 if match:
1362 main = match.group('version')
1363
1364 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1365 if match:
1366 main_rw = match.group('version')
1367
1368 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1369 if match:
1370 ec = match.group('version')
1371
1372 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1373 if match:
1374 ec_rw = match.group('version')
1375
1376 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1377 if match:
1378 model = match.group('model')
1379
1380 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001381
1382
1383MainEcFirmwareVersions = collections.namedtuple(
1384 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1385
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001386def determine_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensena4af79e2020-05-06 16:18:48 -06001387 """Returns a namedtuple with main and ec firmware versions.
1388
1389 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001390 build_target: The build target.
Michael Mortensena4af79e2020-05-06 16:18:48 -06001391
1392 Returns:
1393 MainEcFirmwareVersions namedtuple with results.
1394 """
1395 fw_versions = get_firmware_versions(build_target)
1396 main_fw_version = fw_versions.main_rw or fw_versions.main
1397 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1398
1399 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001400
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001401def determine_kernel_version(
1402 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001403 """Returns a string containing the kernel version for this build target.
1404
1405 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001406 build_target: The build target.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001407
1408 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001409 The kernel versions, or None.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001410 """
1411 try:
1412 packages = portage_util.GetPackageDependencies(build_target.name,
1413 'virtual/linux-sources')
1414 except cros_build_lib.RunCommandError as e:
1415 logging.warning('Unable to get package list for metadata: %s', e)
1416 return None
1417 for package in packages:
1418 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001419 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001420 logging.info('Found active kernel version: %s', kernel_version)
1421 return kernel_version
1422 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001423
1424
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001425def get_models(
1426 build_target: 'build_target_lib.BuildTarget',
1427 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001428 """Obtain a list of models supported by a unified board.
1429
1430 This ignored whitelabel models since GoldenEye has no specific support for
1431 these at present.
1432
1433 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001434 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001435 log_output: Whether to log the output of the cros_config_host invocation.
1436
1437 Returns:
1438 A list of models supported by this board, if it is a unified build; None,
1439 if it is not a unified build.
1440 """
1441 return _run_cros_config_host(build_target, ['list-models'],
1442 log_output=log_output)
1443
1444
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001445def get_key_id(
1446 build_target: 'build_target_lib.BuildTarget',
1447 model: str) -> Optional[str]:
Michael Mortensen359c1f32020-05-28 19:35:42 -06001448 """Obtain the key_id for a model within the build_target.
1449
1450 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001451 build_target: The build target.
1452 model: The model name
Michael Mortensen359c1f32020-05-28 19:35:42 -06001453
1454 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001455 A key_id or None.
Michael Mortensen359c1f32020-05-28 19:35:42 -06001456 """
1457 model_arg = '--model=' + model
1458 key_id_list = _run_cros_config_host(
1459 build_target,
1460 [model_arg, 'get', '/firmware-signing', 'key-id'])
1461 key_id = None
1462 if len(key_id_list) == 1:
1463 key_id = key_id_list[0]
1464 return key_id
1465
1466
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001467def _run_cros_config_host(
1468 build_target: 'build_target_lib.BuildTarget',
1469 args: List[str],
1470 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001471 """Run the cros_config_host tool.
1472
1473 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001474 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001475 args: List of arguments to pass.
1476 log_output: Whether to log the output of the cros_config_host.
1477
1478 Returns:
1479 Output of the tool
1480 """
1481 cros_build_lib.AssertInsideChroot()
1482 tool = '/usr/bin/cros_config_host'
1483 if not os.path.isfile(tool):
1484 return None
1485
1486 config_fname = build_target.full_path(
1487 'usr/share/chromeos-config/yaml/config.yaml')
1488
1489 result = cros_build_lib.run(
1490 [tool, '-c', config_fname] + args,
1491 capture_output=True,
1492 encoding='utf-8',
1493 log_output=log_output,
1494 check=False)
1495 if result.returncode:
1496 # Show the output for debugging purposes.
1497 if 'No such file or directory' not in result.error:
1498 logging.error('cros_config_host failed: %s\n', result.error)
1499 return None
1500 return result.output.strip().splitlines()