blob: b970a7bb8de9b332ce461ad67e8f98d19440aa5e [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()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600402 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600403 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
404 'sys-kernel', version)
405 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
406 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600407 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
408 '%s-9999.ebuild' % version)
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()
Alex Klein87531182019-08-12 15:23:37 -0600554 # Start with chrome itself, as we can't do anything else unless chrome
555 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600556 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
557 # attempt. The expected behavior is documented in the following table:
558 #
559 # Outcome of Chrome uprev attempt:
560 # NEWER_VERSION_EXISTS:
561 # Do nothing.
562 # SAME_VERSION_EXISTS or REVISION_BUMP:
563 # Uprev followers
564 # Assert not VERSION_BUMP (any other outcome is fine)
565 # VERSION_BUMP or NEW_EBUILD_CREATED:
566 # Uprev followers
567 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600568 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600569 return result
Alex Klein87531182019-08-12 15:23:37 -0600570
571 # With a successful chrome rev, also uprev related packages.
572 for package in constants.OTHER_CHROME_PACKAGES:
573 uprev_manager.uprev(package)
574
David Burger37f48672019-09-18 17:07:56 -0600575 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600576
577
Harvey Yang3eee06c2021-03-18 15:47:56 +0800578def _get_latest_version_from_refs(refs_prefix: str,
579 refs: List[uprev_lib.GitRef]) -> str:
580 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000581
Ben Reiche779cf42020-12-15 03:21:31 +0000582 Versions are compared using |distutils.version.LooseVersion| and
583 the latest version is returned.
584
585 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800586 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800587 refs: The tags to parse for the latest Perfetto version.
588
589 Returns:
590 The latest Perfetto version to use.
591 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800592 valid_refs = []
593 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800594 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800595 valid_refs.append(gitiles.ref)
596
597 if not valid_refs:
598 return None
599
600 # Sort by version and take the latest version.
601 target_version_ref = sorted(valid_refs,
602 key=LooseVersion,
603 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800604 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800605
606
Andrew Lamb9563a152019-12-04 11:42:18 -0700607def _generate_platform_c_files(replication_config, chroot):
608 """Generates platform C files from a platform JSON payload.
609
610 Args:
611 replication_config (replication_config_pb2.ReplicationConfig): A
612 ReplicationConfig that has already been run. If it produced a
613 build_config.json file, that file will be used to generate platform C
614 files. Otherwise, nothing will be generated.
615 chroot (chroot_lib.Chroot): The chroot to use to generate.
616
617 Returns:
618 A list of generated files.
619 """
620 # Generate the platform C files from the build config. Note that it would be
621 # more intuitive to generate the platform C files from the platform config;
622 # however, cros_config_schema does not allow this, because the platform config
623 # payload is not always valid input. For example, if a property is both
624 # 'required' and 'build-only', it will fail schema validation. Thus, use the
625 # build config, and use '-f' to filter.
626 build_config_path = [
627 rule.destination_path
628 for rule in replication_config.file_replication_rules
629 if rule.destination_path.endswith('build_config.json')
630 ]
631
632 if not build_config_path:
633 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700634 'No build_config.json found, will not generate platform C files. '
635 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700636 return []
637
638 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700639 raise ValueError('Expected at most one build_config.json destination path. '
640 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700641
642 build_config_path = build_config_path[0]
643
644 # Paths to the build_config.json and dir to output C files to, in the
645 # chroot.
646 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
647 build_config_path)
648 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
649 os.path.dirname(build_config_path))
650
651 command = [
652 'cros_config_schema', '-m', build_config_chroot_path, '-g',
653 generated_output_chroot_dir, '-f', '"TRUE"'
654 ]
655
656 cros_build_lib.run(
657 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
658
659 # A relative (to the source root) path to the generated C files.
660 generated_output_dir = os.path.dirname(build_config_path)
661 generated_files = []
662 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
663 for f in expected_c_files:
664 if os.path.exists(
665 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
666 generated_files.append(os.path.join(generated_output_dir, f))
667
668 if len(expected_c_files) != len(generated_files):
669 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
670
671 return generated_files
672
673
Andrew Lambe836f222019-12-09 12:27:38 -0700674def _get_private_overlay_package_root(ref, package):
675 """Returns the absolute path to the root of a given private overlay.
676
677 Args:
678 ref (uprev_lib.GitRef): GitRef for the private overlay.
679 package (str): Path to the package in the overlay.
680 """
681 # There might be a cleaner way to map from package -> path within the source
682 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700683 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700684 match = re.match(private_overlay_ref_pattern, ref.path)
685 if not match:
686 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
687 (private_overlay_ref_pattern, ref))
688
689 overlay = match.group(1)
690
691 return os.path.join(constants.SOURCE_ROOT,
692 'src/private-overlays/overlay-%s-private' % overlay,
693 package)
694
695
Andrew Lambea9a8a22019-12-12 14:03:43 -0700696@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
697def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700698 """Replicate a private cros_config change to the corresponding public config.
699
Alex Kleinad6b48a2020-01-08 16:57:41 -0700700 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700701 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700702 package = 'chromeos-base/chromeos-config-bsp'
703
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700704 if len(refs) != 1:
705 raise ValueError('Expected exactly one ref, actual %s' % refs)
706
707 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700708 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700709 replication_config_path = os.path.join(package_root,
710 'replication_config.jsonpb')
711
712 try:
713 replication_config = json_format.Parse(
714 osutils.ReadFile(replication_config_path),
715 replication_config_pb2.ReplicationConfig())
716 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700717 raise ValueError(
718 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700719
720 replication_lib.Replicate(replication_config)
721
722 modified_files = [
723 rule.destination_path
724 for rule in replication_config.file_replication_rules
725 ]
726
Andrew Lamb9563a152019-12-04 11:42:18 -0700727 # The generated platform C files are not easily filtered by replication rules,
728 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
729 # files cannot. Therefore, replicate and filter the JSON payloads, and then
730 # generate filtered C files from the JSON payload.
731 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700732
733 # Use the private repo's commit hash as the new version.
734 new_private_version = refs[0].revision
735
Andrew Lamb988f4da2019-12-10 10:16:43 -0700736 # modified_files should contain only relative paths at this point, but the
737 # returned UprevVersionedPackageResult must contain only absolute paths.
738 for i, modified_file in enumerate(modified_files):
739 assert not os.path.isabs(modified_file)
740 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
741
Chris McDonald38409112020-09-24 11:24:51 -0600742 return uprev_lib.UprevVersionedPackageResult().add_result(
743 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700744
745
Alex Kleinbbef2b32019-08-27 10:38:50 -0600746def get_best_visible(atom, build_target=None):
747 """Returns the best visible CPV for the given atom.
748
749 Args:
750 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600751 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600752 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700753
754 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600755 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600756 """
David Burger1e0fe232019-07-01 14:52:07 -0600757 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600758
759 board = build_target.name if build_target else None
760 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600761
762
Alex Klein149fd3b2019-12-16 16:01:05 -0700763def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600764 """Check if a prebuilt exists.
765
766 Args:
767 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600768 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600769 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700770 useflags: Any additional USE flags that should be set. May be a string
771 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700772
773 Returns:
774 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600775 """
776 assert atom
777
778 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700779 extra_env = None
780 if useflags:
781 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500782 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700783 new_flags = ' '.join(useflags)
784
785 existing = os.environ.get('USE', '')
786 final_flags = '%s %s' % (existing, new_flags)
787 extra_env = {'USE': final_flags.strip()}
788 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600789
790
David Burger0f9dd4e2019-10-08 12:33:42 -0600791def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600792 """Check if |build_target| builds |atom| (has it in its depgraph)."""
793 cros_build_lib.AssertInsideChroot()
794
Alex Kleind8cd4c62020-09-14 13:37:47 -0600795 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600796 # TODO(crbug/1081828): Receive and use sysroot.
797 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600798 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600799 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600800
801
Alex Klein6becabc2020-09-11 14:03:05 -0600802def needs_chrome_source(
803 build_target: 'build_target_lib.BuildTarget',
804 compile_source=False,
805 packages: Optional[List[package_info.PackageInfo]] = None,
806 useflags=None):
807 """Check if the chrome source is needed.
808
809 The chrome source is needed if the build target builds chrome or any of its
810 follower packages, and can't use a prebuilt for them either because it's not
811 available, or because we can't use prebuilts because it must build from
812 source.
813 """
814 cros_build_lib.AssertInsideChroot()
815
816 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700817 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600818 builds_chrome = constants.CHROME_CP in graph
819 builds_follower = {
820 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
821 }
822
823 # When we are compiling source set False since we do not use prebuilts.
824 # When not compiling from source, start with True, i.e. we have every prebuilt
825 # we've checked for up to this point.
826 has_chrome_prebuilt = not compile_source
827 has_follower_prebuilts = not compile_source
828 # Save packages that need prebuilts for reporting.
829 pkgs_needing_prebuilts = []
830 if compile_source:
831 # Need everything.
832 pkgs_needing_prebuilts.append(constants.CHROME_CP)
833 pkgs_needing_prebuilts.extend(
834 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
835 else:
836 # Check chrome itself.
837 if builds_chrome:
838 has_chrome_prebuilt = has_prebuilt(
839 constants.CHROME_CP, build_target=build_target, useflags=useflags)
840 if not has_chrome_prebuilt:
841 pkgs_needing_prebuilts.append(constants.CHROME_CP)
842 # Check follower packages.
843 for pkg, builds_pkg in builds_follower.items():
844 if not builds_pkg:
845 continue
846 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
847 has_follower_prebuilts &= prebuilt
848 if not prebuilt:
849 pkgs_needing_prebuilts.append(pkg)
850 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
851 # reflect whether we actually have the corresponding prebuilts for the build.
852
853 needs_chrome = builds_chrome and not has_chrome_prebuilt
854 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
855
856 return NeedsChromeSourceResult(
857 needs_chrome_source=needs_chrome or needs_follower,
858 builds_chrome=builds_chrome,
859 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
860 missing_chrome_prebuilt=not has_chrome_prebuilt,
861 missing_follower_prebuilt=not has_follower_prebuilts)
862
863
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600864def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600865 """Returns the current Chrome version for the board (or in buildroot).
866
867 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600868 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700869
870 Returns:
871 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600872 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600873 # TODO(crbug/1019770): Long term we should not need the try/catch here once
874 # the builds function above only returns True for chrome when
875 # determine_chrome_version will succeed.
876 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700877 cpv = portage_util.PortageqBestVisible(
878 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600879 except cros_build_lib.RunCommandError as e:
880 # Return None because portage failed when trying to determine the chrome
881 # version.
882 logging.warning('Caught exception in determine_chrome_package: %s', e)
883 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600884 # Something like 78.0.3877.4_rc -> 78.0.3877.4
885 return cpv.version_no_rev.partition('_')[0]
886
887
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600888def determine_android_package(board):
889 """Returns the active Android container package in use by the board.
890
891 Args:
892 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700893
894 Returns:
895 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600896 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600897 try:
898 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600899 except cros_build_lib.RunCommandError as e:
900 # Return None because a command (likely portage) failed when trying to
901 # determine the package.
902 logging.warning('Caught exception in determine_android_package: %s', e)
903 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600904
Alex Kleinad6b48a2020-01-08 16:57:41 -0700905 # We assume there is only one Android package in the depgraph.
906 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400907 if (package.startswith('chromeos-base/android-container-') or
908 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700909 return package
910 return None
911
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600912
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500913def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600914 """Determine the current Android version in buildroot now and return it.
915
916 This uses the typical portage logic to determine which version of Android
917 is active right now in the buildroot.
918
919 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500920 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500921 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600922
923 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500924 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600925
926 Raises:
927 NoAndroidVersionError: if no unique Android version can be determined.
928 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500929 if not package:
930 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500931 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600932 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500933 cpv = package_info.SplitCPV(package)
934 if not cpv:
935 raise NoAndroidVersionError(
936 'Android version could not be determined for %s' % board)
937 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600938
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700939
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500940def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600941 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500942 if not package:
943 package = determine_android_package(board)
944 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600945 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500946 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600947 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900948 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900949 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600950 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
951 for target in targets:
952 if target in ebuild_content:
953 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
954 if branch is not None:
955 return branch.group(1)
956 raise NoAndroidBranchError(
957 'Android branch could not be determined for %s (ebuild empty?)' % board)
958
959
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500960def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600961 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500962 if not package:
963 package = determine_android_package(board)
964 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600965 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500966 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600967 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500968 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600969 return 'cheets'
970
971 raise NoAndroidTargetError(
972 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500973 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600974
975
976def determine_platform_version():
977 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600978 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600979 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
980 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600981
982
983def determine_milestone_version():
984 """Returns the platform version from the source root."""
985 # Milestone version is something like '79'.
986 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
987 return version.chrome_branch
988
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700989
Michael Mortensen009cb662019-10-21 11:38:43 -0600990def determine_full_version():
991 """Returns the full version from the source root."""
992 # Full version is something like 'R79-12575.0.0'.
993 milestone_version = determine_milestone_version()
994 platform_version = determine_platform_version()
995 full_version = ('R%s-%s' % (milestone_version, platform_version))
996 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600997
998
Michael Mortensende716a12020-05-15 11:27:00 -0600999def find_fingerprints(build_target):
1000 """Returns a list of fingerprints for this build.
1001
1002 Args:
1003 build_target (build_target_lib.BuildTarget): The build target.
1004
1005 Returns:
1006 list[str] - List of fingerprint strings.
1007 """
1008 cros_build_lib.AssertInsideChroot()
1009 fp_file = 'cheets-fingerprint.txt'
1010 fp_path = os.path.join(
1011 image_lib.GetLatestImageLink(build_target.name),
1012 fp_file)
1013 if not os.path.isfile(fp_path):
1014 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001015 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001016 logging.info('Reading fingerprint file: %s', fp_path)
1017 fingerprints = osutils.ReadFile(fp_path).splitlines()
1018 return fingerprints
1019
1020
Michael Mortensen59e30872020-05-18 14:12:49 -06001021def get_all_firmware_versions(build_target):
1022 """Extract firmware version for all models present.
1023
1024 Args:
1025 build_target (build_target_lib.BuildTarget): The build target.
1026
1027 Returns:
1028 A dict of FirmwareVersions namedtuple instances by model.
1029 Each element will be populated based on whether it was present in the
1030 command output.
1031 """
1032 cros_build_lib.AssertInsideChroot()
1033 result = {}
1034 # Note that example output for _get_firmware_version_cmd_result is available
1035 # in the packages_unittest.py for testing get_all_firmware_versions.
1036 cmd_result = _get_firmware_version_cmd_result(build_target)
1037
1038 # There is a blank line between the version info for each model.
1039 firmware_version_payloads = cmd_result.split('\n\n')
1040 for firmware_version_payload in firmware_version_payloads:
1041 if 'BIOS' in firmware_version_payload:
1042 firmware_version = _find_firmware_versions(firmware_version_payload)
1043 result[firmware_version.model] = firmware_version
1044 return result
1045
1046
Michael Mortensen71ef5682020-05-07 14:29:24 -06001047FirmwareVersions = collections.namedtuple(
1048 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1049
1050
1051def get_firmware_versions(build_target):
1052 """Extract version information from the firmware updater, if one exists.
1053
1054 Args:
1055 build_target (build_target_lib.BuildTarget): The build target.
1056
1057 Returns:
1058 A FirmwareVersions namedtuple instance.
1059 Each element will either be set to the string output by the firmware
1060 updater shellball, or None if there is no firmware updater.
1061 """
1062 cros_build_lib.AssertInsideChroot()
1063 cmd_result = _get_firmware_version_cmd_result(build_target)
1064 if cmd_result:
1065 return _find_firmware_versions(cmd_result)
1066 else:
1067 return FirmwareVersions(None, None, None, None, None)
1068
1069
1070def _get_firmware_version_cmd_result(build_target):
1071 """Gets the raw result output of the firmware updater version command.
1072
1073 Args:
1074 build_target (build_target_lib.BuildTarget): The build target.
1075
1076 Returns:
1077 Command execution result.
1078 """
1079 updater = os.path.join(build_target.root,
1080 'usr/sbin/chromeos-firmwareupdate')
1081 logging.info('Calling updater %s', updater)
1082 # Call the updater using the chroot-based path.
1083 return cros_build_lib.run([updater, '-V'],
1084 capture_output=True, log_output=True,
1085 encoding='utf-8').stdout
1086
1087
1088def _find_firmware_versions(cmd_output):
1089 """Finds firmware version output via regex matches against the cmd_output.
1090
1091 Args:
1092 cmd_output: The raw output to search against.
1093
1094 Returns:
1095 FirmwareVersions namedtuple with results.
1096 Each element will either be set to the string output by the firmware
1097 updater shellball, or None if there is no match.
1098 """
1099
1100 # Sometimes a firmware bundle includes a special combination of RO+RW
1101 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1102 # version" field. In other cases, the "(RW) version" field is not present.
1103 # Therefore, search for the "(RW)" fields first and if they aren't present,
1104 # fallback to the other format. e.g. just "BIOS version:".
1105 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1106 main = None
1107 main_rw = None
1108 ec = None
1109 ec_rw = None
1110 model = None
1111
1112 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1113 if match:
1114 main = match.group('version')
1115
1116 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1117 if match:
1118 main_rw = match.group('version')
1119
1120 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1121 if match:
1122 ec = match.group('version')
1123
1124 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1125 if match:
1126 ec_rw = match.group('version')
1127
1128 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1129 if match:
1130 model = match.group('model')
1131
1132 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001133
1134
1135MainEcFirmwareVersions = collections.namedtuple(
1136 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1137
1138def determine_firmware_versions(build_target):
1139 """Returns a namedtuple with main and ec firmware versions.
1140
1141 Args:
1142 build_target (build_target_lib.BuildTarget): The build target.
1143
1144 Returns:
1145 MainEcFirmwareVersions namedtuple with results.
1146 """
1147 fw_versions = get_firmware_versions(build_target)
1148 main_fw_version = fw_versions.main_rw or fw_versions.main
1149 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1150
1151 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001152
1153def determine_kernel_version(build_target):
1154 """Returns a string containing the kernel version for this build target.
1155
1156 Args:
1157 build_target (build_target_lib.BuildTarget): The build target.
1158
1159 Returns:
1160 (str) The kernel versions, or None.
1161 """
1162 try:
1163 packages = portage_util.GetPackageDependencies(build_target.name,
1164 'virtual/linux-sources')
1165 except cros_build_lib.RunCommandError as e:
1166 logging.warning('Unable to get package list for metadata: %s', e)
1167 return None
1168 for package in packages:
1169 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001170 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001171 logging.info('Found active kernel version: %s', kernel_version)
1172 return kernel_version
1173 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001174
1175
1176def get_models(build_target, log_output=True):
1177 """Obtain a list of models supported by a unified board.
1178
1179 This ignored whitelabel models since GoldenEye has no specific support for
1180 these at present.
1181
1182 Args:
1183 build_target (build_target_lib.BuildTarget): The build target.
1184 log_output: Whether to log the output of the cros_config_host invocation.
1185
1186 Returns:
1187 A list of models supported by this board, if it is a unified build; None,
1188 if it is not a unified build.
1189 """
1190 return _run_cros_config_host(build_target, ['list-models'],
1191 log_output=log_output)
1192
1193
Michael Mortensen359c1f32020-05-28 19:35:42 -06001194def get_key_id(build_target, model):
1195 """Obtain the key_id for a model within the build_target.
1196
1197 Args:
1198 build_target (build_target_lib.BuildTarget): The build target.
1199 model (str): The model name
1200
1201 Returns:
1202 A key_id (str) or None.
1203 """
1204 model_arg = '--model=' + model
1205 key_id_list = _run_cros_config_host(
1206 build_target,
1207 [model_arg, 'get', '/firmware-signing', 'key-id'])
1208 key_id = None
1209 if len(key_id_list) == 1:
1210 key_id = key_id_list[0]
1211 return key_id
1212
1213
Michael Mortensen125bb012020-05-21 14:02:10 -06001214def _run_cros_config_host(build_target, args, log_output=True):
1215 """Run the cros_config_host tool.
1216
1217 Args:
1218 build_target (build_target_lib.BuildTarget): The build target.
1219 args: List of arguments to pass.
1220 log_output: Whether to log the output of the cros_config_host.
1221
1222 Returns:
1223 Output of the tool
1224 """
1225 cros_build_lib.AssertInsideChroot()
1226 tool = '/usr/bin/cros_config_host'
1227 if not os.path.isfile(tool):
1228 return None
1229
1230 config_fname = build_target.full_path(
1231 'usr/share/chromeos-config/yaml/config.yaml')
1232
1233 result = cros_build_lib.run(
1234 [tool, '-c', config_fname] + args,
1235 capture_output=True,
1236 encoding='utf-8',
1237 log_output=log_output,
1238 check=False)
1239 if result.returncode:
1240 # Show the output for debugging purposes.
1241 if 'No such file or directory' not in result.error:
1242 logging.error('cros_config_host failed: %s\n', result.error)
1243 return None
1244 return result.output.strip().splitlines()