blob: 8ae0240b51248484895b2b55833e1dab3d52aee2 [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
Evan Hernandezb51f1522019-08-15 11:29:40 -060012import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060013import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060014import sys
Alex Klein6becabc2020-09-11 14:03:05 -060015from typing import List, Optional
Alex Klein87531182019-08-12 15:23:37 -060016
Mike Frysinger2c024062021-05-22 15:43:22 -040017from chromite.third_party.google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060018
Andrew Lamb2bde9e42019-11-04 13:24:09 -070019from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060020from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060021from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060022from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060023from chromite.lib import cros_logging as logging
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
Alex Kleineb77ffa2019-05-28 14:47:44 -060031
Alex Klein36b117f2019-09-30 15:13:46 -060032if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060033 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060034 from chromite.service import dependency
35
Alex Klein87531182019-08-12 15:23:37 -060036# Registered handlers for uprevving versioned packages.
37_UPREV_FUNCS = {}
38
Alex Kleineb77ffa2019-05-28 14:47:44 -060039
40class Error(Exception):
41 """Module's base error class."""
42
43
Alex Klein4de25e82019-08-05 15:58:39 -060044class UnknownPackageError(Error):
45 """Uprev attempted for a package without a registered handler."""
46
47
Alex Kleineb77ffa2019-05-28 14:47:44 -060048class UprevError(Error):
49 """An error occurred while uprevving packages."""
50
51
Michael Mortensenb70e8a82019-10-10 18:43:41 -060052class NoAndroidVersionError(Error):
53 """An error occurred while trying to determine the android version."""
54
55
56class NoAndroidBranchError(Error):
57 """An error occurred while trying to determine the android branch."""
58
59
60class NoAndroidTargetError(Error):
61 """An error occurred while trying to determine the android target."""
62
63
Alex Klein4de25e82019-08-05 15:58:39 -060064class AndroidIsPinnedUprevError(UprevError):
65 """Raised when we try to uprev while Android is pinned."""
66
67 def __init__(self, new_android_atom):
68 """Initialize a AndroidIsPinnedUprevError.
69
70 Args:
71 new_android_atom: The Android atom that we failed to
72 uprev to, due to Android being pinned.
73 """
74 assert new_android_atom
75 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
76 new_android_atom)
77 super(AndroidIsPinnedUprevError, self).__init__(msg)
78 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060079
80
Andrew Lamb9563a152019-12-04 11:42:18 -070081class GeneratedCrosConfigFilesError(Error):
82 """Error when cros_config_schema does not produce expected files"""
83
84 def __init__(self, expected_files, found_files):
85 msg = ('Expected to find generated C files: %s. Actually found: %s' %
86 (expected_files, found_files))
87 super(GeneratedCrosConfigFilesError, self).__init__(msg)
88
Alex Klein7a3a7dd2020-01-08 16:44:38 -070089
Alex Klein6becabc2020-09-11 14:03:05 -060090NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
91 'needs_chrome_source',
92 'builds_chrome',
93 'packages',
94 'missing_chrome_prebuilt',
95 'missing_follower_prebuilt',
96))
97
98
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060099def patch_ebuild_vars(ebuild_path, variables):
100 """Updates variables in ebuild.
101
102 Use this function rather than portage_util.EBuild.UpdateEBuild when you
103 want to preserve the variable position and quotes within the ebuild.
104
105 Args:
106 ebuild_path: The path of the ebuild.
107 variables: Dictionary of variables to update in ebuild.
108 """
109 try:
110 for line in fileinput.input(ebuild_path, inplace=1):
111 varname, eq, _ = line.partition('=')
112 if eq == '=' and varname.strip() in variables:
113 value = variables[varname]
114 sys.stdout.write('%s="%s"\n' % (varname, value))
115 else:
116 sys.stdout.write(line)
117 finally:
118 fileinput.close()
119
120
Alex Klein87531182019-08-12 15:23:37 -0600121def uprevs_versioned_package(package):
122 """Decorator to register package uprev handlers."""
123 assert package
124
125 def register(func):
126 """Registers |func| as a handler for |package|."""
127 _UPREV_FUNCS[package] = func
128
129 @functools.wraps(func)
130 def pass_through(*args, **kwargs):
131 return func(*args, **kwargs)
132
133 return pass_through
134
135 return register
136
137
Shao-Chuan Leeb6a2cb62021-02-19 14:18:59 +0900138def uprev_android(android_package,
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700139 chroot,
140 build_targets=None,
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900141 android_build_branch=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900142 android_version=None,
143 skip_commit=False):
Alex Klein4de25e82019-08-05 15:58:39 -0600144 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700145 command = [
146 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900147 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700148 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600149 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900150 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900151 if android_build_branch:
152 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600153 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900154 command.append(f'--force_version={android_version}')
155 if skip_commit:
156 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600157
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700158 result = cros_build_lib.run(
159 command,
160 stdout=True,
161 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500162 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700163 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600164
Mike Frysinger88d96362020-02-14 19:05:45 -0500165 portage_atom_string = result.stdout.strip()
166 android_atom = None
167 if portage_atom_string:
168 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600169 if not android_atom:
170 logging.info('Found nothing to rev.')
171 return None
172
173 for target in build_targets or []:
174 # Sanity check: We should always be able to merge the version of
175 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900176 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600177 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700178 cros_build_lib.run(
179 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600180 except cros_build_lib.RunCommandError:
181 logging.error(
182 'Cannot emerge-%s =%s\nIs Android pinned to an older '
183 'version?', target, android_atom)
184 raise AndroidIsPinnedUprevError(android_atom)
185
186 return android_atom
187
188
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700189def uprev_build_targets(build_targets,
190 overlay_type,
191 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600192 output_dir=None):
193 """Uprev the set provided build targets, or all if not specified.
194
195 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600196 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600197 whose overlays should be uprevved, empty or None for all.
198 overlay_type (str): One of the valid overlay types except None (see
199 constants.VALID_OVERLAYS).
200 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
201 output_dir (str|None): The path to optionally dump result files.
202 """
203 # Need a valid overlay, but exclude None.
204 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
205
206 if build_targets:
207 overlays = portage_util.FindOverlaysForBoards(
208 overlay_type, boards=[t.name for t in build_targets])
209 else:
210 overlays = portage_util.FindOverlays(overlay_type)
211
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700212 return uprev_overlays(
213 overlays,
214 build_targets=build_targets,
215 chroot=chroot,
216 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600217
218
219def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
220 """Uprev the given overlays.
221
222 Args:
223 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600224 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600225 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
226 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
227 output_dir (str|None): The path to optionally dump result files.
228
229 Returns:
230 list[str] - The paths to all of the modified ebuild files. This includes the
231 new files that were added (i.e. the new versions) and all of the removed
232 files (i.e. the old versions).
233 """
234 assert overlays
235
236 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
237
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700238 uprev_manager = uprev_lib.UprevOverlayManager(
239 overlays,
240 manifest,
241 build_targets=build_targets,
242 chroot=chroot,
243 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600244 uprev_manager.uprev()
245
246 return uprev_manager.modified_ebuilds
247
248
Alex Klein87531182019-08-12 15:23:37 -0600249def uprev_versioned_package(package, build_targets, refs, chroot):
250 """Call registered uprev handler function for the package.
251
252 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600253 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600254 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600255 clean on a successful uprev.
256 refs (list[uprev_lib.GitRef]):
257 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
258
259 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600260 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600261 """
262 assert package
263
264 if package.cp not in _UPREV_FUNCS:
265 raise UnknownPackageError(
266 'Package "%s" does not have a registered handler.' % package.cp)
267
Andrew Lambea9a8a22019-12-12 14:03:43 -0700268 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600269
270
Navil Perezf57ba872020-06-04 22:38:37 +0000271@uprevs_versioned_package('media-libs/virglrenderer')
272def uprev_virglrenderer(_build_targets, refs, _chroot):
273 """Updates virglrenderer ebuilds.
274
275 See: uprev_versioned_package.
276
277 Returns:
278 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
279 """
Navil Perezf57ba872020-06-04 22:38:37 +0000280 overlay = os.path.join(constants.SOURCE_ROOT,
281 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600282 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
283 'virglrenderer')
284 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000285
286 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
287 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000288 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
289 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000290 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
291
George Engelbrechte73f2782020-06-10 14:10:46 -0600292 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600293 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000294 result.add_result(refs[0].revision, updated_files)
295 return result
296
Jose Magana03b5a842020-08-19 12:52:59 +1000297@uprevs_versioned_package('chromeos-base/drivefs')
298def uprev_drivefs(_build_targets, refs, chroot):
299 """Updates drivefs ebuilds.
300
Harvey Yang3eee06c2021-03-18 15:47:56 +0800301 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000302 See: uprev_versioned_package.
303
304 Returns:
305 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
306 """
307
Ben Reiche779cf42020-12-15 03:21:31 +0000308 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000309 result = uprev_lib.UprevVersionedPackageResult()
310 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000311
Harvey Yang3eee06c2021-03-18 15:47:56 +0800312 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
313 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000314 if not drivefs_version:
315 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000316 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000317
Ben Reiche779cf42020-12-15 03:21:31 +0000318 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000319
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000320 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000321 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000322 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000323 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800324 chroot,
325 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000326
327 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000328 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000329 all_changed_files.extend(uprev_result.changed_files)
330
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000331 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000332 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000333 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000334 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800335 chroot,
336 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000337
338 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000339 logging.warning(
340 'drivefs package has changed files %s but drivefs-ipc does not',
341 all_changed_files)
342 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000343
344 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000345 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000346
347 return result
348
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800349@uprevs_versioned_package('chromeos-base/perfetto')
350def uprev_perfetto(_build_targets, refs, chroot):
351 """Updates Perfetto ebuilds.
352
Harvey Yang3eee06c2021-03-18 15:47:56 +0800353 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800354 See: uprev_versioned_package.
355
356 Returns:
357 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
358 """
359 result = uprev_lib.UprevVersionedPackageResult()
360
Harvey Yang3eee06c2021-03-18 15:47:56 +0800361 PERFETTO_REFS_PREFIX = 'refs/tags/v'
362 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800363 if not perfetto_version:
364 # No valid Perfetto version is identified.
365 return result
366
367 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
368
369 # Attempt to uprev perfetto package.
370 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
371
Harvey Yang3eee06c2021-03-18 15:47:56 +0800372 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
373 PERFETTO_PATH,
374 perfetto_version,
375 chroot,
376 allow_downrev=False,
377 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800378
379 if not uprev_result:
380 return result
381
382 result.add_result(perfetto_version, uprev_result.changed_files)
383
384 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000385
Yaakov Shaul395ae832019-09-09 14:45:32 -0600386@uprevs_versioned_package('afdo/kernel-profiles')
387def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600388 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600389
390 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600391
392 Raises:
393 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600394 """
395 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
396 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
397
David Burger92485342019-09-10 17:52:45 -0600398 with open(path, 'r') as f:
399 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600400
Chris McDonald38409112020-09-24 11:24:51 -0600401 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600402 for kernel_pkg, version_info in versions.items():
403 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
404 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600405 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600406 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600407 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600408 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600409 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600410 patch_ebuild_vars(ebuild_path,
411 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600412
413 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600414 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400415 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600416 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600417 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600418 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600419 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600420
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600421 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600422
Yaakov Shaul730814a2019-09-10 13:58:25 -0600423 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
424
425 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600426
427
Trent Begineb624182020-07-14 10:09:45 -0600428@uprevs_versioned_package('chromeos-base/termina-dlc')
429def uprev_termina_dlc(_build_targets, _refs, chroot):
430 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600431
432 See: uprev_versioned_package.
433 """
Trent Begineb624182020-07-14 10:09:45 -0600434 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600435 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
436 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000437
438 version_pin_src_path = _get_version_pin_src_path(package_path)
439 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
440
Chris McDonald38409112020-09-24 11:24:51 -0600441 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000442
443
Julio Hurtadof1befec2021-05-05 21:34:26 +0000444@uprevs_versioned_package('chromeos-base/chromeos-lacros')
445def uprev_lacros(_build_targets, refs, chroot):
446 """Updates lacros ebuilds.
447
448 Information used is gathered from the QA qualified version tracking file
449 stored in chromium/src.
450
451 See: uprev_versioned_package.
452 """
453 path = os.path.join(
454 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base','chromeos-lacros')
455 return uprev_lib.uprev_ebuild_from_pin(path, refs[0].revision, chroot)
456
457
Patrick Meiring5897add2020-09-16 16:30:17 +1000458@uprevs_versioned_package('app-emulation/parallels-desktop')
459def uprev_parallels_desktop(_build_targets, _refs, chroot):
460 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
461
462 See: uprev_versioned_package
463
464 Returns:
465 UprevVersionedPackageResult: The result.
466 """
467 package = 'parallels-desktop'
468 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
469 'app-emulation', package)
470 version_pin_src_path = _get_version_pin_src_path(package_path)
471
472 # Expect a JSON blob like the following:
473 # {
474 # "version": "1.2.3",
475 # "test_image": { "url": "...", "size": 12345678,
476 # "sha256sum": "<32 bytes of hexadecimal>" }
477 # }
478 with open(version_pin_src_path, 'r') as f:
479 pinned = json.load(f)
480
481 if 'version' not in pinned or 'test_image' not in pinned:
482 raise UprevError('VERSION-PIN for %s missing version and/or '
483 'test_image field' % package)
484
485 version = pinned['version']
486 if not isinstance(version, str):
487 raise UprevError('version in VERSION-PIN for %s not a string' % package)
488
489 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600490 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000491
492 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100493 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
494 'local/bundles/crosint/pita/data/'
495 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000496 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
497 with open(test_image_src_path, 'w') as f:
498 json.dump(pinned['test_image'], f, indent=2)
499 result.add_result(version, [test_image_src_path])
500
501 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600502
503
Trent Begin315d9d92019-12-03 21:55:53 -0700504@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600505def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700506 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
507
508 See: uprev_versioned_package.
509 """
510 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700511 package_path = os.path.join('src', 'private-overlays',
512 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000513 version_pin_src_path = _get_version_pin_src_path(package_path)
514 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700515
Chris McDonald38409112020-09-24 11:24:51 -0600516 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700517
518
Patrick Meiring5897add2020-09-16 16:30:17 +1000519def _get_version_pin_src_path(package_path):
520 """Returns the path to the VERSION-PIN file for the given package."""
521 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
522
523
Alex Klein87531182019-08-12 15:23:37 -0600524@uprevs_versioned_package(constants.CHROME_CP)
Alex Kleinf69bd802021-06-22 15:43:49 -0600525def uprev_chrome_from_ref(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600526 """Uprev chrome and its related packages.
527
528 See: uprev_versioned_package.
529 """
530 # Determine the version from the refs (tags), i.e. the chrome versions are the
531 # tag names.
532 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600533 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600534
Alex Kleinf69bd802021-06-22 15:43:49 -0600535 return uprev_chrome(build_targets, chrome_version, chroot)
536
537
538def revbump_chrome(build_targets, chroot):
539 """Attempt to revbump chrome.
540
541 Revbumps are done by executing an uprev using the current stable version.
542 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
543 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
544 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
545 """
546 chrome_version = uprev_lib.get_stable_chrome_version()
547 return uprev_chrome(build_targets, chrome_version, chroot)
548
549
550def uprev_chrome(build_targets, chrome_version, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600551 uprev_manager = uprev_lib.UprevChromeManager(
552 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600553 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600554 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
555 # attempt. The expected behavior is documented in the following table:
556 #
557 # Outcome of Chrome uprev attempt:
558 # NEWER_VERSION_EXISTS:
559 # Do nothing.
560 # SAME_VERSION_EXISTS or REVISION_BUMP:
561 # Uprev followers
562 # Assert not VERSION_BUMP (any other outcome is fine)
563 # VERSION_BUMP or NEW_EBUILD_CREATED:
564 # Uprev followers
565 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600566
567 # Start with chrome itself so we can proceed accordingly.
568 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
569 if chrome_result.newer_version_exists:
570 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600571 return result
Alex Klein87531182019-08-12 15:23:37 -0600572
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600573 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600574 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600575 follower_result = uprev_manager.uprev(package)
576 if chrome_result.stable_version and follower_result.version_bump:
577 logging.warning('%s had a version bump, but no more than a revision bump '
578 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600579
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600580 if uprev_manager.modified_ebuilds:
581 # Record changes when we have them.
582 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
583
584 return result
Alex Klein87531182019-08-12 15:23:37 -0600585
586
Harvey Yang3eee06c2021-03-18 15:47:56 +0800587def _get_latest_version_from_refs(refs_prefix: str,
588 refs: List[uprev_lib.GitRef]) -> str:
589 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000590
Ben Reiche779cf42020-12-15 03:21:31 +0000591 Versions are compared using |distutils.version.LooseVersion| and
592 the latest version is returned.
593
594 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800595 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800596 refs: The tags to parse for the latest Perfetto version.
597
598 Returns:
599 The latest Perfetto version to use.
600 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800601 valid_refs = []
602 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800603 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800604 valid_refs.append(gitiles.ref)
605
606 if not valid_refs:
607 return None
608
609 # Sort by version and take the latest version.
610 target_version_ref = sorted(valid_refs,
611 key=LooseVersion,
612 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800613 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800614
615
Andrew Lamb9563a152019-12-04 11:42:18 -0700616def _generate_platform_c_files(replication_config, chroot):
617 """Generates platform C files from a platform JSON payload.
618
619 Args:
620 replication_config (replication_config_pb2.ReplicationConfig): A
621 ReplicationConfig that has already been run. If it produced a
622 build_config.json file, that file will be used to generate platform C
623 files. Otherwise, nothing will be generated.
624 chroot (chroot_lib.Chroot): The chroot to use to generate.
625
626 Returns:
627 A list of generated files.
628 """
629 # Generate the platform C files from the build config. Note that it would be
630 # more intuitive to generate the platform C files from the platform config;
631 # however, cros_config_schema does not allow this, because the platform config
632 # payload is not always valid input. For example, if a property is both
633 # 'required' and 'build-only', it will fail schema validation. Thus, use the
634 # build config, and use '-f' to filter.
635 build_config_path = [
636 rule.destination_path
637 for rule in replication_config.file_replication_rules
638 if rule.destination_path.endswith('build_config.json')
639 ]
640
641 if not build_config_path:
642 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700643 'No build_config.json found, will not generate platform C files. '
644 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700645 return []
646
647 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700648 raise ValueError('Expected at most one build_config.json destination path. '
649 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700650
651 build_config_path = build_config_path[0]
652
653 # Paths to the build_config.json and dir to output C files to, in the
654 # chroot.
655 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
656 build_config_path)
657 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
658 os.path.dirname(build_config_path))
659
660 command = [
661 'cros_config_schema', '-m', build_config_chroot_path, '-g',
662 generated_output_chroot_dir, '-f', '"TRUE"'
663 ]
664
665 cros_build_lib.run(
666 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
667
668 # A relative (to the source root) path to the generated C files.
669 generated_output_dir = os.path.dirname(build_config_path)
670 generated_files = []
671 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
672 for f in expected_c_files:
673 if os.path.exists(
674 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
675 generated_files.append(os.path.join(generated_output_dir, f))
676
677 if len(expected_c_files) != len(generated_files):
678 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
679
680 return generated_files
681
682
Andrew Lambe836f222019-12-09 12:27:38 -0700683def _get_private_overlay_package_root(ref, package):
684 """Returns the absolute path to the root of a given private overlay.
685
686 Args:
687 ref (uprev_lib.GitRef): GitRef for the private overlay.
688 package (str): Path to the package in the overlay.
689 """
690 # There might be a cleaner way to map from package -> path within the source
691 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700692 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700693 match = re.match(private_overlay_ref_pattern, ref.path)
694 if not match:
695 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
696 (private_overlay_ref_pattern, ref))
697
698 overlay = match.group(1)
699
700 return os.path.join(constants.SOURCE_ROOT,
701 'src/private-overlays/overlay-%s-private' % overlay,
702 package)
703
704
Andrew Lambea9a8a22019-12-12 14:03:43 -0700705@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
706def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700707 """Replicate a private cros_config change to the corresponding public config.
708
Alex Kleinad6b48a2020-01-08 16:57:41 -0700709 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700710 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700711 package = 'chromeos-base/chromeos-config-bsp'
712
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700713 if len(refs) != 1:
714 raise ValueError('Expected exactly one ref, actual %s' % refs)
715
716 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700717 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700718 replication_config_path = os.path.join(package_root,
719 'replication_config.jsonpb')
720
721 try:
722 replication_config = json_format.Parse(
723 osutils.ReadFile(replication_config_path),
724 replication_config_pb2.ReplicationConfig())
725 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700726 raise ValueError(
727 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700728
729 replication_lib.Replicate(replication_config)
730
731 modified_files = [
732 rule.destination_path
733 for rule in replication_config.file_replication_rules
734 ]
735
Andrew Lamb9563a152019-12-04 11:42:18 -0700736 # The generated platform C files are not easily filtered by replication rules,
737 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
738 # files cannot. Therefore, replicate and filter the JSON payloads, and then
739 # generate filtered C files from the JSON payload.
740 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700741
742 # Use the private repo's commit hash as the new version.
743 new_private_version = refs[0].revision
744
Andrew Lamb988f4da2019-12-10 10:16:43 -0700745 # modified_files should contain only relative paths at this point, but the
746 # returned UprevVersionedPackageResult must contain only absolute paths.
747 for i, modified_file in enumerate(modified_files):
748 assert not os.path.isabs(modified_file)
749 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
750
Chris McDonald38409112020-09-24 11:24:51 -0600751 return uprev_lib.UprevVersionedPackageResult().add_result(
752 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700753
754
Alex Kleinbbef2b32019-08-27 10:38:50 -0600755def get_best_visible(atom, build_target=None):
756 """Returns the best visible CPV for the given atom.
757
758 Args:
759 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600760 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600761 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700762
763 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600764 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600765 """
David Burger1e0fe232019-07-01 14:52:07 -0600766 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600767
768 board = build_target.name if build_target else None
769 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600770
771
Alex Klein149fd3b2019-12-16 16:01:05 -0700772def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600773 """Check if a prebuilt exists.
774
775 Args:
776 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600777 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600778 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700779 useflags: Any additional USE flags that should be set. May be a string
780 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700781
782 Returns:
783 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600784 """
785 assert atom
786
787 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700788 extra_env = None
789 if useflags:
790 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500791 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700792 new_flags = ' '.join(useflags)
793
794 existing = os.environ.get('USE', '')
795 final_flags = '%s %s' % (existing, new_flags)
796 extra_env = {'USE': final_flags.strip()}
797 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600798
799
David Burger0f9dd4e2019-10-08 12:33:42 -0600800def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600801 """Check if |build_target| builds |atom| (has it in its depgraph)."""
802 cros_build_lib.AssertInsideChroot()
803
Alex Kleind8cd4c62020-09-14 13:37:47 -0600804 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600805 # TODO(crbug/1081828): Receive and use sysroot.
806 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600807 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600808 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600809
810
Alex Klein6becabc2020-09-11 14:03:05 -0600811def needs_chrome_source(
812 build_target: 'build_target_lib.BuildTarget',
813 compile_source=False,
814 packages: Optional[List[package_info.PackageInfo]] = None,
815 useflags=None):
816 """Check if the chrome source is needed.
817
818 The chrome source is needed if the build target builds chrome or any of its
819 follower packages, and can't use a prebuilt for them either because it's not
820 available, or because we can't use prebuilts because it must build from
821 source.
822 """
823 cros_build_lib.AssertInsideChroot()
824
825 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700826 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600827 builds_chrome = constants.CHROME_CP in graph
828 builds_follower = {
829 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
830 }
831
832 # When we are compiling source set False since we do not use prebuilts.
833 # When not compiling from source, start with True, i.e. we have every prebuilt
834 # we've checked for up to this point.
835 has_chrome_prebuilt = not compile_source
836 has_follower_prebuilts = not compile_source
837 # Save packages that need prebuilts for reporting.
838 pkgs_needing_prebuilts = []
839 if compile_source:
840 # Need everything.
841 pkgs_needing_prebuilts.append(constants.CHROME_CP)
842 pkgs_needing_prebuilts.extend(
843 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
844 else:
845 # Check chrome itself.
846 if builds_chrome:
847 has_chrome_prebuilt = has_prebuilt(
848 constants.CHROME_CP, build_target=build_target, useflags=useflags)
849 if not has_chrome_prebuilt:
850 pkgs_needing_prebuilts.append(constants.CHROME_CP)
851 # Check follower packages.
852 for pkg, builds_pkg in builds_follower.items():
853 if not builds_pkg:
854 continue
855 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
856 has_follower_prebuilts &= prebuilt
857 if not prebuilt:
858 pkgs_needing_prebuilts.append(pkg)
859 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
860 # reflect whether we actually have the corresponding prebuilts for the build.
861
862 needs_chrome = builds_chrome and not has_chrome_prebuilt
863 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
864
865 return NeedsChromeSourceResult(
866 needs_chrome_source=needs_chrome or needs_follower,
867 builds_chrome=builds_chrome,
868 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
869 missing_chrome_prebuilt=not has_chrome_prebuilt,
870 missing_follower_prebuilt=not has_follower_prebuilts)
871
872
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600873def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600874 """Returns the current Chrome version for the board (or in buildroot).
875
876 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600877 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700878
879 Returns:
880 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600881 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600882 # TODO(crbug/1019770): Long term we should not need the try/catch here once
883 # the builds function above only returns True for chrome when
884 # determine_chrome_version will succeed.
885 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700886 cpv = portage_util.PortageqBestVisible(
887 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600888 except cros_build_lib.RunCommandError as e:
889 # Return None because portage failed when trying to determine the chrome
890 # version.
891 logging.warning('Caught exception in determine_chrome_package: %s', e)
892 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600893 # Something like 78.0.3877.4_rc -> 78.0.3877.4
894 return cpv.version_no_rev.partition('_')[0]
895
896
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600897def determine_android_package(board):
898 """Returns the active Android container package in use by the board.
899
900 Args:
901 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700902
903 Returns:
904 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600905 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600906 try:
907 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600908 except cros_build_lib.RunCommandError as e:
909 # Return None because a command (likely portage) failed when trying to
910 # determine the package.
911 logging.warning('Caught exception in determine_android_package: %s', e)
912 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600913
Alex Kleinad6b48a2020-01-08 16:57:41 -0700914 # We assume there is only one Android package in the depgraph.
915 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400916 if (package.startswith('chromeos-base/android-container-') or
917 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700918 return package
919 return None
920
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600921
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500922def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600923 """Determine the current Android version in buildroot now and return it.
924
925 This uses the typical portage logic to determine which version of Android
926 is active right now in the buildroot.
927
928 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500929 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500930 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600931
932 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500933 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600934
935 Raises:
936 NoAndroidVersionError: if no unique Android version can be determined.
937 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500938 if not package:
939 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500940 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600941 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500942 cpv = package_info.SplitCPV(package)
943 if not cpv:
944 raise NoAndroidVersionError(
945 'Android version could not be determined for %s' % board)
946 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600947
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700948
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500949def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600950 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500951 if not package:
952 package = determine_android_package(board)
953 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600954 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500955 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600956 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900957 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900958 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600959 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
960 for target in targets:
961 if target in ebuild_content:
962 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
963 if branch is not None:
964 return branch.group(1)
965 raise NoAndroidBranchError(
966 'Android branch could not be determined for %s (ebuild empty?)' % board)
967
968
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500969def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600970 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500971 if not package:
972 package = determine_android_package(board)
973 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600974 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500975 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600976 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500977 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600978 return 'cheets'
979
980 raise NoAndroidTargetError(
981 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500982 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600983
984
985def determine_platform_version():
986 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600987 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600988 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
989 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600990
991
992def determine_milestone_version():
993 """Returns the platform version from the source root."""
994 # Milestone version is something like '79'.
995 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
996 return version.chrome_branch
997
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700998
Michael Mortensen009cb662019-10-21 11:38:43 -0600999def determine_full_version():
1000 """Returns the full version from the source root."""
1001 # Full version is something like 'R79-12575.0.0'.
1002 milestone_version = determine_milestone_version()
1003 platform_version = determine_platform_version()
1004 full_version = ('R%s-%s' % (milestone_version, platform_version))
1005 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001006
1007
Michael Mortensende716a12020-05-15 11:27:00 -06001008def find_fingerprints(build_target):
1009 """Returns a list of fingerprints for this build.
1010
1011 Args:
1012 build_target (build_target_lib.BuildTarget): The build target.
1013
1014 Returns:
1015 list[str] - List of fingerprint strings.
1016 """
1017 cros_build_lib.AssertInsideChroot()
1018 fp_file = 'cheets-fingerprint.txt'
1019 fp_path = os.path.join(
1020 image_lib.GetLatestImageLink(build_target.name),
1021 fp_file)
1022 if not os.path.isfile(fp_path):
1023 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001024 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001025 logging.info('Reading fingerprint file: %s', fp_path)
1026 fingerprints = osutils.ReadFile(fp_path).splitlines()
1027 return fingerprints
1028
1029
Michael Mortensen59e30872020-05-18 14:12:49 -06001030def get_all_firmware_versions(build_target):
1031 """Extract firmware version for all models present.
1032
1033 Args:
1034 build_target (build_target_lib.BuildTarget): The build target.
1035
1036 Returns:
1037 A dict of FirmwareVersions namedtuple instances by model.
1038 Each element will be populated based on whether it was present in the
1039 command output.
1040 """
1041 cros_build_lib.AssertInsideChroot()
1042 result = {}
1043 # Note that example output for _get_firmware_version_cmd_result is available
1044 # in the packages_unittest.py for testing get_all_firmware_versions.
1045 cmd_result = _get_firmware_version_cmd_result(build_target)
1046
1047 # There is a blank line between the version info for each model.
1048 firmware_version_payloads = cmd_result.split('\n\n')
1049 for firmware_version_payload in firmware_version_payloads:
1050 if 'BIOS' in firmware_version_payload:
1051 firmware_version = _find_firmware_versions(firmware_version_payload)
1052 result[firmware_version.model] = firmware_version
1053 return result
1054
1055
Michael Mortensen71ef5682020-05-07 14:29:24 -06001056FirmwareVersions = collections.namedtuple(
1057 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1058
1059
1060def get_firmware_versions(build_target):
1061 """Extract version information from the firmware updater, if one exists.
1062
1063 Args:
1064 build_target (build_target_lib.BuildTarget): The build target.
1065
1066 Returns:
1067 A FirmwareVersions namedtuple instance.
1068 Each element will either be set to the string output by the firmware
1069 updater shellball, or None if there is no firmware updater.
1070 """
1071 cros_build_lib.AssertInsideChroot()
1072 cmd_result = _get_firmware_version_cmd_result(build_target)
1073 if cmd_result:
1074 return _find_firmware_versions(cmd_result)
1075 else:
1076 return FirmwareVersions(None, None, None, None, None)
1077
1078
1079def _get_firmware_version_cmd_result(build_target):
1080 """Gets the raw result output of the firmware updater version command.
1081
1082 Args:
1083 build_target (build_target_lib.BuildTarget): The build target.
1084
1085 Returns:
1086 Command execution result.
1087 """
1088 updater = os.path.join(build_target.root,
1089 'usr/sbin/chromeos-firmwareupdate')
1090 logging.info('Calling updater %s', updater)
1091 # Call the updater using the chroot-based path.
1092 return cros_build_lib.run([updater, '-V'],
1093 capture_output=True, log_output=True,
1094 encoding='utf-8').stdout
1095
1096
1097def _find_firmware_versions(cmd_output):
1098 """Finds firmware version output via regex matches against the cmd_output.
1099
1100 Args:
1101 cmd_output: The raw output to search against.
1102
1103 Returns:
1104 FirmwareVersions namedtuple with results.
1105 Each element will either be set to the string output by the firmware
1106 updater shellball, or None if there is no match.
1107 """
1108
1109 # Sometimes a firmware bundle includes a special combination of RO+RW
1110 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1111 # version" field. In other cases, the "(RW) version" field is not present.
1112 # Therefore, search for the "(RW)" fields first and if they aren't present,
1113 # fallback to the other format. e.g. just "BIOS version:".
1114 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1115 main = None
1116 main_rw = None
1117 ec = None
1118 ec_rw = None
1119 model = None
1120
1121 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1122 if match:
1123 main = match.group('version')
1124
1125 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1126 if match:
1127 main_rw = match.group('version')
1128
1129 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1130 if match:
1131 ec = match.group('version')
1132
1133 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1134 if match:
1135 ec_rw = match.group('version')
1136
1137 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1138 if match:
1139 model = match.group('model')
1140
1141 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001142
1143
1144MainEcFirmwareVersions = collections.namedtuple(
1145 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1146
1147def determine_firmware_versions(build_target):
1148 """Returns a namedtuple with main and ec firmware versions.
1149
1150 Args:
1151 build_target (build_target_lib.BuildTarget): The build target.
1152
1153 Returns:
1154 MainEcFirmwareVersions namedtuple with results.
1155 """
1156 fw_versions = get_firmware_versions(build_target)
1157 main_fw_version = fw_versions.main_rw or fw_versions.main
1158 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1159
1160 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001161
1162def determine_kernel_version(build_target):
1163 """Returns a string containing the kernel version for this build target.
1164
1165 Args:
1166 build_target (build_target_lib.BuildTarget): The build target.
1167
1168 Returns:
1169 (str) The kernel versions, or None.
1170 """
1171 try:
1172 packages = portage_util.GetPackageDependencies(build_target.name,
1173 'virtual/linux-sources')
1174 except cros_build_lib.RunCommandError as e:
1175 logging.warning('Unable to get package list for metadata: %s', e)
1176 return None
1177 for package in packages:
1178 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001179 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001180 logging.info('Found active kernel version: %s', kernel_version)
1181 return kernel_version
1182 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001183
1184
1185def get_models(build_target, log_output=True):
1186 """Obtain a list of models supported by a unified board.
1187
1188 This ignored whitelabel models since GoldenEye has no specific support for
1189 these at present.
1190
1191 Args:
1192 build_target (build_target_lib.BuildTarget): The build target.
1193 log_output: Whether to log the output of the cros_config_host invocation.
1194
1195 Returns:
1196 A list of models supported by this board, if it is a unified build; None,
1197 if it is not a unified build.
1198 """
1199 return _run_cros_config_host(build_target, ['list-models'],
1200 log_output=log_output)
1201
1202
Michael Mortensen359c1f32020-05-28 19:35:42 -06001203def get_key_id(build_target, model):
1204 """Obtain the key_id for a model within the build_target.
1205
1206 Args:
1207 build_target (build_target_lib.BuildTarget): The build target.
1208 model (str): The model name
1209
1210 Returns:
1211 A key_id (str) or None.
1212 """
1213 model_arg = '--model=' + model
1214 key_id_list = _run_cros_config_host(
1215 build_target,
1216 [model_arg, 'get', '/firmware-signing', 'key-id'])
1217 key_id = None
1218 if len(key_id_list) == 1:
1219 key_id = key_id_list[0]
1220 return key_id
1221
1222
Michael Mortensen125bb012020-05-21 14:02:10 -06001223def _run_cros_config_host(build_target, args, log_output=True):
1224 """Run the cros_config_host tool.
1225
1226 Args:
1227 build_target (build_target_lib.BuildTarget): The build target.
1228 args: List of arguments to pass.
1229 log_output: Whether to log the output of the cros_config_host.
1230
1231 Returns:
1232 Output of the tool
1233 """
1234 cros_build_lib.AssertInsideChroot()
1235 tool = '/usr/bin/cros_config_host'
1236 if not os.path.isfile(tool):
1237 return None
1238
1239 config_fname = build_target.full_path(
1240 'usr/share/chromeos-config/yaml/config.yaml')
1241
1242 result = cros_build_lib.run(
1243 [tool, '-c', config_fname] + args,
1244 capture_output=True,
1245 encoding='utf-8',
1246 log_output=log_output,
1247 check=False)
1248 if result.returncode:
1249 # Show the output for debugging purposes.
1250 if 'No such file or directory' not in result.error:
1251 logging.error('cros_config_host failed: %s\n', result.error)
1252 return None
1253 return result.output.strip().splitlines()