blob: f8b426d421d2bc7110c1438ac8358f56d9e36566 [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 Klein9ce3f682021-06-23 15:06:44 -060015from typing import List, Optional, Union
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',
Alex Klein9ce3f682021-06-23 15:06:44 -060096 'local_uprev',
Alex Klein6becabc2020-09-11 14:03:05 -060097))
98
99
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600100def patch_ebuild_vars(ebuild_path, variables):
101 """Updates variables in ebuild.
102
103 Use this function rather than portage_util.EBuild.UpdateEBuild when you
104 want to preserve the variable position and quotes within the ebuild.
105
106 Args:
107 ebuild_path: The path of the ebuild.
108 variables: Dictionary of variables to update in ebuild.
109 """
110 try:
111 for line in fileinput.input(ebuild_path, inplace=1):
112 varname, eq, _ = line.partition('=')
113 if eq == '=' and varname.strip() in variables:
114 value = variables[varname]
115 sys.stdout.write('%s="%s"\n' % (varname, value))
116 else:
117 sys.stdout.write(line)
118 finally:
119 fileinput.close()
120
121
Alex Klein87531182019-08-12 15:23:37 -0600122def uprevs_versioned_package(package):
123 """Decorator to register package uprev handlers."""
124 assert package
125
126 def register(func):
127 """Registers |func| as a handler for |package|."""
128 _UPREV_FUNCS[package] = func
129
130 @functools.wraps(func)
131 def pass_through(*args, **kwargs):
132 return func(*args, **kwargs)
133
134 return pass_through
135
136 return register
137
138
Shao-Chuan Leeb6a2cb62021-02-19 14:18:59 +0900139def uprev_android(android_package,
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700140 chroot,
141 build_targets=None,
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900142 android_build_branch=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900143 android_version=None,
144 skip_commit=False):
Alex Klein4de25e82019-08-05 15:58:39 -0600145 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700146 command = [
147 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900148 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700149 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600150 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900151 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900152 if android_build_branch:
153 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600154 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900155 command.append(f'--force_version={android_version}')
156 if skip_commit:
157 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600158
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700159 result = cros_build_lib.run(
160 command,
161 stdout=True,
162 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500163 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700164 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600165
Mike Frysinger88d96362020-02-14 19:05:45 -0500166 portage_atom_string = result.stdout.strip()
167 android_atom = None
168 if portage_atom_string:
169 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600170 if not android_atom:
171 logging.info('Found nothing to rev.')
172 return None
173
174 for target in build_targets or []:
175 # Sanity check: We should always be able to merge the version of
176 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900177 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600178 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700179 cros_build_lib.run(
180 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600181 except cros_build_lib.RunCommandError:
182 logging.error(
183 'Cannot emerge-%s =%s\nIs Android pinned to an older '
184 'version?', target, android_atom)
185 raise AndroidIsPinnedUprevError(android_atom)
186
187 return android_atom
188
189
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700190def uprev_build_targets(build_targets,
191 overlay_type,
192 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600193 output_dir=None):
194 """Uprev the set provided build targets, or all if not specified.
195
196 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600197 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600198 whose overlays should be uprevved, empty or None for all.
199 overlay_type (str): One of the valid overlay types except None (see
200 constants.VALID_OVERLAYS).
201 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
202 output_dir (str|None): The path to optionally dump result files.
203 """
204 # Need a valid overlay, but exclude None.
205 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
206
207 if build_targets:
208 overlays = portage_util.FindOverlaysForBoards(
209 overlay_type, boards=[t.name for t in build_targets])
210 else:
211 overlays = portage_util.FindOverlays(overlay_type)
212
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700213 return uprev_overlays(
214 overlays,
215 build_targets=build_targets,
216 chroot=chroot,
217 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600218
219
220def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
221 """Uprev the given overlays.
222
223 Args:
224 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600225 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600226 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
227 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
228 output_dir (str|None): The path to optionally dump result files.
229
230 Returns:
231 list[str] - The paths to all of the modified ebuild files. This includes the
232 new files that were added (i.e. the new versions) and all of the removed
233 files (i.e. the old versions).
234 """
235 assert overlays
236
237 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
238
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700239 uprev_manager = uprev_lib.UprevOverlayManager(
240 overlays,
241 manifest,
242 build_targets=build_targets,
243 chroot=chroot,
244 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600245 uprev_manager.uprev()
246
247 return uprev_manager.modified_ebuilds
248
249
Alex Klein87531182019-08-12 15:23:37 -0600250def uprev_versioned_package(package, build_targets, refs, chroot):
251 """Call registered uprev handler function for the package.
252
253 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600254 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600255 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600256 clean on a successful uprev.
257 refs (list[uprev_lib.GitRef]):
258 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
259
260 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600261 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600262 """
263 assert package
264
265 if package.cp not in _UPREV_FUNCS:
266 raise UnknownPackageError(
267 'Package "%s" does not have a registered handler.' % package.cp)
268
Andrew Lambea9a8a22019-12-12 14:03:43 -0700269 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600270
271
Navil Perezf57ba872020-06-04 22:38:37 +0000272@uprevs_versioned_package('media-libs/virglrenderer')
273def uprev_virglrenderer(_build_targets, refs, _chroot):
274 """Updates virglrenderer ebuilds.
275
276 See: uprev_versioned_package.
277
278 Returns:
279 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
280 """
Navil Perezf57ba872020-06-04 22:38:37 +0000281 overlay = os.path.join(constants.SOURCE_ROOT,
282 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600283 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
284 'virglrenderer')
285 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000286
287 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
288 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000289 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
290 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000291 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
292
George Engelbrechte73f2782020-06-10 14:10:46 -0600293 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600294 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000295 result.add_result(refs[0].revision, updated_files)
296 return result
297
Jose Magana03b5a842020-08-19 12:52:59 +1000298@uprevs_versioned_package('chromeos-base/drivefs')
299def uprev_drivefs(_build_targets, refs, chroot):
300 """Updates drivefs ebuilds.
301
Harvey Yang3eee06c2021-03-18 15:47:56 +0800302 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000303 See: uprev_versioned_package.
304
305 Returns:
306 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
307 """
308
Ben Reiche779cf42020-12-15 03:21:31 +0000309 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000310 result = uprev_lib.UprevVersionedPackageResult()
311 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000312
Harvey Yang3eee06c2021-03-18 15:47:56 +0800313 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
314 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000315 if not drivefs_version:
316 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000317 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000318
Ben Reiche779cf42020-12-15 03:21:31 +0000319 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000320
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000321 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000322 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000323 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000324 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800325 chroot,
326 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000327
328 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000329 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000330 all_changed_files.extend(uprev_result.changed_files)
331
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000332 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000333 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000334 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000335 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800336 chroot,
337 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000338
339 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000340 logging.warning(
341 'drivefs package has changed files %s but drivefs-ipc does not',
342 all_changed_files)
343 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000344
345 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000346 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000347
348 return result
349
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800350@uprevs_versioned_package('chromeos-base/perfetto')
351def uprev_perfetto(_build_targets, refs, chroot):
352 """Updates Perfetto ebuilds.
353
Harvey Yang3eee06c2021-03-18 15:47:56 +0800354 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800355 See: uprev_versioned_package.
356
357 Returns:
358 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
359 """
360 result = uprev_lib.UprevVersionedPackageResult()
361
Harvey Yang3eee06c2021-03-18 15:47:56 +0800362 PERFETTO_REFS_PREFIX = 'refs/tags/v'
363 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800364 if not perfetto_version:
365 # No valid Perfetto version is identified.
366 return result
367
368 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
369
370 # Attempt to uprev perfetto package.
371 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
372
Harvey Yang3eee06c2021-03-18 15:47:56 +0800373 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
374 PERFETTO_PATH,
375 perfetto_version,
376 chroot,
377 allow_downrev=False,
378 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800379
380 if not uprev_result:
381 return result
382
383 result.add_result(perfetto_version, uprev_result.changed_files)
384
385 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000386
Yaakov Shaul395ae832019-09-09 14:45:32 -0600387@uprevs_versioned_package('afdo/kernel-profiles')
388def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600389 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600390
391 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600392
393 Raises:
394 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600395 """
396 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
397 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
398
David Burger92485342019-09-10 17:52:45 -0600399 with open(path, 'r') as f:
400 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600401
Chris McDonald38409112020-09-24 11:24:51 -0600402 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600403 for kernel_pkg, version_info in versions.items():
404 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
405 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600406 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600407 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600408 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600409 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600410 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600411 patch_ebuild_vars(ebuild_path,
412 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600413
414 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600415 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400416 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600417 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600418 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600419 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600420 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600421
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600422 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600423
Yaakov Shaul730814a2019-09-10 13:58:25 -0600424 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
425
426 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600427
428
Trent Begineb624182020-07-14 10:09:45 -0600429@uprevs_versioned_package('chromeos-base/termina-dlc')
430def uprev_termina_dlc(_build_targets, _refs, chroot):
431 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600432
433 See: uprev_versioned_package.
434 """
Trent Begineb624182020-07-14 10:09:45 -0600435 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600436 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
437 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000438
439 version_pin_src_path = _get_version_pin_src_path(package_path)
440 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
441
Chris McDonald38409112020-09-24 11:24:51 -0600442 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000443
444
Julio Hurtadof1befec2021-05-05 21:34:26 +0000445@uprevs_versioned_package('chromeos-base/chromeos-lacros')
446def uprev_lacros(_build_targets, refs, chroot):
447 """Updates lacros ebuilds.
448
Julio Hurtadoa994e002021-07-07 17:57:45 +0000449 Version to uprev to is gathered from the QA qualified version tracking file
450 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
451 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000452
453 See: uprev_versioned_package.
454 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000455 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000456 path = os.path.join(
457 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base','chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000458 lacros_version = refs[0].revision
459 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
460 lacros_version,
461 chroot,
462 allow_downrev=False)
463
464 if not uprev_result:
465 return result
466
467 result.add_result(lacros_version, uprev_result.changed_files)
468 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000469
470
Patrick Meiring5897add2020-09-16 16:30:17 +1000471@uprevs_versioned_package('app-emulation/parallels-desktop')
472def uprev_parallels_desktop(_build_targets, _refs, chroot):
473 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
474
475 See: uprev_versioned_package
476
477 Returns:
478 UprevVersionedPackageResult: The result.
479 """
480 package = 'parallels-desktop'
481 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
482 'app-emulation', package)
483 version_pin_src_path = _get_version_pin_src_path(package_path)
484
485 # Expect a JSON blob like the following:
486 # {
487 # "version": "1.2.3",
488 # "test_image": { "url": "...", "size": 12345678,
489 # "sha256sum": "<32 bytes of hexadecimal>" }
490 # }
491 with open(version_pin_src_path, 'r') as f:
492 pinned = json.load(f)
493
494 if 'version' not in pinned or 'test_image' not in pinned:
495 raise UprevError('VERSION-PIN for %s missing version and/or '
496 'test_image field' % package)
497
498 version = pinned['version']
499 if not isinstance(version, str):
500 raise UprevError('version in VERSION-PIN for %s not a string' % package)
501
502 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600503 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000504
505 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100506 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
507 'local/bundles/crosint/pita/data/'
508 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000509 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
510 with open(test_image_src_path, 'w') as f:
511 json.dump(pinned['test_image'], f, indent=2)
512 result.add_result(version, [test_image_src_path])
513
514 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600515
516
Trent Begin315d9d92019-12-03 21:55:53 -0700517@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600518def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700519 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
520
521 See: uprev_versioned_package.
522 """
523 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700524 package_path = os.path.join('src', 'private-overlays',
525 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000526 version_pin_src_path = _get_version_pin_src_path(package_path)
527 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700528
Chris McDonald38409112020-09-24 11:24:51 -0600529 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700530
531
Patrick Meiring5897add2020-09-16 16:30:17 +1000532def _get_version_pin_src_path(package_path):
533 """Returns the path to the VERSION-PIN file for the given package."""
534 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
535
536
Alex Klein87531182019-08-12 15:23:37 -0600537@uprevs_versioned_package(constants.CHROME_CP)
Alex Kleinf69bd802021-06-22 15:43:49 -0600538def uprev_chrome_from_ref(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600539 """Uprev chrome and its related packages.
540
541 See: uprev_versioned_package.
542 """
543 # Determine the version from the refs (tags), i.e. the chrome versions are the
544 # tag names.
545 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600546 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600547
Alex Kleinf69bd802021-06-22 15:43:49 -0600548 return uprev_chrome(build_targets, chrome_version, chroot)
549
550
Alex Klein9ce3f682021-06-23 15:06:44 -0600551def revbump_chrome(
552 build_targets: List['build_target_lib.BuildTarget'],
553 chroot: Optional['chroot_lib.Chroot'] = None
554) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600555 """Attempt to revbump chrome.
556
557 Revbumps are done by executing an uprev using the current stable version.
558 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
559 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
560 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
561 """
562 chrome_version = uprev_lib.get_stable_chrome_version()
563 return uprev_chrome(build_targets, chrome_version, chroot)
564
565
Alex Klein9ce3f682021-06-23 15:06:44 -0600566def uprev_chrome(
567 build_targets: List['build_target_lib.BuildTarget'], chrome_version: str,
568 chroot: Union['chroot_lib.Chroot', None]
569) -> uprev_lib.UprevVersionedPackageResult:
570 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600571 uprev_manager = uprev_lib.UprevChromeManager(
572 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600573 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600574 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
575 # attempt. The expected behavior is documented in the following table:
576 #
577 # Outcome of Chrome uprev attempt:
578 # NEWER_VERSION_EXISTS:
579 # Do nothing.
580 # SAME_VERSION_EXISTS or REVISION_BUMP:
581 # Uprev followers
582 # Assert not VERSION_BUMP (any other outcome is fine)
583 # VERSION_BUMP or NEW_EBUILD_CREATED:
584 # Uprev followers
585 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600586
587 # Start with chrome itself so we can proceed accordingly.
588 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
589 if chrome_result.newer_version_exists:
590 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600591 return result
Alex Klein87531182019-08-12 15:23:37 -0600592
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600593 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600594 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600595 follower_result = uprev_manager.uprev(package)
596 if chrome_result.stable_version and follower_result.version_bump:
597 logging.warning('%s had a version bump, but no more than a revision bump '
598 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600599
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600600 if uprev_manager.modified_ebuilds:
601 # Record changes when we have them.
602 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
603
604 return result
Alex Klein87531182019-08-12 15:23:37 -0600605
606
Harvey Yang3eee06c2021-03-18 15:47:56 +0800607def _get_latest_version_from_refs(refs_prefix: str,
608 refs: List[uprev_lib.GitRef]) -> str:
609 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000610
Ben Reiche779cf42020-12-15 03:21:31 +0000611 Versions are compared using |distutils.version.LooseVersion| and
612 the latest version is returned.
613
614 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800615 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800616 refs: The tags to parse for the latest Perfetto version.
617
618 Returns:
619 The latest Perfetto version to use.
620 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800621 valid_refs = []
622 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800623 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800624 valid_refs.append(gitiles.ref)
625
626 if not valid_refs:
627 return None
628
629 # Sort by version and take the latest version.
630 target_version_ref = sorted(valid_refs,
631 key=LooseVersion,
632 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800633 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800634
635
Andrew Lamb9563a152019-12-04 11:42:18 -0700636def _generate_platform_c_files(replication_config, chroot):
637 """Generates platform C files from a platform JSON payload.
638
639 Args:
640 replication_config (replication_config_pb2.ReplicationConfig): A
641 ReplicationConfig that has already been run. If it produced a
642 build_config.json file, that file will be used to generate platform C
643 files. Otherwise, nothing will be generated.
644 chroot (chroot_lib.Chroot): The chroot to use to generate.
645
646 Returns:
647 A list of generated files.
648 """
649 # Generate the platform C files from the build config. Note that it would be
650 # more intuitive to generate the platform C files from the platform config;
651 # however, cros_config_schema does not allow this, because the platform config
652 # payload is not always valid input. For example, if a property is both
653 # 'required' and 'build-only', it will fail schema validation. Thus, use the
654 # build config, and use '-f' to filter.
655 build_config_path = [
656 rule.destination_path
657 for rule in replication_config.file_replication_rules
658 if rule.destination_path.endswith('build_config.json')
659 ]
660
661 if not build_config_path:
662 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700663 'No build_config.json found, will not generate platform C files. '
664 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700665 return []
666
667 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700668 raise ValueError('Expected at most one build_config.json destination path. '
669 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700670
671 build_config_path = build_config_path[0]
672
673 # Paths to the build_config.json and dir to output C files to, in the
674 # chroot.
675 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
676 build_config_path)
677 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
678 os.path.dirname(build_config_path))
679
680 command = [
681 'cros_config_schema', '-m', build_config_chroot_path, '-g',
682 generated_output_chroot_dir, '-f', '"TRUE"'
683 ]
684
685 cros_build_lib.run(
686 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
687
688 # A relative (to the source root) path to the generated C files.
689 generated_output_dir = os.path.dirname(build_config_path)
690 generated_files = []
691 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
692 for f in expected_c_files:
693 if os.path.exists(
694 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
695 generated_files.append(os.path.join(generated_output_dir, f))
696
697 if len(expected_c_files) != len(generated_files):
698 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
699
700 return generated_files
701
702
Andrew Lambe836f222019-12-09 12:27:38 -0700703def _get_private_overlay_package_root(ref, package):
704 """Returns the absolute path to the root of a given private overlay.
705
706 Args:
707 ref (uprev_lib.GitRef): GitRef for the private overlay.
708 package (str): Path to the package in the overlay.
709 """
710 # There might be a cleaner way to map from package -> path within the source
711 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700712 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700713 match = re.match(private_overlay_ref_pattern, ref.path)
714 if not match:
715 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
716 (private_overlay_ref_pattern, ref))
717
718 overlay = match.group(1)
719
720 return os.path.join(constants.SOURCE_ROOT,
721 'src/private-overlays/overlay-%s-private' % overlay,
722 package)
723
724
Andrew Lambea9a8a22019-12-12 14:03:43 -0700725@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
726def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700727 """Replicate a private cros_config change to the corresponding public config.
728
Alex Kleinad6b48a2020-01-08 16:57:41 -0700729 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700730 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700731 package = 'chromeos-base/chromeos-config-bsp'
732
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700733 if len(refs) != 1:
734 raise ValueError('Expected exactly one ref, actual %s' % refs)
735
736 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700737 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700738 replication_config_path = os.path.join(package_root,
739 'replication_config.jsonpb')
740
741 try:
742 replication_config = json_format.Parse(
743 osutils.ReadFile(replication_config_path),
744 replication_config_pb2.ReplicationConfig())
745 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700746 raise ValueError(
747 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700748
749 replication_lib.Replicate(replication_config)
750
751 modified_files = [
752 rule.destination_path
753 for rule in replication_config.file_replication_rules
754 ]
755
Andrew Lamb9563a152019-12-04 11:42:18 -0700756 # The generated platform C files are not easily filtered by replication rules,
757 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
758 # files cannot. Therefore, replicate and filter the JSON payloads, and then
759 # generate filtered C files from the JSON payload.
760 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700761
762 # Use the private repo's commit hash as the new version.
763 new_private_version = refs[0].revision
764
Andrew Lamb988f4da2019-12-10 10:16:43 -0700765 # modified_files should contain only relative paths at this point, but the
766 # returned UprevVersionedPackageResult must contain only absolute paths.
767 for i, modified_file in enumerate(modified_files):
768 assert not os.path.isabs(modified_file)
769 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
770
Chris McDonald38409112020-09-24 11:24:51 -0600771 return uprev_lib.UprevVersionedPackageResult().add_result(
772 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700773
774
Alex Kleinbbef2b32019-08-27 10:38:50 -0600775def get_best_visible(atom, build_target=None):
776 """Returns the best visible CPV for the given atom.
777
778 Args:
779 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600780 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600781 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700782
783 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600784 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600785 """
David Burger1e0fe232019-07-01 14:52:07 -0600786 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600787
788 board = build_target.name if build_target else None
789 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600790
791
Alex Klein149fd3b2019-12-16 16:01:05 -0700792def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600793 """Check if a prebuilt exists.
794
795 Args:
796 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600797 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600798 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700799 useflags: Any additional USE flags that should be set. May be a string
800 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700801
802 Returns:
803 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600804 """
805 assert atom
806
807 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700808 extra_env = None
809 if useflags:
810 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500811 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700812 new_flags = ' '.join(useflags)
813
814 existing = os.environ.get('USE', '')
815 final_flags = '%s %s' % (existing, new_flags)
816 extra_env = {'USE': final_flags.strip()}
817 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600818
819
David Burger0f9dd4e2019-10-08 12:33:42 -0600820def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600821 """Check if |build_target| builds |atom| (has it in its depgraph)."""
822 cros_build_lib.AssertInsideChroot()
823
Alex Kleind8cd4c62020-09-14 13:37:47 -0600824 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600825 # TODO(crbug/1081828): Receive and use sysroot.
826 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600827 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600828 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600829
830
Alex Klein6becabc2020-09-11 14:03:05 -0600831def needs_chrome_source(
832 build_target: 'build_target_lib.BuildTarget',
833 compile_source=False,
834 packages: Optional[List[package_info.PackageInfo]] = None,
835 useflags=None):
836 """Check if the chrome source is needed.
837
838 The chrome source is needed if the build target builds chrome or any of its
839 follower packages, and can't use a prebuilt for them either because it's not
840 available, or because we can't use prebuilts because it must build from
841 source.
842 """
843 cros_build_lib.AssertInsideChroot()
844
845 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700846 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600847 builds_chrome = constants.CHROME_CP in graph
848 builds_follower = {
849 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
850 }
851
Alex Klein9ce3f682021-06-23 15:06:44 -0600852 local_uprev = builds_chrome and revbump_chrome([build_target])
853
Alex Klein6becabc2020-09-11 14:03:05 -0600854 # When we are compiling source set False since we do not use prebuilts.
855 # When not compiling from source, start with True, i.e. we have every prebuilt
856 # we've checked for up to this point.
857 has_chrome_prebuilt = not compile_source
858 has_follower_prebuilts = not compile_source
859 # Save packages that need prebuilts for reporting.
860 pkgs_needing_prebuilts = []
861 if compile_source:
862 # Need everything.
863 pkgs_needing_prebuilts.append(constants.CHROME_CP)
864 pkgs_needing_prebuilts.extend(
865 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
866 else:
867 # Check chrome itself.
868 if builds_chrome:
869 has_chrome_prebuilt = has_prebuilt(
870 constants.CHROME_CP, build_target=build_target, useflags=useflags)
871 if not has_chrome_prebuilt:
872 pkgs_needing_prebuilts.append(constants.CHROME_CP)
873 # Check follower packages.
874 for pkg, builds_pkg in builds_follower.items():
875 if not builds_pkg:
876 continue
877 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
878 has_follower_prebuilts &= prebuilt
879 if not prebuilt:
880 pkgs_needing_prebuilts.append(pkg)
881 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
882 # reflect whether we actually have the corresponding prebuilts for the build.
883
884 needs_chrome = builds_chrome and not has_chrome_prebuilt
885 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
886
887 return NeedsChromeSourceResult(
888 needs_chrome_source=needs_chrome or needs_follower,
889 builds_chrome=builds_chrome,
890 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
891 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -0600892 missing_follower_prebuilt=not has_follower_prebuilts,
893 local_uprev=local_uprev,
894 )
Alex Klein6becabc2020-09-11 14:03:05 -0600895
896
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600897def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600898 """Returns the current Chrome version for the board (or in buildroot).
899
900 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600901 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700902
903 Returns:
904 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600905 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600906 # TODO(crbug/1019770): Long term we should not need the try/catch here once
907 # the builds function above only returns True for chrome when
908 # determine_chrome_version will succeed.
909 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700910 cpv = portage_util.PortageqBestVisible(
911 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600912 except cros_build_lib.RunCommandError as e:
913 # Return None because portage failed when trying to determine the chrome
914 # version.
915 logging.warning('Caught exception in determine_chrome_package: %s', e)
916 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600917 # Something like 78.0.3877.4_rc -> 78.0.3877.4
918 return cpv.version_no_rev.partition('_')[0]
919
920
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600921def determine_android_package(board):
922 """Returns the active Android container package in use by the board.
923
924 Args:
925 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700926
927 Returns:
928 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600929 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600930 try:
931 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600932 except cros_build_lib.RunCommandError as e:
933 # Return None because a command (likely portage) failed when trying to
934 # determine the package.
935 logging.warning('Caught exception in determine_android_package: %s', e)
936 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600937
Alex Kleinad6b48a2020-01-08 16:57:41 -0700938 # We assume there is only one Android package in the depgraph.
939 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400940 if (package.startswith('chromeos-base/android-container-') or
941 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700942 return package
943 return None
944
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600945
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500946def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600947 """Determine the current Android version in buildroot now and return it.
948
949 This uses the typical portage logic to determine which version of Android
950 is active right now in the buildroot.
951
952 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500953 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500954 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600955
956 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500957 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600958
959 Raises:
960 NoAndroidVersionError: if no unique Android version can be determined.
961 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500962 if not package:
963 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500964 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600965 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500966 cpv = package_info.SplitCPV(package)
967 if not cpv:
968 raise NoAndroidVersionError(
969 'Android version could not be determined for %s' % board)
970 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600971
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700972
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500973def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600974 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500975 if not package:
976 package = determine_android_package(board)
977 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600978 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500979 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600980 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900981 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900982 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600983 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
984 for target in targets:
985 if target in ebuild_content:
986 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
987 if branch is not None:
988 return branch.group(1)
989 raise NoAndroidBranchError(
990 'Android branch could not be determined for %s (ebuild empty?)' % board)
991
992
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500993def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600994 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500995 if not package:
996 package = determine_android_package(board)
997 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600998 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500999 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001000 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001001 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001002 return 'cheets'
1003
1004 raise NoAndroidTargetError(
1005 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001006 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001007
1008
1009def determine_platform_version():
1010 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001011 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001012 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1013 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001014
1015
1016def determine_milestone_version():
1017 """Returns the platform version from the source root."""
1018 # Milestone version is something like '79'.
1019 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1020 return version.chrome_branch
1021
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001022
Michael Mortensen009cb662019-10-21 11:38:43 -06001023def determine_full_version():
1024 """Returns the full version from the source root."""
1025 # Full version is something like 'R79-12575.0.0'.
1026 milestone_version = determine_milestone_version()
1027 platform_version = determine_platform_version()
1028 full_version = ('R%s-%s' % (milestone_version, platform_version))
1029 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001030
1031
Michael Mortensende716a12020-05-15 11:27:00 -06001032def find_fingerprints(build_target):
1033 """Returns a list of fingerprints for this build.
1034
1035 Args:
1036 build_target (build_target_lib.BuildTarget): The build target.
1037
1038 Returns:
1039 list[str] - List of fingerprint strings.
1040 """
1041 cros_build_lib.AssertInsideChroot()
1042 fp_file = 'cheets-fingerprint.txt'
1043 fp_path = os.path.join(
1044 image_lib.GetLatestImageLink(build_target.name),
1045 fp_file)
1046 if not os.path.isfile(fp_path):
1047 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001048 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001049 logging.info('Reading fingerprint file: %s', fp_path)
1050 fingerprints = osutils.ReadFile(fp_path).splitlines()
1051 return fingerprints
1052
1053
Michael Mortensen59e30872020-05-18 14:12:49 -06001054def get_all_firmware_versions(build_target):
1055 """Extract firmware version for all models present.
1056
1057 Args:
1058 build_target (build_target_lib.BuildTarget): The build target.
1059
1060 Returns:
1061 A dict of FirmwareVersions namedtuple instances by model.
1062 Each element will be populated based on whether it was present in the
1063 command output.
1064 """
1065 cros_build_lib.AssertInsideChroot()
1066 result = {}
1067 # Note that example output for _get_firmware_version_cmd_result is available
1068 # in the packages_unittest.py for testing get_all_firmware_versions.
1069 cmd_result = _get_firmware_version_cmd_result(build_target)
1070
1071 # There is a blank line between the version info for each model.
1072 firmware_version_payloads = cmd_result.split('\n\n')
1073 for firmware_version_payload in firmware_version_payloads:
1074 if 'BIOS' in firmware_version_payload:
1075 firmware_version = _find_firmware_versions(firmware_version_payload)
1076 result[firmware_version.model] = firmware_version
1077 return result
1078
1079
Michael Mortensen71ef5682020-05-07 14:29:24 -06001080FirmwareVersions = collections.namedtuple(
1081 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1082
1083
1084def get_firmware_versions(build_target):
1085 """Extract version information from the firmware updater, if one exists.
1086
1087 Args:
1088 build_target (build_target_lib.BuildTarget): The build target.
1089
1090 Returns:
1091 A FirmwareVersions namedtuple instance.
1092 Each element will either be set to the string output by the firmware
1093 updater shellball, or None if there is no firmware updater.
1094 """
1095 cros_build_lib.AssertInsideChroot()
1096 cmd_result = _get_firmware_version_cmd_result(build_target)
1097 if cmd_result:
1098 return _find_firmware_versions(cmd_result)
1099 else:
1100 return FirmwareVersions(None, None, None, None, None)
1101
1102
1103def _get_firmware_version_cmd_result(build_target):
1104 """Gets the raw result output of the firmware updater version command.
1105
1106 Args:
1107 build_target (build_target_lib.BuildTarget): The build target.
1108
1109 Returns:
1110 Command execution result.
1111 """
1112 updater = os.path.join(build_target.root,
1113 'usr/sbin/chromeos-firmwareupdate')
1114 logging.info('Calling updater %s', updater)
1115 # Call the updater using the chroot-based path.
1116 return cros_build_lib.run([updater, '-V'],
1117 capture_output=True, log_output=True,
1118 encoding='utf-8').stdout
1119
1120
1121def _find_firmware_versions(cmd_output):
1122 """Finds firmware version output via regex matches against the cmd_output.
1123
1124 Args:
1125 cmd_output: The raw output to search against.
1126
1127 Returns:
1128 FirmwareVersions namedtuple with results.
1129 Each element will either be set to the string output by the firmware
1130 updater shellball, or None if there is no match.
1131 """
1132
1133 # Sometimes a firmware bundle includes a special combination of RO+RW
1134 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1135 # version" field. In other cases, the "(RW) version" field is not present.
1136 # Therefore, search for the "(RW)" fields first and if they aren't present,
1137 # fallback to the other format. e.g. just "BIOS version:".
1138 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1139 main = None
1140 main_rw = None
1141 ec = None
1142 ec_rw = None
1143 model = None
1144
1145 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1146 if match:
1147 main = match.group('version')
1148
1149 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1150 if match:
1151 main_rw = match.group('version')
1152
1153 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1154 if match:
1155 ec = match.group('version')
1156
1157 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1158 if match:
1159 ec_rw = match.group('version')
1160
1161 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1162 if match:
1163 model = match.group('model')
1164
1165 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001166
1167
1168MainEcFirmwareVersions = collections.namedtuple(
1169 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1170
1171def determine_firmware_versions(build_target):
1172 """Returns a namedtuple with main and ec firmware versions.
1173
1174 Args:
1175 build_target (build_target_lib.BuildTarget): The build target.
1176
1177 Returns:
1178 MainEcFirmwareVersions namedtuple with results.
1179 """
1180 fw_versions = get_firmware_versions(build_target)
1181 main_fw_version = fw_versions.main_rw or fw_versions.main
1182 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1183
1184 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001185
1186def determine_kernel_version(build_target):
1187 """Returns a string containing the kernel version for this build target.
1188
1189 Args:
1190 build_target (build_target_lib.BuildTarget): The build target.
1191
1192 Returns:
1193 (str) The kernel versions, or None.
1194 """
1195 try:
1196 packages = portage_util.GetPackageDependencies(build_target.name,
1197 'virtual/linux-sources')
1198 except cros_build_lib.RunCommandError as e:
1199 logging.warning('Unable to get package list for metadata: %s', e)
1200 return None
1201 for package in packages:
1202 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001203 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001204 logging.info('Found active kernel version: %s', kernel_version)
1205 return kernel_version
1206 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001207
1208
1209def get_models(build_target, log_output=True):
1210 """Obtain a list of models supported by a unified board.
1211
1212 This ignored whitelabel models since GoldenEye has no specific support for
1213 these at present.
1214
1215 Args:
1216 build_target (build_target_lib.BuildTarget): The build target.
1217 log_output: Whether to log the output of the cros_config_host invocation.
1218
1219 Returns:
1220 A list of models supported by this board, if it is a unified build; None,
1221 if it is not a unified build.
1222 """
1223 return _run_cros_config_host(build_target, ['list-models'],
1224 log_output=log_output)
1225
1226
Michael Mortensen359c1f32020-05-28 19:35:42 -06001227def get_key_id(build_target, model):
1228 """Obtain the key_id for a model within the build_target.
1229
1230 Args:
1231 build_target (build_target_lib.BuildTarget): The build target.
1232 model (str): The model name
1233
1234 Returns:
1235 A key_id (str) or None.
1236 """
1237 model_arg = '--model=' + model
1238 key_id_list = _run_cros_config_host(
1239 build_target,
1240 [model_arg, 'get', '/firmware-signing', 'key-id'])
1241 key_id = None
1242 if len(key_id_list) == 1:
1243 key_id = key_id_list[0]
1244 return key_id
1245
1246
Michael Mortensen125bb012020-05-21 14:02:10 -06001247def _run_cros_config_host(build_target, args, log_output=True):
1248 """Run the cros_config_host tool.
1249
1250 Args:
1251 build_target (build_target_lib.BuildTarget): The build target.
1252 args: List of arguments to pass.
1253 log_output: Whether to log the output of the cros_config_host.
1254
1255 Returns:
1256 Output of the tool
1257 """
1258 cros_build_lib.AssertInsideChroot()
1259 tool = '/usr/bin/cros_config_host'
1260 if not os.path.isfile(tool):
1261 return None
1262
1263 config_fname = build_target.full_path(
1264 'usr/share/chromeos-config/yaml/config.yaml')
1265
1266 result = cros_build_lib.run(
1267 [tool, '-c', config_fname] + args,
1268 capture_output=True,
1269 encoding='utf-8',
1270 log_output=log_output,
1271 check=False)
1272 if result.returncode:
1273 # Show the output for debugging purposes.
1274 if 'No such file or directory' not in result.error:
1275 logging.error('cros_config_host failed: %s\n', result.error)
1276 return None
1277 return result.output.strip().splitlines()