blob: a0f2b956ca9fa5d66a320dfcb869f5f30bed1e94 [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Package utility functionality."""
6
Yaakov Shaul730814a2019-09-10 13:58:25 -06007import collections
Ben Reiche779cf42020-12-15 03:21:31 +00008from distutils.version import LooseVersion
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -06009import fileinput
Alex Klein87531182019-08-12 15:23:37 -060010import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060011import json
Chris McDonaldf7c03d42021-07-21 11:54:26 -060012import logging
Evan Hernandezb51f1522019-08-15 11:29:40 -060013import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060014import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060015import sys
Alex Klein9ce3f682021-06-23 15:06:44 -060016from typing import List, Optional, Union
Alex Klein87531182019-08-12 15:23:37 -060017
Mike Frysinger2c024062021-05-22 15:43:22 -040018from chromite.third_party.google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060019
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060021from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060022from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060023from chromite.lib import cros_build_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060025from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060026from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070028from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060029from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060030from chromite.lib.parser import package_info
Alex Kleineb77ffa2019-05-28 14:47:44 -060031
Chris McDonaldf7c03d42021-07-21 11:54:26 -060032
Alex Klein36b117f2019-09-30 15:13:46 -060033if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060034 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060035 from chromite.service import dependency
36
Alex Klein87531182019-08-12 15:23:37 -060037# Registered handlers for uprevving versioned packages.
38_UPREV_FUNCS = {}
39
Alex Kleineb77ffa2019-05-28 14:47:44 -060040
41class Error(Exception):
42 """Module's base error class."""
43
44
Alex Klein4de25e82019-08-05 15:58:39 -060045class UnknownPackageError(Error):
46 """Uprev attempted for a package without a registered handler."""
47
48
Alex Kleineb77ffa2019-05-28 14:47:44 -060049class UprevError(Error):
50 """An error occurred while uprevving packages."""
51
52
Michael Mortensenb70e8a82019-10-10 18:43:41 -060053class NoAndroidVersionError(Error):
54 """An error occurred while trying to determine the android version."""
55
56
57class NoAndroidBranchError(Error):
58 """An error occurred while trying to determine the android branch."""
59
60
61class NoAndroidTargetError(Error):
62 """An error occurred while trying to determine the android target."""
63
64
Alex Klein4de25e82019-08-05 15:58:39 -060065class AndroidIsPinnedUprevError(UprevError):
66 """Raised when we try to uprev while Android is pinned."""
67
68 def __init__(self, new_android_atom):
69 """Initialize a AndroidIsPinnedUprevError.
70
71 Args:
72 new_android_atom: The Android atom that we failed to
73 uprev to, due to Android being pinned.
74 """
75 assert new_android_atom
76 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
77 new_android_atom)
Jae Hoon Kimad176b82021-07-26 19:29:29 +000078 super().__init__(msg)
Alex Klein4de25e82019-08-05 15:58:39 -060079 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060080
81
Andrew Lamb9563a152019-12-04 11:42:18 -070082class GeneratedCrosConfigFilesError(Error):
83 """Error when cros_config_schema does not produce expected files"""
84
85 def __init__(self, expected_files, found_files):
86 msg = ('Expected to find generated C files: %s. Actually found: %s' %
87 (expected_files, found_files))
Jae Hoon Kimad176b82021-07-26 19:29:29 +000088 super().__init__(msg)
Andrew Lamb9563a152019-12-04 11:42:18 -070089
Alex Klein7a3a7dd2020-01-08 16:44:38 -070090
Alex Klein6becabc2020-09-11 14:03:05 -060091NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
92 'needs_chrome_source',
93 'builds_chrome',
94 'packages',
95 'missing_chrome_prebuilt',
96 'missing_follower_prebuilt',
Alex Klein9ce3f682021-06-23 15:06:44 -060097 'local_uprev',
Alex Klein6becabc2020-09-11 14:03:05 -060098))
99
100
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600101def patch_ebuild_vars(ebuild_path, variables):
102 """Updates variables in ebuild.
103
104 Use this function rather than portage_util.EBuild.UpdateEBuild when you
105 want to preserve the variable position and quotes within the ebuild.
106
107 Args:
108 ebuild_path: The path of the ebuild.
109 variables: Dictionary of variables to update in ebuild.
110 """
111 try:
112 for line in fileinput.input(ebuild_path, inplace=1):
113 varname, eq, _ = line.partition('=')
114 if eq == '=' and varname.strip() in variables:
115 value = variables[varname]
116 sys.stdout.write('%s="%s"\n' % (varname, value))
117 else:
118 sys.stdout.write(line)
119 finally:
120 fileinput.close()
121
122
Alex Klein87531182019-08-12 15:23:37 -0600123def uprevs_versioned_package(package):
124 """Decorator to register package uprev handlers."""
125 assert package
126
127 def register(func):
128 """Registers |func| as a handler for |package|."""
129 _UPREV_FUNCS[package] = func
130
131 @functools.wraps(func)
132 def pass_through(*args, **kwargs):
133 return func(*args, **kwargs)
134
135 return pass_through
136
137 return register
138
139
Shao-Chuan Leeb6a2cb62021-02-19 14:18:59 +0900140def uprev_android(android_package,
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700141 chroot,
142 build_targets=None,
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900143 android_build_branch=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900144 android_version=None,
145 skip_commit=False):
Alex Klein4de25e82019-08-05 15:58:39 -0600146 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700147 command = [
148 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900149 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700150 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600151 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900152 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900153 if android_build_branch:
154 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600155 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900156 command.append(f'--force_version={android_version}')
157 if skip_commit:
158 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600159
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700160 result = cros_build_lib.run(
161 command,
162 stdout=True,
163 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500164 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700165 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600166
Mike Frysinger88d96362020-02-14 19:05:45 -0500167 portage_atom_string = result.stdout.strip()
168 android_atom = None
169 if portage_atom_string:
170 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600171 if not android_atom:
172 logging.info('Found nothing to rev.')
173 return None
174
175 for target in build_targets or []:
176 # Sanity check: We should always be able to merge the version of
177 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900178 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600179 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700180 cros_build_lib.run(
181 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600182 except cros_build_lib.RunCommandError:
183 logging.error(
184 'Cannot emerge-%s =%s\nIs Android pinned to an older '
185 'version?', target, android_atom)
186 raise AndroidIsPinnedUprevError(android_atom)
187
188 return android_atom
189
190
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700191def uprev_build_targets(build_targets,
192 overlay_type,
193 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600194 output_dir=None):
195 """Uprev the set provided build targets, or all if not specified.
196
197 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600198 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600199 whose overlays should be uprevved, empty or None for all.
200 overlay_type (str): One of the valid overlay types except None (see
201 constants.VALID_OVERLAYS).
202 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
203 output_dir (str|None): The path to optionally dump result files.
204 """
205 # Need a valid overlay, but exclude None.
206 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
207
208 if build_targets:
209 overlays = portage_util.FindOverlaysForBoards(
210 overlay_type, boards=[t.name for t in build_targets])
211 else:
212 overlays = portage_util.FindOverlays(overlay_type)
213
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700214 return uprev_overlays(
215 overlays,
216 build_targets=build_targets,
217 chroot=chroot,
218 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600219
220
221def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
222 """Uprev the given overlays.
223
224 Args:
225 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600226 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600227 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
228 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
229 output_dir (str|None): The path to optionally dump result files.
230
231 Returns:
232 list[str] - The paths to all of the modified ebuild files. This includes the
233 new files that were added (i.e. the new versions) and all of the removed
234 files (i.e. the old versions).
235 """
236 assert overlays
237
238 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
239
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700240 uprev_manager = uprev_lib.UprevOverlayManager(
241 overlays,
242 manifest,
243 build_targets=build_targets,
244 chroot=chroot,
245 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600246 uprev_manager.uprev()
247
248 return uprev_manager.modified_ebuilds
249
250
Alex Klein87531182019-08-12 15:23:37 -0600251def uprev_versioned_package(package, build_targets, refs, chroot):
252 """Call registered uprev handler function for the package.
253
254 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600255 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600256 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600257 clean on a successful uprev.
258 refs (list[uprev_lib.GitRef]):
259 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
260
261 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600262 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600263 """
264 assert package
265
266 if package.cp not in _UPREV_FUNCS:
267 raise UnknownPackageError(
268 'Package "%s" does not have a registered handler.' % package.cp)
269
Andrew Lambea9a8a22019-12-12 14:03:43 -0700270 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600271
272
Navil Perezf57ba872020-06-04 22:38:37 +0000273@uprevs_versioned_package('media-libs/virglrenderer')
274def uprev_virglrenderer(_build_targets, refs, _chroot):
275 """Updates virglrenderer ebuilds.
276
277 See: uprev_versioned_package.
278
279 Returns:
280 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
281 """
Navil Perezf57ba872020-06-04 22:38:37 +0000282 overlay = os.path.join(constants.SOURCE_ROOT,
283 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600284 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
285 'virglrenderer')
286 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000287
288 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
289 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000290 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
291 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000292 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
293
George Engelbrechte73f2782020-06-10 14:10:46 -0600294 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600295 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000296 result.add_result(refs[0].revision, updated_files)
297 return result
298
Jose Magana03b5a842020-08-19 12:52:59 +1000299@uprevs_versioned_package('chromeos-base/drivefs')
300def uprev_drivefs(_build_targets, refs, chroot):
301 """Updates drivefs ebuilds.
302
Harvey Yang3eee06c2021-03-18 15:47:56 +0800303 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000304 See: uprev_versioned_package.
305
306 Returns:
307 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
308 """
309
Ben Reiche779cf42020-12-15 03:21:31 +0000310 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000311 result = uprev_lib.UprevVersionedPackageResult()
312 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000313
Harvey Yang3eee06c2021-03-18 15:47:56 +0800314 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
315 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000316 if not drivefs_version:
317 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000318 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000319
Ben Reiche779cf42020-12-15 03:21:31 +0000320 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000321
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000322 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000323 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000324 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000325 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800326 chroot,
327 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000328
329 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000330 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000331 all_changed_files.extend(uprev_result.changed_files)
332
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000333 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000334 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000335 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000336 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800337 chroot,
338 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000339
340 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000341 logging.warning(
342 'drivefs package has changed files %s but drivefs-ipc does not',
343 all_changed_files)
344 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000345
346 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000347 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000348
349 return result
350
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800351@uprevs_versioned_package('chromeos-base/perfetto')
352def uprev_perfetto(_build_targets, refs, chroot):
353 """Updates Perfetto ebuilds.
354
Harvey Yang3eee06c2021-03-18 15:47:56 +0800355 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800356 See: uprev_versioned_package.
357
358 Returns:
359 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
360 """
361 result = uprev_lib.UprevVersionedPackageResult()
362
Harvey Yang3eee06c2021-03-18 15:47:56 +0800363 PERFETTO_REFS_PREFIX = 'refs/tags/v'
364 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800365 if not perfetto_version:
366 # No valid Perfetto version is identified.
367 return result
368
369 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
370
371 # Attempt to uprev perfetto package.
372 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
373
Harvey Yang3eee06c2021-03-18 15:47:56 +0800374 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
375 PERFETTO_PATH,
376 perfetto_version,
377 chroot,
378 allow_downrev=False,
379 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800380
381 if not uprev_result:
382 return result
383
384 result.add_result(perfetto_version, uprev_result.changed_files)
385
386 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000387
Yaakov Shaul395ae832019-09-09 14:45:32 -0600388@uprevs_versioned_package('afdo/kernel-profiles')
389def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600390 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600391
392 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600393
394 Raises:
395 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600396 """
397 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
398 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
399
David Burger92485342019-09-10 17:52:45 -0600400 with open(path, 'r') as f:
401 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600402
Chris McDonald38409112020-09-24 11:24:51 -0600403 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein6edd4e62021-07-08 12:43:25 -0600404 for kernel_pkg, version_info in versions.items():
405 path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
406 'sys-kernel', kernel_pkg)
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600407 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600408 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaula187b152019-09-11 12:41:32 -0600409 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
Alex Klein6edd4e62021-07-08 12:43:25 -0600410 '%s-9999.ebuild' % kernel_pkg)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600411 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600412 patch_ebuild_vars(ebuild_path,
413 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600414
415 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600416 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400417 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600418 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600419 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600420 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600421 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600422
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600423 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600424
Yaakov Shaul730814a2019-09-10 13:58:25 -0600425 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
426
427 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600428
429
Trent Begineb624182020-07-14 10:09:45 -0600430@uprevs_versioned_package('chromeos-base/termina-dlc')
431def uprev_termina_dlc(_build_targets, _refs, chroot):
432 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600433
434 See: uprev_versioned_package.
435 """
Trent Begineb624182020-07-14 10:09:45 -0600436 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600437 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
438 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000439
440 version_pin_src_path = _get_version_pin_src_path(package_path)
441 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
442
Chris McDonald38409112020-09-24 11:24:51 -0600443 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000444
445
Julio Hurtadof1befec2021-05-05 21:34:26 +0000446@uprevs_versioned_package('chromeos-base/chromeos-lacros')
447def uprev_lacros(_build_targets, refs, chroot):
448 """Updates lacros ebuilds.
449
Julio Hurtadoa994e002021-07-07 17:57:45 +0000450 Version to uprev to is gathered from the QA qualified version tracking file
451 stored in chromium/src/chrome/LACROS_QA_QUALIFIED_VERSION. Uprev is triggered
452 on modification of this file across all chromium/src branches.
Julio Hurtadof1befec2021-05-05 21:34:26 +0000453
454 See: uprev_versioned_package.
455 """
Julio Hurtadoa994e002021-07-07 17:57:45 +0000456 result = uprev_lib.UprevVersionedPackageResult()
Julio Hurtadof1befec2021-05-05 21:34:26 +0000457 path = os.path.join(
458 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base','chromeos-lacros')
Julio Hurtadoa994e002021-07-07 17:57:45 +0000459 lacros_version = refs[0].revision
460 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
461 lacros_version,
462 chroot,
463 allow_downrev=False)
464
465 if not uprev_result:
466 return result
467
468 result.add_result(lacros_version, uprev_result.changed_files)
469 return result
Julio Hurtadof1befec2021-05-05 21:34:26 +0000470
471
Patrick Meiring5897add2020-09-16 16:30:17 +1000472@uprevs_versioned_package('app-emulation/parallels-desktop')
473def uprev_parallels_desktop(_build_targets, _refs, chroot):
474 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
475
476 See: uprev_versioned_package
477
478 Returns:
479 UprevVersionedPackageResult: The result.
480 """
481 package = 'parallels-desktop'
482 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
483 'app-emulation', package)
484 version_pin_src_path = _get_version_pin_src_path(package_path)
485
486 # Expect a JSON blob like the following:
487 # {
488 # "version": "1.2.3",
489 # "test_image": { "url": "...", "size": 12345678,
490 # "sha256sum": "<32 bytes of hexadecimal>" }
491 # }
492 with open(version_pin_src_path, 'r') as f:
493 pinned = json.load(f)
494
495 if 'version' not in pinned or 'test_image' not in pinned:
496 raise UprevError('VERSION-PIN for %s missing version and/or '
497 'test_image field' % package)
498
499 version = pinned['version']
500 if not isinstance(version, str):
501 raise UprevError('version in VERSION-PIN for %s not a string' % package)
502
503 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600504 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000505
506 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100507 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
508 'local/bundles/crosint/pita/data/'
509 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000510 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
511 with open(test_image_src_path, 'w') as f:
512 json.dump(pinned['test_image'], f, indent=2)
513 result.add_result(version, [test_image_src_path])
514
515 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600516
517
Trent Begin315d9d92019-12-03 21:55:53 -0700518@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600519def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700520 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
521
522 See: uprev_versioned_package.
523 """
524 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700525 package_path = os.path.join('src', 'private-overlays',
526 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000527 version_pin_src_path = _get_version_pin_src_path(package_path)
528 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700529
Chris McDonald38409112020-09-24 11:24:51 -0600530 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700531
532
Patrick Meiring5897add2020-09-16 16:30:17 +1000533def _get_version_pin_src_path(package_path):
534 """Returns the path to the VERSION-PIN file for the given package."""
535 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
536
537
Alex Klein87531182019-08-12 15:23:37 -0600538@uprevs_versioned_package(constants.CHROME_CP)
Alex Kleinf69bd802021-06-22 15:43:49 -0600539def uprev_chrome_from_ref(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600540 """Uprev chrome and its related packages.
541
542 See: uprev_versioned_package.
543 """
544 # Determine the version from the refs (tags), i.e. the chrome versions are the
545 # tag names.
546 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600547 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600548
Alex Kleinf69bd802021-06-22 15:43:49 -0600549 return uprev_chrome(build_targets, chrome_version, chroot)
550
551
Alex Klein9ce3f682021-06-23 15:06:44 -0600552def revbump_chrome(
553 build_targets: List['build_target_lib.BuildTarget'],
554 chroot: Optional['chroot_lib.Chroot'] = None
555) -> uprev_lib.UprevVersionedPackageResult:
Alex Kleinf69bd802021-06-22 15:43:49 -0600556 """Attempt to revbump chrome.
557
558 Revbumps are done by executing an uprev using the current stable version.
559 E.g. if chrome is on 1.2.3.4 and has a 1.2.3.4_rc-r2.ebuild, performing an
560 uprev on version 1.2.3.4 when there are applicable changes (e.g. to the 9999
561 ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
562 """
563 chrome_version = uprev_lib.get_stable_chrome_version()
564 return uprev_chrome(build_targets, chrome_version, chroot)
565
566
Alex Klein9ce3f682021-06-23 15:06:44 -0600567def uprev_chrome(
568 build_targets: List['build_target_lib.BuildTarget'], chrome_version: str,
569 chroot: Union['chroot_lib.Chroot', None]
570) -> uprev_lib.UprevVersionedPackageResult:
571 """Attempt to uprev chrome and its related packages to the given version."""
Alex Klein87531182019-08-12 15:23:37 -0600572 uprev_manager = uprev_lib.UprevChromeManager(
573 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600574 result = uprev_lib.UprevVersionedPackageResult()
Chris McDonald25881af2020-05-12 03:17:53 -0600575 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
576 # attempt. The expected behavior is documented in the following table:
577 #
578 # Outcome of Chrome uprev attempt:
579 # NEWER_VERSION_EXISTS:
580 # Do nothing.
581 # SAME_VERSION_EXISTS or REVISION_BUMP:
582 # Uprev followers
583 # Assert not VERSION_BUMP (any other outcome is fine)
584 # VERSION_BUMP or NEW_EBUILD_CREATED:
585 # Uprev followers
586 # Assert that Chrome & followers are at same package version
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600587
588 # Start with chrome itself so we can proceed accordingly.
589 chrome_result = uprev_manager.uprev(constants.CHROME_CP)
590 if chrome_result.newer_version_exists:
591 # Cannot use the given version (newer version already exists).
David Burger37f48672019-09-18 17:07:56 -0600592 return result
Alex Klein87531182019-08-12 15:23:37 -0600593
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600594 # Also uprev related packages.
Alex Klein87531182019-08-12 15:23:37 -0600595 for package in constants.OTHER_CHROME_PACKAGES:
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600596 follower_result = uprev_manager.uprev(package)
597 if chrome_result.stable_version and follower_result.version_bump:
598 logging.warning('%s had a version bump, but no more than a revision bump '
599 'should have been possible.', package)
Alex Klein87531182019-08-12 15:23:37 -0600600
Alex Klein0b2ec2d2021-06-23 15:56:45 -0600601 if uprev_manager.modified_ebuilds:
602 # Record changes when we have them.
603 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
604
605 return result
Alex Klein87531182019-08-12 15:23:37 -0600606
607
Harvey Yang3eee06c2021-03-18 15:47:56 +0800608def _get_latest_version_from_refs(refs_prefix: str,
609 refs: List[uprev_lib.GitRef]) -> str:
610 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000611
Ben Reiche779cf42020-12-15 03:21:31 +0000612 Versions are compared using |distutils.version.LooseVersion| and
613 the latest version is returned.
614
615 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800616 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800617 refs: The tags to parse for the latest Perfetto version.
618
619 Returns:
620 The latest Perfetto version to use.
621 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800622 valid_refs = []
623 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800624 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800625 valid_refs.append(gitiles.ref)
626
627 if not valid_refs:
628 return None
629
630 # Sort by version and take the latest version.
631 target_version_ref = sorted(valid_refs,
632 key=LooseVersion,
633 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800634 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800635
636
Andrew Lamb9563a152019-12-04 11:42:18 -0700637def _generate_platform_c_files(replication_config, chroot):
638 """Generates platform C files from a platform JSON payload.
639
640 Args:
641 replication_config (replication_config_pb2.ReplicationConfig): A
642 ReplicationConfig that has already been run. If it produced a
643 build_config.json file, that file will be used to generate platform C
644 files. Otherwise, nothing will be generated.
645 chroot (chroot_lib.Chroot): The chroot to use to generate.
646
647 Returns:
648 A list of generated files.
649 """
650 # Generate the platform C files from the build config. Note that it would be
651 # more intuitive to generate the platform C files from the platform config;
652 # however, cros_config_schema does not allow this, because the platform config
653 # payload is not always valid input. For example, if a property is both
654 # 'required' and 'build-only', it will fail schema validation. Thus, use the
655 # build config, and use '-f' to filter.
656 build_config_path = [
657 rule.destination_path
658 for rule in replication_config.file_replication_rules
659 if rule.destination_path.endswith('build_config.json')
660 ]
661
662 if not build_config_path:
663 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700664 'No build_config.json found, will not generate platform C files. '
665 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700666 return []
667
668 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700669 raise ValueError('Expected at most one build_config.json destination path. '
670 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700671
672 build_config_path = build_config_path[0]
673
674 # Paths to the build_config.json and dir to output C files to, in the
675 # chroot.
676 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
677 build_config_path)
678 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
679 os.path.dirname(build_config_path))
680
681 command = [
682 'cros_config_schema', '-m', build_config_chroot_path, '-g',
683 generated_output_chroot_dir, '-f', '"TRUE"'
684 ]
685
686 cros_build_lib.run(
687 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
688
689 # A relative (to the source root) path to the generated C files.
690 generated_output_dir = os.path.dirname(build_config_path)
691 generated_files = []
692 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
693 for f in expected_c_files:
694 if os.path.exists(
695 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
696 generated_files.append(os.path.join(generated_output_dir, f))
697
698 if len(expected_c_files) != len(generated_files):
699 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
700
701 return generated_files
702
703
Andrew Lambe836f222019-12-09 12:27:38 -0700704def _get_private_overlay_package_root(ref, package):
705 """Returns the absolute path to the root of a given private overlay.
706
707 Args:
708 ref (uprev_lib.GitRef): GitRef for the private overlay.
709 package (str): Path to the package in the overlay.
710 """
711 # There might be a cleaner way to map from package -> path within the source
712 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700713 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700714 match = re.match(private_overlay_ref_pattern, ref.path)
715 if not match:
716 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
717 (private_overlay_ref_pattern, ref))
718
719 overlay = match.group(1)
720
721 return os.path.join(constants.SOURCE_ROOT,
722 'src/private-overlays/overlay-%s-private' % overlay,
723 package)
724
725
Andrew Lambea9a8a22019-12-12 14:03:43 -0700726@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
727def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700728 """Replicate a private cros_config change to the corresponding public config.
729
Alex Kleinad6b48a2020-01-08 16:57:41 -0700730 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700731 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700732 package = 'chromeos-base/chromeos-config-bsp'
733
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700734 if len(refs) != 1:
735 raise ValueError('Expected exactly one ref, actual %s' % refs)
736
737 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700738 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700739 replication_config_path = os.path.join(package_root,
740 'replication_config.jsonpb')
741
742 try:
743 replication_config = json_format.Parse(
744 osutils.ReadFile(replication_config_path),
745 replication_config_pb2.ReplicationConfig())
746 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700747 raise ValueError(
748 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700749
750 replication_lib.Replicate(replication_config)
751
752 modified_files = [
753 rule.destination_path
754 for rule in replication_config.file_replication_rules
755 ]
756
Andrew Lamb9563a152019-12-04 11:42:18 -0700757 # The generated platform C files are not easily filtered by replication rules,
758 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
759 # files cannot. Therefore, replicate and filter the JSON payloads, and then
760 # generate filtered C files from the JSON payload.
761 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700762
763 # Use the private repo's commit hash as the new version.
764 new_private_version = refs[0].revision
765
Andrew Lamb988f4da2019-12-10 10:16:43 -0700766 # modified_files should contain only relative paths at this point, but the
767 # returned UprevVersionedPackageResult must contain only absolute paths.
768 for i, modified_file in enumerate(modified_files):
769 assert not os.path.isabs(modified_file)
770 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
771
Chris McDonald38409112020-09-24 11:24:51 -0600772 return uprev_lib.UprevVersionedPackageResult().add_result(
773 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700774
775
Alex Kleinbbef2b32019-08-27 10:38:50 -0600776def get_best_visible(atom, build_target=None):
777 """Returns the best visible CPV for the given atom.
778
779 Args:
780 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600781 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600782 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700783
784 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600785 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600786 """
David Burger1e0fe232019-07-01 14:52:07 -0600787 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600788
789 board = build_target.name if build_target else None
790 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600791
792
Alex Klein149fd3b2019-12-16 16:01:05 -0700793def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600794 """Check if a prebuilt exists.
795
796 Args:
797 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600798 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600799 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700800 useflags: Any additional USE flags that should be set. May be a string
801 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700802
803 Returns:
804 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600805 """
806 assert atom
807
808 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700809 extra_env = None
810 if useflags:
811 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500812 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700813 new_flags = ' '.join(useflags)
814
815 existing = os.environ.get('USE', '')
816 final_flags = '%s %s' % (existing, new_flags)
817 extra_env = {'USE': final_flags.strip()}
818 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600819
820
David Burger0f9dd4e2019-10-08 12:33:42 -0600821def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600822 """Check if |build_target| builds |atom| (has it in its depgraph)."""
823 cros_build_lib.AssertInsideChroot()
824
Alex Kleind8cd4c62020-09-14 13:37:47 -0600825 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600826 # TODO(crbug/1081828): Receive and use sysroot.
827 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600828 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600829 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600830
831
Alex Klein6becabc2020-09-11 14:03:05 -0600832def needs_chrome_source(
833 build_target: 'build_target_lib.BuildTarget',
834 compile_source=False,
835 packages: Optional[List[package_info.PackageInfo]] = None,
836 useflags=None):
837 """Check if the chrome source is needed.
838
839 The chrome source is needed if the build target builds chrome or any of its
840 follower packages, and can't use a prebuilt for them either because it's not
841 available, or because we can't use prebuilts because it must build from
842 source.
843 """
844 cros_build_lib.AssertInsideChroot()
845
846 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700847 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600848 builds_chrome = constants.CHROME_CP in graph
849 builds_follower = {
850 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
851 }
852
Alex Klein9ce3f682021-06-23 15:06:44 -0600853 local_uprev = builds_chrome and revbump_chrome([build_target])
854
Alex Klein6becabc2020-09-11 14:03:05 -0600855 # When we are compiling source set False since we do not use prebuilts.
856 # When not compiling from source, start with True, i.e. we have every prebuilt
857 # we've checked for up to this point.
858 has_chrome_prebuilt = not compile_source
859 has_follower_prebuilts = not compile_source
860 # Save packages that need prebuilts for reporting.
861 pkgs_needing_prebuilts = []
862 if compile_source:
863 # Need everything.
864 pkgs_needing_prebuilts.append(constants.CHROME_CP)
865 pkgs_needing_prebuilts.extend(
866 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
867 else:
868 # Check chrome itself.
869 if builds_chrome:
870 has_chrome_prebuilt = has_prebuilt(
871 constants.CHROME_CP, build_target=build_target, useflags=useflags)
872 if not has_chrome_prebuilt:
873 pkgs_needing_prebuilts.append(constants.CHROME_CP)
874 # Check follower packages.
875 for pkg, builds_pkg in builds_follower.items():
876 if not builds_pkg:
877 continue
878 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
879 has_follower_prebuilts &= prebuilt
880 if not prebuilt:
881 pkgs_needing_prebuilts.append(pkg)
882 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
883 # reflect whether we actually have the corresponding prebuilts for the build.
884
885 needs_chrome = builds_chrome and not has_chrome_prebuilt
886 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
887
888 return NeedsChromeSourceResult(
Sergey Frolov26ff97b2021-08-14 00:02:11 +0000889 needs_chrome_source=needs_chrome or needs_follower,
Alex Klein6becabc2020-09-11 14:03:05 -0600890 builds_chrome=builds_chrome,
891 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
892 missing_chrome_prebuilt=not has_chrome_prebuilt,
Alex Klein9ce3f682021-06-23 15:06:44 -0600893 missing_follower_prebuilt=not has_follower_prebuilts,
894 local_uprev=local_uprev,
895 )
Alex Klein6becabc2020-09-11 14:03:05 -0600896
897
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600898def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600899 """Returns the current Chrome version for the board (or in buildroot).
900
901 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600902 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700903
904 Returns:
905 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600906 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600907 # TODO(crbug/1019770): Long term we should not need the try/catch here once
908 # the builds function above only returns True for chrome when
909 # determine_chrome_version will succeed.
910 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700911 cpv = portage_util.PortageqBestVisible(
912 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600913 except cros_build_lib.RunCommandError as e:
914 # Return None because portage failed when trying to determine the chrome
915 # version.
916 logging.warning('Caught exception in determine_chrome_package: %s', e)
917 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600918 # Something like 78.0.3877.4_rc -> 78.0.3877.4
919 return cpv.version_no_rev.partition('_')[0]
920
921
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600922def determine_android_package(board):
923 """Returns the active Android container package in use by the board.
924
925 Args:
926 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700927
928 Returns:
929 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600930 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600931 try:
932 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600933 except cros_build_lib.RunCommandError as e:
934 # Return None because a command (likely portage) failed when trying to
935 # determine the package.
936 logging.warning('Caught exception in determine_android_package: %s', e)
937 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600938
Alex Kleinad6b48a2020-01-08 16:57:41 -0700939 # We assume there is only one Android package in the depgraph.
940 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400941 if (package.startswith('chromeos-base/android-container-') or
942 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700943 return package
944 return None
945
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600946
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500947def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600948 """Determine the current Android version in buildroot now and return it.
949
950 This uses the typical portage logic to determine which version of Android
951 is active right now in the buildroot.
952
953 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500954 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500955 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600956
957 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500958 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600959
960 Raises:
961 NoAndroidVersionError: if no unique Android version can be determined.
962 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500963 if not package:
964 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500965 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600966 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500967 cpv = package_info.SplitCPV(package)
968 if not cpv:
969 raise NoAndroidVersionError(
970 'Android version could not be determined for %s' % board)
971 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600972
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700973
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500974def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600975 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500976 if not package:
977 package = determine_android_package(board)
978 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600979 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500980 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600981 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900982 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900983 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600984 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
985 for target in targets:
986 if target in ebuild_content:
987 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
988 if branch is not None:
989 return branch.group(1)
990 raise NoAndroidBranchError(
991 'Android branch could not be determined for %s (ebuild empty?)' % board)
992
993
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500994def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600995 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500996 if not package:
997 package = determine_android_package(board)
998 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600999 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001000 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001001 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001002 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -06001003 return 'cheets'
1004
1005 raise NoAndroidTargetError(
1006 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -05001007 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001008
1009
1010def determine_platform_version():
1011 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -06001012 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -06001013 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1014 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -06001015
1016
1017def determine_milestone_version():
1018 """Returns the platform version from the source root."""
1019 # Milestone version is something like '79'.
1020 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
1021 return version.chrome_branch
1022
Alex Klein7a3a7dd2020-01-08 16:44:38 -07001023
Michael Mortensen009cb662019-10-21 11:38:43 -06001024def determine_full_version():
1025 """Returns the full version from the source root."""
1026 # Full version is something like 'R79-12575.0.0'.
1027 milestone_version = determine_milestone_version()
1028 platform_version = determine_platform_version()
1029 full_version = ('R%s-%s' % (milestone_version, platform_version))
1030 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -06001031
1032
Michael Mortensende716a12020-05-15 11:27:00 -06001033def find_fingerprints(build_target):
1034 """Returns a list of fingerprints for this build.
1035
1036 Args:
1037 build_target (build_target_lib.BuildTarget): The build target.
1038
1039 Returns:
1040 list[str] - List of fingerprint strings.
1041 """
1042 cros_build_lib.AssertInsideChroot()
1043 fp_file = 'cheets-fingerprint.txt'
1044 fp_path = os.path.join(
1045 image_lib.GetLatestImageLink(build_target.name),
1046 fp_file)
1047 if not os.path.isfile(fp_path):
1048 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001049 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001050 logging.info('Reading fingerprint file: %s', fp_path)
1051 fingerprints = osutils.ReadFile(fp_path).splitlines()
1052 return fingerprints
1053
1054
Michael Mortensen59e30872020-05-18 14:12:49 -06001055def get_all_firmware_versions(build_target):
1056 """Extract firmware version for all models present.
1057
1058 Args:
1059 build_target (build_target_lib.BuildTarget): The build target.
1060
1061 Returns:
1062 A dict of FirmwareVersions namedtuple instances by model.
1063 Each element will be populated based on whether it was present in the
1064 command output.
1065 """
1066 cros_build_lib.AssertInsideChroot()
1067 result = {}
1068 # Note that example output for _get_firmware_version_cmd_result is available
1069 # in the packages_unittest.py for testing get_all_firmware_versions.
1070 cmd_result = _get_firmware_version_cmd_result(build_target)
1071
1072 # There is a blank line between the version info for each model.
1073 firmware_version_payloads = cmd_result.split('\n\n')
1074 for firmware_version_payload in firmware_version_payloads:
1075 if 'BIOS' in firmware_version_payload:
1076 firmware_version = _find_firmware_versions(firmware_version_payload)
1077 result[firmware_version.model] = firmware_version
1078 return result
1079
1080
Michael Mortensen71ef5682020-05-07 14:29:24 -06001081FirmwareVersions = collections.namedtuple(
1082 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1083
1084
1085def get_firmware_versions(build_target):
1086 """Extract version information from the firmware updater, if one exists.
1087
1088 Args:
1089 build_target (build_target_lib.BuildTarget): The build target.
1090
1091 Returns:
1092 A FirmwareVersions namedtuple instance.
1093 Each element will either be set to the string output by the firmware
1094 updater shellball, or None if there is no firmware updater.
1095 """
1096 cros_build_lib.AssertInsideChroot()
1097 cmd_result = _get_firmware_version_cmd_result(build_target)
1098 if cmd_result:
1099 return _find_firmware_versions(cmd_result)
1100 else:
1101 return FirmwareVersions(None, None, None, None, None)
1102
1103
1104def _get_firmware_version_cmd_result(build_target):
1105 """Gets the raw result output of the firmware updater version command.
1106
1107 Args:
1108 build_target (build_target_lib.BuildTarget): The build target.
1109
1110 Returns:
1111 Command execution result.
1112 """
1113 updater = os.path.join(build_target.root,
1114 'usr/sbin/chromeos-firmwareupdate')
1115 logging.info('Calling updater %s', updater)
1116 # Call the updater using the chroot-based path.
1117 return cros_build_lib.run([updater, '-V'],
1118 capture_output=True, log_output=True,
1119 encoding='utf-8').stdout
1120
1121
1122def _find_firmware_versions(cmd_output):
1123 """Finds firmware version output via regex matches against the cmd_output.
1124
1125 Args:
1126 cmd_output: The raw output to search against.
1127
1128 Returns:
1129 FirmwareVersions namedtuple with results.
1130 Each element will either be set to the string output by the firmware
1131 updater shellball, or None if there is no match.
1132 """
1133
1134 # Sometimes a firmware bundle includes a special combination of RO+RW
1135 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1136 # version" field. In other cases, the "(RW) version" field is not present.
1137 # Therefore, search for the "(RW)" fields first and if they aren't present,
1138 # fallback to the other format. e.g. just "BIOS version:".
1139 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1140 main = None
1141 main_rw = None
1142 ec = None
1143 ec_rw = None
1144 model = None
1145
1146 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1147 if match:
1148 main = match.group('version')
1149
1150 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1151 if match:
1152 main_rw = match.group('version')
1153
1154 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1155 if match:
1156 ec = match.group('version')
1157
1158 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1159 if match:
1160 ec_rw = match.group('version')
1161
1162 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1163 if match:
1164 model = match.group('model')
1165
1166 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001167
1168
1169MainEcFirmwareVersions = collections.namedtuple(
1170 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1171
1172def determine_firmware_versions(build_target):
1173 """Returns a namedtuple with main and ec firmware versions.
1174
1175 Args:
1176 build_target (build_target_lib.BuildTarget): The build target.
1177
1178 Returns:
1179 MainEcFirmwareVersions namedtuple with results.
1180 """
1181 fw_versions = get_firmware_versions(build_target)
1182 main_fw_version = fw_versions.main_rw or fw_versions.main
1183 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1184
1185 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001186
1187def determine_kernel_version(build_target):
1188 """Returns a string containing the kernel version for this build target.
1189
1190 Args:
1191 build_target (build_target_lib.BuildTarget): The build target.
1192
1193 Returns:
1194 (str) The kernel versions, or None.
1195 """
1196 try:
1197 packages = portage_util.GetPackageDependencies(build_target.name,
1198 'virtual/linux-sources')
1199 except cros_build_lib.RunCommandError as e:
1200 logging.warning('Unable to get package list for metadata: %s', e)
1201 return None
1202 for package in packages:
1203 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001204 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001205 logging.info('Found active kernel version: %s', kernel_version)
1206 return kernel_version
1207 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001208
1209
1210def get_models(build_target, log_output=True):
1211 """Obtain a list of models supported by a unified board.
1212
1213 This ignored whitelabel models since GoldenEye has no specific support for
1214 these at present.
1215
1216 Args:
1217 build_target (build_target_lib.BuildTarget): The build target.
1218 log_output: Whether to log the output of the cros_config_host invocation.
1219
1220 Returns:
1221 A list of models supported by this board, if it is a unified build; None,
1222 if it is not a unified build.
1223 """
1224 return _run_cros_config_host(build_target, ['list-models'],
1225 log_output=log_output)
1226
1227
Michael Mortensen359c1f32020-05-28 19:35:42 -06001228def get_key_id(build_target, model):
1229 """Obtain the key_id for a model within the build_target.
1230
1231 Args:
1232 build_target (build_target_lib.BuildTarget): The build target.
1233 model (str): The model name
1234
1235 Returns:
1236 A key_id (str) or None.
1237 """
1238 model_arg = '--model=' + model
1239 key_id_list = _run_cros_config_host(
1240 build_target,
1241 [model_arg, 'get', '/firmware-signing', 'key-id'])
1242 key_id = None
1243 if len(key_id_list) == 1:
1244 key_id = key_id_list[0]
1245 return key_id
1246
1247
Michael Mortensen125bb012020-05-21 14:02:10 -06001248def _run_cros_config_host(build_target, args, log_output=True):
1249 """Run the cros_config_host tool.
1250
1251 Args:
1252 build_target (build_target_lib.BuildTarget): The build target.
1253 args: List of arguments to pass.
1254 log_output: Whether to log the output of the cros_config_host.
1255
1256 Returns:
1257 Output of the tool
1258 """
1259 cros_build_lib.AssertInsideChroot()
1260 tool = '/usr/bin/cros_config_host'
1261 if not os.path.isfile(tool):
1262 return None
1263
1264 config_fname = build_target.full_path(
1265 'usr/share/chromeos-config/yaml/config.yaml')
1266
1267 result = cros_build_lib.run(
1268 [tool, '-c', config_fname] + args,
1269 capture_output=True,
1270 encoding='utf-8',
1271 log_output=log_output,
1272 check=False)
1273 if result.returncode:
1274 # Show the output for debugging purposes.
1275 if 'No such file or directory' not in result.error:
1276 logging.error('cros_config_host failed: %s\n', result.error)
1277 return None
1278 return result.output.strip().splitlines()