blob: 76d71eda25e45bf0a367390b11f4159c0eef5247 [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Package utility functionality."""
6
Yaakov Shaul730814a2019-09-10 13:58:25 -06007import collections
Ben Reiche779cf42020-12-15 03:21:31 +00008from distutils.version import LooseVersion
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -06009import fileinput
Alex Klein87531182019-08-12 15:23:37 -060010import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060011import json
Chris McDonaldf7c03d42021-07-21 11:54:26 -060012import logging
Evan Hernandezb51f1522019-08-15 11:29:40 -060013import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060014import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060015import sys
Alex Klein68a28712021-11-08 11:08:30 -070016from typing import Iterable, List, NamedTuple, Optional, TYPE_CHECKING, Union
Alex Klein87531182019-08-12 15:23:37 -060017
Mike Frysinger2c024062021-05-22 15:43:22 -040018from chromite.third_party.google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060019
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060021from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060022from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060023from chromite.lib import cros_build_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060025from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060026from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070028from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060029from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060030from chromite.lib.parser import package_info
Shao-Chuan Lee05e51142021-11-24 12:27:37 +090031from chromite.service import android
Alex Kleineb77ffa2019-05-28 14:47:44 -060032
Alex Klein5caab872021-09-10 11:44:37 -060033if TYPE_CHECKING:
34 from chromite.lib import build_target_lib
Alex Klein16ea1b32021-10-01 15:48:50 -060035 from chromite.lib import chroot_lib
Chris McDonaldf7c03d42021-07-21 11:54:26 -060036
Alex Klein36b117f2019-09-30 15:13:46 -060037if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060038 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060039 from chromite.service import dependency
40
Alex Klein87531182019-08-12 15:23:37 -060041# Registered handlers for uprevving versioned packages.
42_UPREV_FUNCS = {}
43
Alex Kleineb77ffa2019-05-28 14:47:44 -060044
45class Error(Exception):
46 """Module's base error class."""
47
48
Alex Klein4de25e82019-08-05 15:58:39 -060049class UnknownPackageError(Error):
50 """Uprev attempted for a package without a registered handler."""
51
52
Alex Kleineb77ffa2019-05-28 14:47:44 -060053class UprevError(Error):
54 """An error occurred while uprevving packages."""
55
56
Michael Mortensenb70e8a82019-10-10 18:43:41 -060057class NoAndroidVersionError(Error):
58 """An error occurred while trying to determine the android version."""
59
60
61class NoAndroidBranchError(Error):
62 """An error occurred while trying to determine the android branch."""
63
64
65class NoAndroidTargetError(Error):
66 """An error occurred while trying to determine the android target."""
67
68
Alex Klein4de25e82019-08-05 15:58:39 -060069class AndroidIsPinnedUprevError(UprevError):
70 """Raised when we try to uprev while Android is pinned."""
71
72 def __init__(self, new_android_atom):
73 """Initialize a AndroidIsPinnedUprevError.
74
75 Args:
76 new_android_atom: The Android atom that we failed to
77 uprev to, due to Android being pinned.
78 """
79 assert new_android_atom
80 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
81 new_android_atom)
Jae Hoon Kimad176b82021-07-26 19:29:29 +000082 super().__init__(msg)
Alex Klein4de25e82019-08-05 15:58:39 -060083 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060084
85
Andrew Lamb9563a152019-12-04 11:42:18 -070086class GeneratedCrosConfigFilesError(Error):
87 """Error when cros_config_schema does not produce expected files"""
88
89 def __init__(self, expected_files, found_files):
90 msg = ('Expected to find generated C files: %s. Actually found: %s' %
91 (expected_files, found_files))
Jae Hoon Kimad176b82021-07-26 19:29:29 +000092 super().__init__(msg)
Andrew Lamb9563a152019-12-04 11:42:18 -070093
Alex Klein7a3a7dd2020-01-08 16:44:38 -070094
Alex Klein6becabc2020-09-11 14:03:05 -060095NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
96 'needs_chrome_source',
97 'builds_chrome',
98 'packages',
99 'missing_chrome_prebuilt',
100 'missing_follower_prebuilt',
Alex Klein9ce3f682021-06-23 15:06:44 -0600101 'local_uprev',
Alex Klein6becabc2020-09-11 14:03:05 -0600102))
103
104
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600105def patch_ebuild_vars(ebuild_path, variables):
106 """Updates variables in ebuild.
107
108 Use this function rather than portage_util.EBuild.UpdateEBuild when you
109 want to preserve the variable position and quotes within the ebuild.
110
111 Args:
112 ebuild_path: The path of the ebuild.
113 variables: Dictionary of variables to update in ebuild.
114 """
115 try:
116 for line in fileinput.input(ebuild_path, inplace=1):
117 varname, eq, _ = line.partition('=')
118 if eq == '=' and varname.strip() in variables:
119 value = variables[varname]
120 sys.stdout.write('%s="%s"\n' % (varname, value))
121 else:
122 sys.stdout.write(line)
123 finally:
124 fileinput.close()
125
126
Alex Klein87531182019-08-12 15:23:37 -0600127def uprevs_versioned_package(package):
128 """Decorator to register package uprev handlers."""
129 assert package
130
131 def register(func):
132 """Registers |func| as a handler for |package|."""
133 _UPREV_FUNCS[package] = func
134
135 @functools.wraps(func)
136 def pass_through(*args, **kwargs):
137 return func(*args, **kwargs)
138
139 return pass_through
140
141 return register
142
143
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900144class UprevAndroidResult(NamedTuple):
145 """Results of an Android uprev."""
146 revved: bool
147 android_atom: str = None
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900148 modified_files: List[str] = None
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900149
150
151def uprev_android(
152 android_package: str,
153 chroot: 'chroot_lib.Chroot',
154 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
155 android_build_branch: Optional[str] = None,
156 android_version: Optional[str] = None,
157 skip_commit: bool = False) -> UprevAndroidResult:
158 """Performs an Android uprev by calling cros_mark_android_as_stable.
159
160 Args:
161 android_package: The Android package to uprev.
162 chroot: The chroot to enter.
163 build_targets: List of build targets to cleanup after uprev.
164 android_build_branch: Override the default Android branch corresponding to
165 the package.
166 android_version: Uprev to the particular version. By default the latest
167 available version is used.
168 skip_commit: Whether to skip committing the change after a successful uprev.
169
170 Returns:
171 The uprev result containing:
172 revved: Whether an uprev happened.
173 android_atom: If revved, the portage atom for the revved Android ebuild.
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900174 modified_files: If revved, list of files being modified.
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900175 """
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700176 command = [
177 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900178 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700179 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600180 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900181 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900182 if android_build_branch:
183 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600184 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900185 command.append(f'--force_version={android_version}')
186 if skip_commit:
187 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600188
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700189 result = cros_build_lib.run(
190 command,
191 stdout=True,
192 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500193 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700194 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600195
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900196 # cros_mark_android_as_stable prints the uprev result to stdout as JSON in a
197 # single line. We only take the last line from stdout to make sure no junk
198 # output is included (e.g. messages from bashrc scripts that run upon entering
199 # the chroot.)
200 output = json.loads(result.stdout.strip().splitlines()[-1])
201
202 if not output['revved']:
Alex Klein4de25e82019-08-05 15:58:39 -0600203 logging.info('Found nothing to rev.')
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900204 return UprevAndroidResult(revved=False)
205
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900206 android_atom = output['android_atom']
Alex Klein4de25e82019-08-05 15:58:39 -0600207
208 for target in build_targets or []:
209 # Sanity check: We should always be able to merge the version of
210 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900211 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600212 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700213 cros_build_lib.run(
214 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600215 except cros_build_lib.RunCommandError:
216 logging.error(
217 'Cannot emerge-%s =%s\nIs Android pinned to an older '
218 'version?', target, android_atom)
219 raise AndroidIsPinnedUprevError(android_atom)
220
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +0900221 return UprevAndroidResult(revved=True,
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900222 android_atom=android_atom,
223 modified_files=output['modified_files'])
224
225
226def uprev_android_lkgb(android_package: str,
227 build_targets: List['build_target_lib.BuildTarget'],
228 chroot: 'chroot_lib.Chroot'
229 ) -> uprev_lib.UprevVersionedPackageResult:
230 """Uprevs an Android package to the version specified in the LKGB file.
231
232 This is the PUpr handler for Android packages, triggered whenever the
233 corresponding LKGB file is being updated.
234
235 PUpr for Android does not test the uprev change in CQ; instead we run separate
236 jobs to test new Android versions, and we write the latest vetted version to
237 the LKGB file. Find the design at go/android-uprev-recipes.
238
239 Args:
240 android_package: The Android package to uprev.
241 build_targets: List of build targets to cleanup after uprev.
242 chroot: The chroot to enter.
243
244 Returns:
245 An uprev_lib.UprevVersionedPackageResult containing the new version and a
246 list of modified files.
247 """
Shao-Chuan Lee62cfbc72021-11-30 14:15:07 +0900248 overlay_dir = os.path.join(constants.SOURCE_ROOT, 'src', 'private-overlays',
249 'project-cheets-private')
250 android_package_dir = os.path.join(overlay_dir, 'chromeos-base',
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900251 android_package)
252 android_version = android.ReadLKGB(android_package_dir)
253
254 result = uprev_lib.UprevVersionedPackageResult()
255 uprev_result = uprev_android(android_package, chroot,
256 build_targets=build_targets,
257 android_version=android_version,
258 skip_commit=True)
259 if not uprev_result.revved:
260 return result
261
Shao-Chuan Lee62cfbc72021-11-30 14:15:07 +0900262 # cros_mark_android_as_stable returns paths relative to |overlay_dir|.
263 result.add_result(android_version, [os.path.join(overlay_dir, f)
264 for f in uprev_result.modified_files])
Shao-Chuan Lee05e51142021-11-24 12:27:37 +0900265 return result
266
267
268def define_uprev_android_lkgb_handlers():
269 """Dynamically define uprev handlers for each Android package"""
270
271 def define_handler(android_package):
272 """Defines the uprev handler for an Android package."""
273 full_package_name = 'chromeos-base/' + android_package
274
275 @uprevs_versioned_package(full_package_name)
276 def _handler(build_targets, _refs, chroot):
277 return uprev_android_lkgb(android_package, build_targets, chroot)
278
279 for android_package in constants.ANDROID_ALL_PACKAGES:
280 define_handler(android_package)
281
282
283define_uprev_android_lkgb_handlers()
Alex Klein4de25e82019-08-05 15:58:39 -0600284
285
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700286def uprev_build_targets(
287 build_targets: Optional[List['build_target_lib.BuildTarget']],
288 overlay_type: str,
289 chroot: 'chroot_lib.Chroot' = None,
290 output_dir: Optional[str] = None):
Alex Kleineb77ffa2019-05-28 14:47:44 -0600291 """Uprev the set provided build targets, or all if not specified.
292
293 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700294 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600295 whose overlays should be uprevved, empty or None for all.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700296 overlay_type: One of the valid overlay types except None (see
Alex Kleineb77ffa2019-05-28 14:47:44 -0600297 constants.VALID_OVERLAYS).
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700298 chroot: The chroot to clean, if desired.
299 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600300 """
301 # Need a valid overlay, but exclude None.
302 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
303
304 if build_targets:
305 overlays = portage_util.FindOverlaysForBoards(
306 overlay_type, boards=[t.name for t in build_targets])
307 else:
308 overlays = portage_util.FindOverlays(overlay_type)
309
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700310 return uprev_overlays(
311 overlays,
312 build_targets=build_targets,
313 chroot=chroot,
314 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600315
316
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700317def uprev_overlays(
318 overlays: List[str],
319 build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
320 chroot: Optional['chroot_lib.Chroot'] = None,
321 output_dir: Optional[str] = None) -> List[str]:
Alex Kleineb77ffa2019-05-28 14:47:44 -0600322 """Uprev the given overlays.
323
324 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700325 overlays: The list of overlay paths.
326 build_targets: The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600327 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700328 chroot: The chroot to clean, if desired.
329 output_dir: The path to optionally dump result files.
Alex Kleineb77ffa2019-05-28 14:47:44 -0600330
331 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700332 The paths to all of the modified ebuild files. This includes the new files
333 that were added (i.e. the new versions) and all of the removed files
334 (i.e. the old versions).
Alex Kleineb77ffa2019-05-28 14:47:44 -0600335 """
336 assert overlays
337
338 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
339
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700340 uprev_manager = uprev_lib.UprevOverlayManager(
341 overlays,
342 manifest,
343 build_targets=build_targets,
344 chroot=chroot,
345 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600346 uprev_manager.uprev()
347
Dhanya Ganeshd03a4162021-08-25 00:21:50 +0000348 return uprev_manager.modified_ebuilds, uprev_manager.revved_packages
Alex Kleineb77ffa2019-05-28 14:47:44 -0600349
350
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700351def uprev_versioned_package(
352 package: package_info.CPV,
353 build_targets: List['build_target_lib.BuildTarget'],
354 refs: List[uprev_lib.GitRef],
355 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
Alex Klein87531182019-08-12 15:23:37 -0600356 """Call registered uprev handler function for the package.
357
358 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700359 package: The package being uprevved.
360 build_targets: The build targets to clean on a successful uprev.
361 refs:
362 chroot: The chroot to enter for cleaning.
Alex Klein87531182019-08-12 15:23:37 -0600363
364 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700365 The result.
Alex Klein87531182019-08-12 15:23:37 -0600366 """
367 assert package
368
369 if package.cp not in _UPREV_FUNCS:
370 raise UnknownPackageError(
371 'Package "%s" does not have a registered handler.' % package.cp)
372
Andrew Lambea9a8a22019-12-12 14:03:43 -0700373 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600374
375
Navil Perezf57ba872020-06-04 22:38:37 +0000376@uprevs_versioned_package('media-libs/virglrenderer')
377def uprev_virglrenderer(_build_targets, refs, _chroot):
378 """Updates virglrenderer ebuilds.
379
380 See: uprev_versioned_package.
381
382 Returns:
383 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
384 """
Navil Perezf57ba872020-06-04 22:38:37 +0000385 overlay = os.path.join(constants.SOURCE_ROOT,
386 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600387 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
388 'virglrenderer')
389 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000390
391 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
392 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000393 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
394 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000395 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
396
George Engelbrechte73f2782020-06-10 14:10:46 -0600397 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600398 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000399 result.add_result(refs[0].revision, updated_files)
400 return result
401
Jose Magana03b5a842020-08-19 12:52:59 +1000402@uprevs_versioned_package('chromeos-base/drivefs')
403def uprev_drivefs(_build_targets, refs, chroot):
404 """Updates drivefs ebuilds.
405
Harvey Yang3eee06c2021-03-18 15:47:56 +0800406 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000407 See: uprev_versioned_package.
408
409 Returns:
410 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
411 """
412
Ben Reiche779cf42020-12-15 03:21:31 +0000413 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000414 result = uprev_lib.UprevVersionedPackageResult()
415 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000416
Harvey Yang3eee06c2021-03-18 15:47:56 +0800417 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
418 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000419 if not drivefs_version:
420 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000421 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000422
Ben Reiche779cf42020-12-15 03:21:31 +0000423 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000424
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000425 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000426 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000427 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000428 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800429 chroot,
430 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000431
432 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000433 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000434 all_changed_files.extend(uprev_result.changed_files)
435
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000436 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000437 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000438 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000439 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800440 chroot,
441 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000442
443 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000444 logging.warning(
445 'drivefs package has changed files %s but drivefs-ipc does not',
446 all_changed_files)
447 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000448
449 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000450 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000451
452 return result
453
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800454@uprevs_versioned_package('chromeos-base/perfetto')
455def uprev_perfetto(_build_targets, refs, chroot):
456 """Updates Perfetto ebuilds.
457
Harvey Yang3eee06c2021-03-18 15:47:56 +0800458 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800459 See: uprev_versioned_package.
460
461 Returns:
462 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
463 """
464 result = uprev_lib.UprevVersionedPackageResult()
465
Harvey Yang3eee06c2021-03-18 15:47:56 +0800466 PERFETTO_REFS_PREFIX = 'refs/tags/v'
467 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800468 if not perfetto_version:
469 # No valid Perfetto version is identified.
470 return result
471
472 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
473
474 # Attempt to uprev perfetto package.
475 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
476
Harvey Yang3eee06c2021-03-18 15:47:56 +0800477 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
478 PERFETTO_PATH,
479 perfetto_version,
480 chroot,
481 allow_downrev=False,
482 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800483
484 if not uprev_result:
485 return result
486
487 result.add_result(perfetto_version, uprev_result.changed_files)
488
489 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000490
Yaakov Shaul395ae832019-09-09 14:45:32 -0600491@uprevs_versioned_package('afdo/kernel-profiles')
492def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600493 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600494
495 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600496
497 Raises:
498 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600499 """
500 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
501 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
502
David Burger92485342019-09-10 17:52:45 -0600503 with open(path, 'r') as f:
504 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600505
Chris McDonald38409112020-09-24 11:24:51 -0600506 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600507 for kernel_pkg, version_info in versions.items():
508 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
509 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600510 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600511 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600512 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600513 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600514 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600515 patch_ebuild_vars(ebuild_path,
516 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600517
518 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600519 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400520 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600521 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600522 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600523 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600524 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600525
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600526 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600527
Yaakov Shaul730814a2019-09-10 13:58:25 -0600528 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
529
530 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600531
532
Trent Begineb624182020-07-14 10:09:45 -0600533@uprevs_versioned_package('chromeos-base/termina-dlc')
534def uprev_termina_dlc(_build_targets, _refs, chroot):
535 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600536
537 See: uprev_versioned_package.
538 """
Trent Begineb624182020-07-14 10:09:45 -0600539 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600540 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
541 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000542
543 version_pin_src_path = _get_version_pin_src_path(package_path)
544 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
545
Chris McDonald38409112020-09-24 11:24:51 -0600546 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000547
548
Julio Hurtadof1befec2021-05-05 21:34:26 +0000549@uprevs_versioned_package('chromeos-base/chromeos-lacros')
550def uprev_lacros(_build_targets, refs, chroot):
551 """Updates lacros ebuilds.
552
Julio Hurtadoa994e002021-07-07 17:57:45 +0000553 Version to uprev to is gathered from the QA qualified version tracking file
554 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
555 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000556
557 See: uprev_versioned_package.
558 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000559 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000560 path = os.path.join(
Dennis Kempin257b74c2021-09-28 14:38:17 -0700561 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000562 lacros_version = refs[0].revision
563 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
564 lacros_version,
565 chroot,
566 allow_downrev=False)
567
568 if not uprev_result:
569 return result
570
571 result.add_result(lacros_version, uprev_result.changed_files)
572 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000573
574
Julio Hurtado870ed322021-12-03 18:22:40 +0000575@uprevs_versioned_package('chromeos-base/chromeos-lacros-parallel')
576def uprev_lacros_in_parallel(
577 _build_targets: Optional[List['build_target_lib.BuildTarget']],
578 refs: List[uprev_lib.GitRef],
579 chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
580 """Updates lacros ebuilds in parallel with ash-chrome.
581
582 This handler is going to be used temporarily while lacros transitions to being
583 uprevved atomically with ash-chrome. Unlike a standalone lacros uprev, this
584 handler will not need to look at the QA qualified file. Rather, it will
585 function identical to ash-chrome using git tags.
586
587 See: uprev_versioned_package.
588
589 Returns:
590 UprevVersionedPackageResult: The result.
591 """
592 result = uprev_lib.UprevVersionedPackageResult()
593 path = os.path.join(
594 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
595 lacros_version = uprev_lib.get_version_from_refs(refs)
596 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
597 lacros_version,
598 chroot,
599 allow_downrev=False)
600
601 if not uprev_result:
602 return result
603
604 result.add_result(lacros_version, uprev_result.changed_files)
605 return result
606
607
Patrick Meiring5897add2020-09-16 16:30:17 +1000608@uprevs_versioned_package('app-emulation/parallels-desktop')
609def uprev_parallels_desktop(_build_targets, _refs, chroot):
610 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
611
612 See: uprev_versioned_package
613
614 Returns:
615 UprevVersionedPackageResult: The result.
616 """
617 package = 'parallels-desktop'
618 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
619 'app-emulation', package)
620 version_pin_src_path = _get_version_pin_src_path(package_path)
621
622 # Expect a JSON blob like the following:
623 # {
624 # "version": "1.2.3",
625 # "test_image": { "url": "...", "size": 12345678,
626 # "sha256sum": "<32 bytes of hexadecimal>" }
627 # }
628 with open(version_pin_src_path, 'r') as f:
629 pinned = json.load(f)
630
631 if 'version' not in pinned or 'test_image' not in pinned:
632 raise UprevError('VERSION-PIN for %s missing version and/or '
633 'test_image field' % package)
634
635 version = pinned['version']
636 if not isinstance(version, str):
637 raise UprevError('version in VERSION-PIN for %s not a string' % package)
638
639 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600640 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000641
642 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100643 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
644 'local/bundles/crosint/pita/data/'
645 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000646 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
647 with open(test_image_src_path, 'w') as f:
648 json.dump(pinned['test_image'], f, indent=2)
649 result.add_result(version, [test_image_src_path])
650
651 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600652
653
Trent Begin315d9d92019-12-03 21:55:53 -0700654@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600655def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700656 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
657
658 See: uprev_versioned_package.
659 """
660 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700661 package_path = os.path.join('src', 'private-overlays',
662 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000663 version_pin_src_path = _get_version_pin_src_path(package_path)
664 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700665
Chris McDonald38409112020-09-24 11:24:51 -0600666 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700667
668
David Riley8513c1f2021-10-14 17:07:41 -0700669@uprevs_versioned_package('chromeos-base/borealis-dlc')
670def uprev_borealis_dlc(_build_targets, _refs, chroot):
671 """Updates shared borealis-dlc ebuild - chromeos-base/borealis-dlc.
672
673 See: uprev_versioned_package.
674 """
675 package_path = os.path.join('src', 'private-overlays', 'chromeos-overlay',
676 'chromeos-base', 'borealis-dlc')
677
678 version_pin_src_path = _get_version_pin_src_path(package_path)
679 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
680
681 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
682
683
Patrick Meiring5897add2020-09-16 16:30:17 +1000684def _get_version_pin_src_path(package_path):
685 """Returns the path to the VERSION-PIN file for the given package."""
686 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
687
688
Alex Klein87531182019-08-12 15:23:37 -0600689@uprevs_versioned_package(constants.CHROME_CP)
Alex Kleinf69bd802021-06-22 15:43:49 -0600690def uprev_chrome_from_ref(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600691 """Uprev chrome and its related packages.
692
693 See: uprev_versioned_package.
694 """
695 # Determine the version from the refs (tags), i.e. the chrome versions are the
696 # tag names.
Julio Hurtado870ed322021-12-03 18:22:40 +0000697 chrome_version = uprev_lib.get_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600698 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600699
Alex Klein16ea1b32021-10-01 15:48:50 -0600700 return uprev_chrome(chrome_version, build_targets, chroot)
Alex Kleinf69bd802021-06-22 15:43:49 -0600701
702
Alex Klein9ce3f682021-06-23 15:06:44 -0600703def revbump_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600704 build_targets: List['build_target_lib.BuildTarget'] = None,
Alex Klein9ce3f682021-06-23 15:06:44 -0600705 chroot: Optional['chroot_lib.Chroot'] = None
706) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600707 """Attempt to revbump chrome.
708
709 Revbumps are done by executing an uprev using the current stable version.
710 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
711 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
712 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
713 """
714 chrome_version = uprev_lib.get_stable_chrome_version()
Alex Klein16ea1b32021-10-01 15:48:50 -0600715 return uprev_chrome(chrome_version, build_targets, chroot)
Alex Kleinf69bd802021-06-22 15:43:49 -0600716
717
Alex Klein9ce3f682021-06-23 15:06:44 -0600718def uprev_chrome(
Alex Klein16ea1b32021-10-01 15:48:50 -0600719 chrome_version: str,
720 build_targets: Optional[List['build_target_lib.BuildTarget']],
721 chroot: Optional['chroot_lib.Chroot']
Alex Klein9ce3f682021-06-23 15:06:44 -0600722) -> uprev_lib.UprevVersionedPackageResult:
723 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600724 uprev_manager = uprev_lib.UprevChromeManager(
725 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600726 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600727 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
728 # attempt. The expected behavior is documented in the following table:
729 #
730 # Outcome of Chrome uprev attempt:
731 # NEWER_VERSION_EXISTS:
732 # Do nothing.
733 # SAME_VERSION_EXISTS or REVISION_BUMP:
734 # Uprev followers
735 # Assert not VERSION_BUMP (any other outcome is fine)
736 # VERSION_BUMP or NEW_EBUILD_CREATED:
737 # Uprev followers
738 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600739
740 # Start with chrome itself so we can proceed accordingly.
741 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
742 if chrome_result.newer_version_exists:
743 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600744 return result
Alex Klein87531182019-08-12 15:23:37 -0600745
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600746 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600747 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600748 follower_result = uprev_manager.uprev(package)
749 if chrome_result.stable_version and follower_result.version_bump:
750 logging.warning('%s had a version bump, but no more than a revision bump '
751 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600752
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600753 if uprev_manager.modified_ebuilds:
754 # Record changes when we have them.
755 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
756
757 return result
Alex Klein87531182019-08-12 15:23:37 -0600758
759
Harvey Yang3eee06c2021-03-18 15:47:56 +0800760def _get_latest_version_from_refs(refs_prefix: str,
761 refs: List[uprev_lib.GitRef]) -> str:
762 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000763
Ben Reiche779cf42020-12-15 03:21:31 +0000764 Versions are compared using |distutils.version.LooseVersion| and
765 the latest version is returned.
766
767 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800768 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800769 refs: The tags to parse for the latest Perfetto version.
770
771 Returns:
772 The latest Perfetto version to use.
773 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800774 valid_refs = []
775 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800776 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800777 valid_refs.append(gitiles.ref)
778
779 if not valid_refs:
780 return None
781
782 # Sort by version and take the latest version.
783 target_version_ref = sorted(valid_refs,
784 key=LooseVersion,
785 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800786 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800787
788
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700789def _generate_platform_c_files(
790 replication_config: replication_config_pb2.ReplicationConfig,
791 chroot: 'chroot_lib.Chroot') -> List[str]:
Andrew Lamb9563a152019-12-04 11:42:18 -0700792 """Generates platform C files from a platform JSON payload.
793
794 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700795 replication_config: A ReplicationConfig that has already been run. If it
796 produced a build_config.json file, that file will be used to generate
797 platform C files. Otherwise, nothing will be generated.
798 chroot: The chroot to use to generate.
Andrew Lamb9563a152019-12-04 11:42:18 -0700799
800 Returns:
801 A list of generated files.
802 """
803 # Generate the platform C files from the build config. Note that it would be
804 # more intuitive to generate the platform C files from the platform config;
805 # however, cros_config_schema does not allow this, because the platform config
806 # payload is not always valid input. For example, if a property is both
807 # 'required' and 'build-only', it will fail schema validation. Thus, use the
808 # build config, and use '-f' to filter.
809 build_config_path = [
810 rule.destination_path
811 for rule in replication_config.file_replication_rules
812 if rule.destination_path.endswith('build_config.json')
813 ]
814
815 if not build_config_path:
816 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700817 'No build_config.json found, will not generate platform C files. '
818 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700819 return []
820
821 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700822 raise ValueError('Expected at most one build_config.json destination path. '
823 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700824
825 build_config_path = build_config_path[0]
826
827 # Paths to the build_config.json and dir to output C files to, in the
828 # chroot.
829 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
830 build_config_path)
831 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
832 os.path.dirname(build_config_path))
833
834 command = [
835 'cros_config_schema', '-m', build_config_chroot_path, '-g',
836 generated_output_chroot_dir, '-f', '"TRUE"'
837 ]
838
839 cros_build_lib.run(
840 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
841
842 # A relative (to the source root) path to the generated C files.
843 generated_output_dir = os.path.dirname(build_config_path)
844 generated_files = []
845 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
846 for f in expected_c_files:
847 if os.path.exists(
848 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
849 generated_files.append(os.path.join(generated_output_dir, f))
850
851 if len(expected_c_files) != len(generated_files):
852 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
853
854 return generated_files
855
856
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700857def _get_private_overlay_package_root(ref: uprev_lib.GitRef, package: str):
Andrew Lambe836f222019-12-09 12:27:38 -0700858 """Returns the absolute path to the root of a given private overlay.
859
860 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700861 ref: GitRef for the private overlay.
862 package: Path to the package in the overlay.
Andrew Lambe836f222019-12-09 12:27:38 -0700863 """
864 # There might be a cleaner way to map from package -> path within the source
865 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700866 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700867 match = re.match(private_overlay_ref_pattern, ref.path)
868 if not match:
869 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
870 (private_overlay_ref_pattern, ref))
871
872 overlay = match.group(1)
873
874 return os.path.join(constants.SOURCE_ROOT,
875 'src/private-overlays/overlay-%s-private' % overlay,
876 package)
877
878
Andrew Lambea9a8a22019-12-12 14:03:43 -0700879@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
880def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700881 """Replicate a private cros_config change to the corresponding public config.
882
Alex Kleinad6b48a2020-01-08 16:57:41 -0700883 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700884 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700885 package = 'chromeos-base/chromeos-config-bsp'
886
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700887 if len(refs) != 1:
888 raise ValueError('Expected exactly one ref, actual %s' % refs)
889
890 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700891 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700892 replication_config_path = os.path.join(package_root,
893 'replication_config.jsonpb')
894
895 try:
896 replication_config = json_format.Parse(
897 osutils.ReadFile(replication_config_path),
898 replication_config_pb2.ReplicationConfig())
899 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700900 raise ValueError(
901 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700902
903 replication_lib.Replicate(replication_config)
904
905 modified_files = [
906 rule.destination_path
907 for rule in replication_config.file_replication_rules
908 ]
909
Andrew Lamb9563a152019-12-04 11:42:18 -0700910 # The generated platform C files are not easily filtered by replication rules,
911 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
912 # files cannot. Therefore, replicate and filter the JSON payloads, and then
913 # generate filtered C files from the JSON payload.
914 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700915
916 # Use the private repo's commit hash as the new version.
917 new_private_version = refs[0].revision
918
Andrew Lamb988f4da2019-12-10 10:16:43 -0700919 # modified_files should contain only relative paths at this point, but the
920 # returned UprevVersionedPackageResult must contain only absolute paths.
921 for i, modified_file in enumerate(modified_files):
922 assert not os.path.isabs(modified_file)
923 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
924
Chris McDonald38409112020-09-24 11:24:51 -0600925 return uprev_lib.UprevVersionedPackageResult().add_result(
926 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700927
928
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700929@uprevs_versioned_package('chromeos-base/crosvm')
930def uprev_crosvm(_build_targets, refs, _chroot):
931 """Updates crosvm ebuilds to latest revision
932
933 crosvm is not versioned. We are updating to the latest commit on the main
934 branch.
935
936 See: uprev_versioned_package.
937
938 Returns:
939 UprevVersionedPackageResult: The result of updating crosvm ebuilds.
940 """
941 overlay = os.path.join(constants.SOURCE_ROOT,
942 constants.CHROMIUMOS_OVERLAY_DIR)
943 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'crosvm')
944 manifest = git.ManifestCheckout.Cached(repo_path)
945
946 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
Dennis Kempin257b74c2021-09-28 14:38:17 -0700947 uprev_manager.uprev(
948 package_list=[
949 'chromeos-base/crosvm',
950 'dev-rust/assertions',
951 'dev-rust/cros_async',
952 'dev-rust/cros_fuzz',
953 'dev-rust/data_model',
954 'dev-rust/enumn',
955 'dev-rust/io_uring',
956 'dev-rust/p9',
957 'dev-rust/sync',
958 'dev-rust/sys_util',
959 'dev-rust/tempfile',
960 'media-sound/audio_streams',
961 ],
962 force=True
963 )
Dennis Kempinef05f2b2021-09-08 16:36:49 -0700964
965 updated_files = uprev_manager.modified_ebuilds
966 result = uprev_lib.UprevVersionedPackageResult()
967 result.add_result(refs[0].revision, updated_files)
968 return result
969
970
Alex Klein5caab872021-09-10 11:44:37 -0600971def get_best_visible(
972 atom: str,
973 build_target: Optional['build_target_lib.BuildTarget'] = None
974) -> package_info.PackageInfo:
Alex Kleinbbef2b32019-08-27 10:38:50 -0600975 """Returns the best visible CPV for the given atom.
976
977 Args:
Alex Klein5caab872021-09-10 11:44:37 -0600978 atom: The atom to look up.
979 build_target: The build target whose sysroot should be searched, or the SDK
980 if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700981
982 Returns:
Alex Klein5caab872021-09-10 11:44:37 -0600983 The best visible package, or None if none are visible.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600984 """
David Burger1e0fe232019-07-01 14:52:07 -0600985 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600986
Alex Klein5caab872021-09-10 11:44:37 -0600987 return portage_util.PortageqBestVisible(
988 atom,
989 board=build_target.name if build_target else None,
990 sysroot=build_target.root if build_target else None)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600991
992
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -0700993def has_prebuilt(
994 atom: str,
995 build_target: 'build_target_lib.BuildTarget' = None,
996 useflags: Union[Iterable[str], str] = None) -> bool:
Alex Kleinda39c6d2019-09-16 14:36:36 -0600997 """Check if a prebuilt exists.
998
999 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001000 atom: The package whose prebuilt is being queried.
1001 build_target: The build target whose sysroot should be searched, or the
1002 SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -07001003 useflags: Any additional USE flags that should be set. May be a string
1004 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001005
1006 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001007 True if there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -06001008 """
1009 assert atom
1010
1011 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -07001012 extra_env = None
1013 if useflags:
1014 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -05001015 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -07001016 new_flags = ' '.join(useflags)
1017
1018 existing = os.environ.get('USE', '')
1019 final_flags = '%s %s' % (existing, new_flags)
1020 extra_env = {'USE': final_flags.strip()}
1021 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -06001022
1023
David Burger0f9dd4e2019-10-08 12:33:42 -06001024def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -06001025 """Check if |build_target| builds |atom| (has it in its depgraph)."""
1026 cros_build_lib.AssertInsideChroot()
1027
Alex Kleind8cd4c62020-09-14 13:37:47 -06001028 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -06001029 # TODO(crbug/1081828): Receive and use sysroot.
1030 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -06001031 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -06001032 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001033
1034
Alex Klein6becabc2020-09-11 14:03:05 -06001035def needs_chrome_source(
1036 build_target: 'build_target_lib.BuildTarget',
1037 compile_source=False,
1038 packages: Optional[List[package_info.PackageInfo]] = None,
1039 useflags=None):
1040 """Check if the chrome source is needed.
1041
1042 The chrome source is needed if the build target builds chrome or any of its
1043 follower packages, and can't use a prebuilt for them either because it's not
1044 available, or because we can't use prebuilts because it must build from
1045 source.
1046 """
1047 cros_build_lib.AssertInsideChroot()
1048
1049 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -07001050 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -06001051 builds_chrome = constants.CHROME_CP in graph
1052 builds_follower = {
1053 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
1054 }
1055
Alex Klein9ce3f682021-06-23 15:06:44 -06001056 local_uprev = builds_chrome and revbump_chrome([build_target])
1057
Alex Klein6becabc2020-09-11 14:03:05 -06001058 # When we are compiling source set False since we do not use prebuilts.
1059 # When not compiling from source, start with True, i.e. we have every prebuilt
1060 # we've checked for up to this point.
1061 has_chrome_prebuilt = not compile_source
1062 has_follower_prebuilts = not compile_source
1063 # Save packages that need prebuilts for reporting.
1064 pkgs_needing_prebuilts = []
1065 if compile_source:
1066 # Need everything.
1067 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1068 pkgs_needing_prebuilts.extend(
1069 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
1070 else:
1071 # Check chrome itself.
1072 if builds_chrome:
1073 has_chrome_prebuilt = has_prebuilt(
1074 constants.CHROME_CP, build_target=build_target, useflags=useflags)
1075 if not has_chrome_prebuilt:
1076 pkgs_needing_prebuilts.append(constants.CHROME_CP)
1077 # Check follower packages.
1078 for pkg, builds_pkg in builds_follower.items():
1079 if not builds_pkg:
1080 continue
1081 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
1082 has_follower_prebuilts &= prebuilt
1083 if not prebuilt:
1084 pkgs_needing_prebuilts.append(pkg)
1085 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
1086 # reflect whether we actually have the corresponding prebuilts for the build.
1087
1088 needs_chrome = builds_chrome and not has_chrome_prebuilt
1089 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
1090
1091 return NeedsChromeSourceResult(
Sergey Frolov26ff97b2021-08-14 00:02:11 +00001092 needs_chrome_source=needs_chrome or needs_follower,
Alex Klein6becabc2020-09-11 14:03:05 -06001093 builds_chrome=builds_chrome,
1094 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
1095 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -06001096 missing_follower_prebuilt=not has_follower_prebuilts,
1097 local_uprev=local_uprev,
1098 )
Alex Klein6becabc2020-09-11 14:03:05 -06001099
1100
Alex Klein68a28712021-11-08 11:08:30 -07001101class TargetVersions(NamedTuple):
1102 """Data class for the info that makes up the "target versions"."""
1103 android_version: str
1104 android_branch: str
1105 android_target: str
1106 chrome_version: str
1107 platform_version: str
1108 milestone_version: str
1109 full_version: str
1110
1111
1112def get_target_versions(
1113 build_target: 'build_target_lib.BuildTarget',
1114 packages: List[package_info.PackageInfo] = None
1115) -> TargetVersions:
1116 """Aggregate version info for a few key packages and the OS as a whole."""
1117 # Android version.
1118 android_version = determine_android_version(build_target.name)
1119 logging.info('Found android version: %s', android_version)
1120 # Android branch version.
1121 android_branch = determine_android_branch(build_target.name)
1122 logging.info('Found android branch version: %s', android_branch)
1123 # Android target version.
1124 android_target = determine_android_target(build_target.name)
1125 logging.info('Found android target version: %s', android_target)
1126
1127 # TODO(crbug/1019770): Investigate cases where builds_chrome is true but
1128 # chrome_version is None.
1129
1130 builds_chrome = builds(constants.CHROME_CP, build_target, packages=packages)
1131 chrome_version = None
1132 if builds_chrome:
1133 # Chrome version fetch.
1134 chrome_version = determine_chrome_version(build_target)
1135 logging.info('Found chrome version: %s', chrome_version)
1136
1137 # The ChromeOS version info.
1138 platform_version = determine_platform_version()
1139 milestone_version = determine_milestone_version()
1140 full_version = determine_full_version()
1141
1142 return TargetVersions(android_version, android_branch, android_target,
1143 chrome_version, platform_version, milestone_version,
1144 full_version)
1145
1146
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001147def determine_chrome_version(
1148 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenc2615b72019-10-15 08:12:24 -06001149 """Returns the current Chrome version for the board (or in buildroot).
1150
1151 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001152 build_target: The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001153
1154 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001155 The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -06001156 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001157 # TODO(crbug/1019770): Long term we should not need the try/catch here once
1158 # the builds function above only returns True for chrome when
1159 # determine_chrome_version will succeed.
1160 try:
Alex Klein5caab872021-09-10 11:44:37 -06001161 pkg_info = portage_util.PortageqBestVisible(
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001162 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -06001163 except cros_build_lib.RunCommandError as e:
1164 # Return None because portage failed when trying to determine the chrome
1165 # version.
1166 logging.warning('Caught exception in determine_chrome_package: %s', e)
1167 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -06001168 # Something like 78.0.3877.4_rc -> 78.0.3877.4
Alex Klein5caab872021-09-10 11:44:37 -06001169 return pkg_info.version.partition('_')[0]
Michael Mortensenc2615b72019-10-15 08:12:24 -06001170
1171
Alex Klein68a28712021-11-08 11:08:30 -07001172@functools.lru_cache()
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001173def determine_android_package(board: str) -> Optional[str]:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001174 """Returns the active Android container package in use by the board.
1175
1176 Args:
1177 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -07001178
1179 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001180 The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001181 """
Michael Mortensene0f4b542019-10-24 15:30:23 -06001182 try:
1183 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -06001184 except cros_build_lib.RunCommandError as e:
1185 # Return None because a command (likely portage) failed when trying to
1186 # determine the package.
1187 logging.warning('Caught exception in determine_android_package: %s', e)
1188 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001189
Alex Kleinad6b48a2020-01-08 16:57:41 -07001190 # We assume there is only one Android package in the depgraph.
1191 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -04001192 if (package.startswith('chromeos-base/android-container-') or
1193 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -07001194 return package
1195 return None
1196
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001197
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001198def determine_android_version(board: str, package: str = None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001199 """Determine the current Android version in buildroot now and return it.
1200
1201 This uses the typical portage logic to determine which version of Android
1202 is active right now in the buildroot.
1203
1204 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001205 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001206 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001207
1208 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -05001209 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001210
1211 Raises:
1212 NoAndroidVersionError: if no unique Android version can be determined.
1213 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001214 if not package:
1215 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -05001216 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001217 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -05001218 cpv = package_info.SplitCPV(package)
1219 if not cpv:
1220 raise NoAndroidVersionError(
1221 'Android version could not be determined for %s' % board)
1222 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001223
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001224
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001225def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001226 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001227 if not package:
1228 package = determine_android_package(board)
1229 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001230 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001231 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001232 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +09001233 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +09001234 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001235 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
1236 for target in targets:
1237 if target in ebuild_content:
1238 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
1239 if branch is not None:
1240 return branch.group(1)
1241 raise NoAndroidBranchError(
1242 'Android branch could not be determined for %s (ebuild empty?)' % board)
1243
1244
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001245def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -06001246 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001247 if not package:
1248 package = determine_android_package(board)
1249 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -06001250 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001251 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001252 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001253 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001254 return 'cheets'
1255
1256 raise NoAndroidTargetError(
1257 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001258 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001259
1260
1261def determine_platform_version():
1262 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001263 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001264 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1265 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001266
1267
1268def determine_milestone_version():
1269 """Returns the platform version from the source root."""
1270 # Milestone version is something like '79'.
1271 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1272 return version.chrome_branch
1273
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001274
Michael Mortensen009cb662019-10-21 11:38:43 -06001275def determine_full_version():
1276 """Returns the full version from the source root."""
1277 # Full version is something like 'R79-12575.0.0'.
1278 milestone_version = determine_milestone_version()
1279 platform_version = determine_platform_version()
1280 full_version = ('R%s-%s' % (milestone_version, platform_version))
1281 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001282
1283
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001284def find_fingerprints(
1285 build_target: 'build_target_lib.BuildTarget') -> List[str]:
Michael Mortensende716a12020-05-15 11:27:00 -06001286 """Returns a list of fingerprints for this build.
1287
1288 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001289 build_target: The build target.
Michael Mortensende716a12020-05-15 11:27:00 -06001290
1291 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001292 List of fingerprint strings.
Michael Mortensende716a12020-05-15 11:27:00 -06001293 """
1294 cros_build_lib.AssertInsideChroot()
1295 fp_file = 'cheets-fingerprint.txt'
1296 fp_path = os.path.join(
1297 image_lib.GetLatestImageLink(build_target.name),
1298 fp_file)
1299 if not os.path.isfile(fp_path):
1300 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001301 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001302 logging.info('Reading fingerprint file: %s', fp_path)
1303 fingerprints = osutils.ReadFile(fp_path).splitlines()
1304 return fingerprints
1305
1306
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001307def get_all_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen59e30872020-05-18 14:12:49 -06001308 """Extract firmware version for all models present.
1309
1310 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001311 build_target: The build target.
Michael Mortensen59e30872020-05-18 14:12:49 -06001312
1313 Returns:
1314 A dict of FirmwareVersions namedtuple instances by model.
1315 Each element will be populated based on whether it was present in the
1316 command output.
1317 """
1318 cros_build_lib.AssertInsideChroot()
1319 result = {}
1320 # Note that example output for _get_firmware_version_cmd_result is available
1321 # in the packages_unittest.py for testing get_all_firmware_versions.
1322 cmd_result = _get_firmware_version_cmd_result(build_target)
1323
1324 # There is a blank line between the version info for each model.
1325 firmware_version_payloads = cmd_result.split('\n\n')
1326 for firmware_version_payload in firmware_version_payloads:
1327 if 'BIOS' in firmware_version_payload:
1328 firmware_version = _find_firmware_versions(firmware_version_payload)
1329 result[firmware_version.model] = firmware_version
1330 return result
1331
1332
Michael Mortensen71ef5682020-05-07 14:29:24 -06001333FirmwareVersions = collections.namedtuple(
1334 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1335
1336
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001337def get_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen71ef5682020-05-07 14:29:24 -06001338 """Extract version information from the firmware updater, if one exists.
1339
1340 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001341 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001342
1343 Returns:
1344 A FirmwareVersions namedtuple instance.
1345 Each element will either be set to the string output by the firmware
1346 updater shellball, or None if there is no firmware updater.
1347 """
1348 cros_build_lib.AssertInsideChroot()
1349 cmd_result = _get_firmware_version_cmd_result(build_target)
1350 if cmd_result:
1351 return _find_firmware_versions(cmd_result)
1352 else:
1353 return FirmwareVersions(None, None, None, None, None)
1354
1355
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001356def _get_firmware_version_cmd_result(
1357 build_target: 'build_target_lib.BuildTarget'):
Michael Mortensen71ef5682020-05-07 14:29:24 -06001358 """Gets the raw result output of the firmware updater version command.
1359
1360 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001361 build_target: The build target.
Michael Mortensen71ef5682020-05-07 14:29:24 -06001362
1363 Returns:
1364 Command execution result.
1365 """
1366 updater = os.path.join(build_target.root,
1367 'usr/sbin/chromeos-firmwareupdate')
1368 logging.info('Calling updater %s', updater)
1369 # Call the updater using the chroot-based path.
1370 return cros_build_lib.run([updater, '-V'],
1371 capture_output=True, log_output=True,
1372 encoding='utf-8').stdout
1373
1374
1375def _find_firmware_versions(cmd_output):
1376 """Finds firmware version output via regex matches against the cmd_output.
1377
1378 Args:
1379 cmd_output: The raw output to search against.
1380
1381 Returns:
1382 FirmwareVersions namedtuple with results.
1383 Each element will either be set to the string output by the firmware
1384 updater shellball, or None if there is no match.
1385 """
1386
1387 # Sometimes a firmware bundle includes a special combination of RO+RW
1388 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1389 # version" field. In other cases, the "(RW) version" field is not present.
1390 # Therefore, search for the "(RW)" fields first and if they aren't present,
1391 # fallback to the other format. e.g. just "BIOS version:".
1392 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1393 main = None
1394 main_rw = None
1395 ec = None
1396 ec_rw = None
1397 model = None
1398
1399 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1400 if match:
1401 main = match.group('version')
1402
1403 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1404 if match:
1405 main_rw = match.group('version')
1406
1407 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1408 if match:
1409 ec = match.group('version')
1410
1411 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1412 if match:
1413 ec_rw = match.group('version')
1414
1415 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1416 if match:
1417 model = match.group('model')
1418
1419 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001420
1421
1422MainEcFirmwareVersions = collections.namedtuple(
1423 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1424
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001425def determine_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
Michael Mortensena4af79e2020-05-06 16:18:48 -06001426 """Returns a namedtuple with main and ec firmware versions.
1427
1428 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001429 build_target: The build target.
Michael Mortensena4af79e2020-05-06 16:18:48 -06001430
1431 Returns:
1432 MainEcFirmwareVersions namedtuple with results.
1433 """
1434 fw_versions = get_firmware_versions(build_target)
1435 main_fw_version = fw_versions.main_rw or fw_versions.main
1436 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1437
1438 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001439
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001440def determine_kernel_version(
1441 build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001442 """Returns a string containing the kernel version for this build target.
1443
1444 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001445 build_target: The build target.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001446
1447 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001448 The kernel versions, or None.
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001449 """
1450 try:
1451 packages = portage_util.GetPackageDependencies(build_target.name,
1452 'virtual/linux-sources')
1453 except cros_build_lib.RunCommandError as e:
1454 logging.warning('Unable to get package list for metadata: %s', e)
1455 return None
1456 for package in packages:
1457 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001458 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001459 logging.info('Found active kernel version: %s', kernel_version)
1460 return kernel_version
1461 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001462
1463
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001464def get_models(
1465 build_target: 'build_target_lib.BuildTarget',
1466 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001467 """Obtain a list of models supported by a unified board.
1468
1469 This ignored whitelabel models since GoldenEye has no specific support for
1470 these at present.
1471
1472 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001473 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001474 log_output: Whether to log the output of the cros_config_host invocation.
1475
1476 Returns:
1477 A list of models supported by this board, if it is a unified build; None,
1478 if it is not a unified build.
1479 """
1480 return _run_cros_config_host(build_target, ['list-models'],
1481 log_output=log_output)
1482
1483
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001484def get_key_id(
1485 build_target: 'build_target_lib.BuildTarget',
1486 model: str) -> Optional[str]:
Michael Mortensen359c1f32020-05-28 19:35:42 -06001487 """Obtain the key_id for a model within the build_target.
1488
1489 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001490 build_target: The build target.
1491 model: The model name
Michael Mortensen359c1f32020-05-28 19:35:42 -06001492
1493 Returns:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001494 A key_id or None.
Michael Mortensen359c1f32020-05-28 19:35:42 -06001495 """
1496 model_arg = '--model=' + model
1497 key_id_list = _run_cros_config_host(
1498 build_target,
1499 [model_arg, 'get', '/firmware-signing', 'key-id'])
1500 key_id = None
1501 if len(key_id_list) == 1:
1502 key_id = key_id_list[0]
1503 return key_id
1504
1505
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001506def _run_cros_config_host(
1507 build_target: 'build_target_lib.BuildTarget',
1508 args: List[str],
1509 log_output: bool = True) -> Optional[List[str]]:
Michael Mortensen125bb012020-05-21 14:02:10 -06001510 """Run the cros_config_host tool.
1511
1512 Args:
Matthias Kaehlckebf7d1772021-11-04 16:01:36 -07001513 build_target: The build target.
Michael Mortensen125bb012020-05-21 14:02:10 -06001514 args: List of arguments to pass.
1515 log_output: Whether to log the output of the cros_config_host.
1516
1517 Returns:
1518 Output of the tool
1519 """
1520 cros_build_lib.AssertInsideChroot()
1521 tool = '/usr/bin/cros_config_host'
1522 if not os.path.isfile(tool):
1523 return None
1524
1525 config_fname = build_target.full_path(
1526 'usr/share/chromeos-config/yaml/config.yaml')
1527
1528 result = cros_build_lib.run(
1529 [tool, '-c', config_fname] + args,
1530 capture_output=True,
1531 encoding='utf-8',
1532 log_output=log_output,
1533 check=False)
1534 if result.returncode:
1535 # Show the output for debugging purposes.
1536 if 'No such file or directory' not in result.error:
1537 logging.error('cros_config_host failed: %s\n', result.error)
1538 return None
1539 return result.output.strip().splitlines()