blob: 00ce44ec65290f739e5a0f21e1dc921093f14a2f [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Package utility functionality."""
6
Yaakov Shaul730814a2019-09-10 13:58:25 -06007import collections
Ben Reiche779cf42020-12-15 03:21:31 +00008from distutils.version import LooseVersion
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -06009import fileinput
Alex Klein87531182019-08-12 15:23:37 -060010import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060011import json
Evan Hernandezb51f1522019-08-15 11:29:40 -060012import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060013import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060014import sys
Alex Klein6becabc2020-09-11 14:03:05 -060015from typing import List, Optional
Alex Klein87531182019-08-12 15:23:37 -060016
Mike Frysinger2c024062021-05-22 15:43:22 -040017from chromite.third_party.google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060018
Andrew Lamb2bde9e42019-11-04 13:24:09 -070019from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060020from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060021from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060022from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060023from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060025from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060026from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070028from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060029from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060030from chromite.lib.parser import package_info
Alex Kleineb77ffa2019-05-28 14:47:44 -060031
Alex Klein36b117f2019-09-30 15:13:46 -060032if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060033 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060034 from chromite.service import dependency
35
Alex Klein87531182019-08-12 15:23:37 -060036# Registered handlers for uprevving versioned packages.
37_UPREV_FUNCS = {}
38
Alex Kleineb77ffa2019-05-28 14:47:44 -060039
40class Error(Exception):
41 """Module's base error class."""
42
43
Alex Klein4de25e82019-08-05 15:58:39 -060044class UnknownPackageError(Error):
45 """Uprev attempted for a package without a registered handler."""
46
47
Alex Kleineb77ffa2019-05-28 14:47:44 -060048class UprevError(Error):
49 """An error occurred while uprevving packages."""
50
51
Michael Mortensenb70e8a82019-10-10 18:43:41 -060052class NoAndroidVersionError(Error):
53 """An error occurred while trying to determine the android version."""
54
55
56class NoAndroidBranchError(Error):
57 """An error occurred while trying to determine the android branch."""
58
59
60class NoAndroidTargetError(Error):
61 """An error occurred while trying to determine the android target."""
62
63
Alex Klein4de25e82019-08-05 15:58:39 -060064class AndroidIsPinnedUprevError(UprevError):
65 """Raised when we try to uprev while Android is pinned."""
66
67 def __init__(self, new_android_atom):
68 """Initialize a AndroidIsPinnedUprevError.
69
70 Args:
71 new_android_atom: The Android atom that we failed to
72 uprev to, due to Android being pinned.
73 """
74 assert new_android_atom
75 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
76 new_android_atom)
77 super(AndroidIsPinnedUprevError, self).__init__(msg)
78 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060079
80
Andrew Lamb9563a152019-12-04 11:42:18 -070081class GeneratedCrosConfigFilesError(Error):
82 """Error when cros_config_schema does not produce expected files"""
83
84 def __init__(self, expected_files, found_files):
85 msg = ('Expected to find generated C files: %s. Actually found: %s' %
86 (expected_files, found_files))
87 super(GeneratedCrosConfigFilesError, self).__init__(msg)
88
Alex Klein7a3a7dd2020-01-08 16:44:38 -070089
Alex Klein6becabc2020-09-11 14:03:05 -060090NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
91 'needs_chrome_source',
92 'builds_chrome',
93 'packages',
94 'missing_chrome_prebuilt',
95 'missing_follower_prebuilt',
96))
97
98
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060099def patch_ebuild_vars(ebuild_path, variables):
100 """Updates variables in ebuild.
101
102 Use this function rather than portage_util.EBuild.UpdateEBuild when you
103 want to preserve the variable position and quotes within the ebuild.
104
105 Args:
106 ebuild_path: The path of the ebuild.
107 variables: Dictionary of variables to update in ebuild.
108 """
109 try:
110 for line in fileinput.input(ebuild_path, inplace=1):
111 varname, eq, _ = line.partition('=')
112 if eq == '=' and varname.strip() in variables:
113 value = variables[varname]
114 sys.stdout.write('%s="%s"\n' % (varname, value))
115 else:
116 sys.stdout.write(line)
117 finally:
118 fileinput.close()
119
120
Alex Klein87531182019-08-12 15:23:37 -0600121def uprevs_versioned_package(package):
122 """Decorator to register package uprev handlers."""
123 assert package
124
125 def register(func):
126 """Registers |func| as a handler for |package|."""
127 _UPREV_FUNCS[package] = func
128
129 @functools.wraps(func)
130 def pass_through(*args, **kwargs):
131 return func(*args, **kwargs)
132
133 return pass_through
134
135 return register
136
137
Shao-Chuan Leeb6a2cb62021-02-19 14:18:59 +0900138def uprev_android(android_package,
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700139 chroot,
140 build_targets=None,
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900141 android_build_branch=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900142 android_version=None,
143 skip_commit=False):
Alex Klein4de25e82019-08-05 15:58:39 -0600144 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700145 command = [
146 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900147 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700148 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600149 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900150 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900151 if android_build_branch:
152 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600153 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900154 command.append(f'--force_version={android_version}')
155 if skip_commit:
156 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600157
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700158 result = cros_build_lib.run(
159 command,
160 stdout=True,
161 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500162 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700163 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600164
Mike Frysinger88d96362020-02-14 19:05:45 -0500165 portage_atom_string = result.stdout.strip()
166 android_atom = None
167 if portage_atom_string:
168 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600169 if not android_atom:
170 logging.info('Found nothing to rev.')
171 return None
172
173 for target in build_targets or []:
174 # Sanity check: We should always be able to merge the version of
175 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900176 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600177 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700178 cros_build_lib.run(
179 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600180 except cros_build_lib.RunCommandError:
181 logging.error(
182 'Cannot emerge-%s =%s\nIs Android pinned to an older '
183 'version?', target, android_atom)
184 raise AndroidIsPinnedUprevError(android_atom)
185
186 return android_atom
187
188
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700189def uprev_build_targets(build_targets,
190 overlay_type,
191 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600192 output_dir=None):
193 """Uprev the set provided build targets, or all if not specified.
194
195 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600196 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600197 whose overlays should be uprevved, empty or None for all.
198 overlay_type (str): One of the valid overlay types except None (see
199 constants.VALID_OVERLAYS).
200 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
201 output_dir (str|None): The path to optionally dump result files.
202 """
203 # Need a valid overlay, but exclude None.
204 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
205
206 if build_targets:
207 overlays = portage_util.FindOverlaysForBoards(
208 overlay_type, boards=[t.name for t in build_targets])
209 else:
210 overlays = portage_util.FindOverlays(overlay_type)
211
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700212 return uprev_overlays(
213 overlays,
214 build_targets=build_targets,
215 chroot=chroot,
216 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600217
218
219def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
220 """Uprev the given overlays.
221
222 Args:
223 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600224 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600225 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
226 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
227 output_dir (str|None): The path to optionally dump result files.
228
229 Returns:
230 list[str] - The paths to all of the modified ebuild files. This includes the
231 new files that were added (i.e. the new versions) and all of the removed
232 files (i.e. the old versions).
233 """
234 assert overlays
235
236 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
237
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700238 uprev_manager = uprev_lib.UprevOverlayManager(
239 overlays,
240 manifest,
241 build_targets=build_targets,
242 chroot=chroot,
243 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600244 uprev_manager.uprev()
245
246 return uprev_manager.modified_ebuilds
247
248
Alex Klein87531182019-08-12 15:23:37 -0600249def uprev_versioned_package(package, build_targets, refs, chroot):
250 """Call registered uprev handler function for the package.
251
252 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600253 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600254 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600255 clean on a successful uprev.
256 refs (list[uprev_lib.GitRef]):
257 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
258
259 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600260 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600261 """
262 assert package
263
264 if package.cp not in _UPREV_FUNCS:
265 raise UnknownPackageError(
266 'Package "%s" does not have a registered handler.' % package.cp)
267
Andrew Lambea9a8a22019-12-12 14:03:43 -0700268 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600269
270
Navil Perezf57ba872020-06-04 22:38:37 +0000271@uprevs_versioned_package('media-libs/virglrenderer')
272def uprev_virglrenderer(_build_targets, refs, _chroot):
273 """Updates virglrenderer ebuilds.
274
275 See: uprev_versioned_package.
276
277 Returns:
278 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
279 """
Navil Perezf57ba872020-06-04 22:38:37 +0000280 overlay = os.path.join(constants.SOURCE_ROOT,
281 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600282 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
283 'virglrenderer')
284 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000285
286 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
287 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000288 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
289 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000290 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
291
George Engelbrechte73f2782020-06-10 14:10:46 -0600292 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600293 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000294 result.add_result(refs[0].revision, updated_files)
295 return result
296
Jose Magana03b5a842020-08-19 12:52:59 +1000297@uprevs_versioned_package('chromeos-base/drivefs')
298def uprev_drivefs(_build_targets, refs, chroot):
299 """Updates drivefs ebuilds.
300
Harvey Yang3eee06c2021-03-18 15:47:56 +0800301 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000302 See: uprev_versioned_package.
303
304 Returns:
305 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
306 """
307
Ben Reiche779cf42020-12-15 03:21:31 +0000308 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000309 result = uprev_lib.UprevVersionedPackageResult()
310 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000311
Harvey Yang3eee06c2021-03-18 15:47:56 +0800312 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
313 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000314 if not drivefs_version:
315 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000316 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000317
Ben Reiche779cf42020-12-15 03:21:31 +0000318 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000319
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000320 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000321 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000322 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000323 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800324 chroot,
325 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000326
327 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000328 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000329 all_changed_files.extend(uprev_result.changed_files)
330
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000331 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000332 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000333 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000334 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800335 chroot,
336 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000337
338 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000339 logging.warning(
340 'drivefs package has changed files %s but drivefs-ipc does not',
341 all_changed_files)
342 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000343
344 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000345 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000346
347 return result
348
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800349@uprevs_versioned_package('chromeos-base/perfetto')
350def uprev_perfetto(_build_targets, refs, chroot):
351 """Updates Perfetto ebuilds.
352
Harvey Yang3eee06c2021-03-18 15:47:56 +0800353 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800354 See: uprev_versioned_package.
355
356 Returns:
357 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
358 """
359 result = uprev_lib.UprevVersionedPackageResult()
360
Harvey Yang3eee06c2021-03-18 15:47:56 +0800361 PERFETTO_REFS_PREFIX = 'refs/tags/v'
362 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800363 if not perfetto_version:
364 # No valid Perfetto version is identified.
365 return result
366
367 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
368
369 # Attempt to uprev perfetto package.
370 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
371
Harvey Yang3eee06c2021-03-18 15:47:56 +0800372 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
373 PERFETTO_PATH,
374 perfetto_version,
375 chroot,
376 allow_downrev=False,
377 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800378
379 if not uprev_result:
380 return result
381
382 result.add_result(perfetto_version, uprev_result.changed_files)
383
384 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000385
Yaakov Shaul395ae832019-09-09 14:45:32 -0600386@uprevs_versioned_package('afdo/kernel-profiles')
387def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600388 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600389
390 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600391
392 Raises:
393 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600394 """
395 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
396 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
397
David Burger92485342019-09-10 17:52:45 -0600398 with open(path, 'r') as f:
399 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600400
Chris McDonald38409112020-09-24 11:24:51 -0600401 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600402 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600403 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
404 'sys-kernel', version)
405 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
406 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600407 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
408 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600409 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600410 patch_ebuild_vars(ebuild_path,
411 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600412
413 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600414 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400415 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600416 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600417 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600418 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600419 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600420
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600421 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600422
Yaakov Shaul730814a2019-09-10 13:58:25 -0600423 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
424
425 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600426
427
Trent Begineb624182020-07-14 10:09:45 -0600428@uprevs_versioned_package('chromeos-base/termina-dlc')
429def uprev_termina_dlc(_build_targets, _refs, chroot):
430 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600431
432 See: uprev_versioned_package.
433 """
Trent Begineb624182020-07-14 10:09:45 -0600434 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600435 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
436 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000437
438 version_pin_src_path = _get_version_pin_src_path(package_path)
439 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
440
Chris McDonald38409112020-09-24 11:24:51 -0600441 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000442
443
Julio Hurtadof1befec2021-05-05 21:34:26 +0000444@uprevs_versioned_package('chromeos-base/chromeos-lacros')
445def uprev_lacros(_build_targets, refs, chroot):
446 """Updates lacros ebuilds.
447
448 Information used is gathered from the QA qualified version tracking file
449 stored in chromium/src.
450
451 See: uprev_versioned_package.
452 """
453 path = os.path.join(
454 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base','chromeos-lacros')
455 return uprev_lib.uprev_ebuild_from_pin(path, refs[0].revision, chroot)
456
457
Patrick Meiring5897add2020-09-16 16:30:17 +1000458@uprevs_versioned_package('app-emulation/parallels-desktop')
459def uprev_parallels_desktop(_build_targets, _refs, chroot):
460 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
461
462 See: uprev_versioned_package
463
464 Returns:
465 UprevVersionedPackageResult: The result.
466 """
467 package = 'parallels-desktop'
468 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
469 'app-emulation', package)
470 version_pin_src_path = _get_version_pin_src_path(package_path)
471
472 # Expect a JSON blob like the following:
473 # {
474 # "version": "1.2.3",
475 # "test_image": { "url": "...", "size": 12345678,
476 # "sha256sum": "<32 bytes of hexadecimal>" }
477 # }
478 with open(version_pin_src_path, 'r') as f:
479 pinned = json.load(f)
480
481 if 'version' not in pinned or 'test_image' not in pinned:
482 raise UprevError('VERSION-PIN for %s missing version and/or '
483 'test_image field' % package)
484
485 version = pinned['version']
486 if not isinstance(version, str):
487 raise UprevError('version in VERSION-PIN for %s not a string' % package)
488
489 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600490 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000491
492 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100493 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
494 'local/bundles/crosint/pita/data/'
495 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000496 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
497 with open(test_image_src_path, 'w') as f:
498 json.dump(pinned['test_image'], f, indent=2)
499 result.add_result(version, [test_image_src_path])
500
501 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600502
503
Trent Begin315d9d92019-12-03 21:55:53 -0700504@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600505def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700506 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
507
508 See: uprev_versioned_package.
509 """
510 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700511 package_path = os.path.join('src', 'private-overlays',
512 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000513 version_pin_src_path = _get_version_pin_src_path(package_path)
514 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700515
Chris McDonald38409112020-09-24 11:24:51 -0600516 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700517
518
Patrick Meiring5897add2020-09-16 16:30:17 +1000519def _get_version_pin_src_path(package_path):
520 """Returns the path to the VERSION-PIN file for the given package."""
521 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
522
523
Alex Klein87531182019-08-12 15:23:37 -0600524@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700525def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600526 """Uprev chrome and its related packages.
527
528 See: uprev_versioned_package.
529 """
530 # Determine the version from the refs (tags), i.e. the chrome versions are the
531 # tag names.
532 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600533 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600534
535 uprev_manager = uprev_lib.UprevChromeManager(
536 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600537 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600538 # Start with chrome itself, as we can't do anything else unless chrome
539 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600540 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
541 # attempt. The expected behavior is documented in the following table:
542 #
543 # Outcome of Chrome uprev attempt:
544 # NEWER_VERSION_EXISTS:
545 # Do nothing.
546 # SAME_VERSION_EXISTS or REVISION_BUMP:
547 # Uprev followers
548 # Assert not VERSION_BUMP (any other outcome is fine)
549 # VERSION_BUMP or NEW_EBUILD_CREATED:
550 # Uprev followers
551 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600552 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600553 return result
Alex Klein87531182019-08-12 15:23:37 -0600554
555 # With a successful chrome rev, also uprev related packages.
556 for package in constants.OTHER_CHROME_PACKAGES:
557 uprev_manager.uprev(package)
558
David Burger37f48672019-09-18 17:07:56 -0600559 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600560
561
Harvey Yang3eee06c2021-03-18 15:47:56 +0800562def _get_latest_version_from_refs(refs_prefix: str,
563 refs: List[uprev_lib.GitRef]) -> str:
564 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000565
Ben Reiche779cf42020-12-15 03:21:31 +0000566 Versions are compared using |distutils.version.LooseVersion| and
567 the latest version is returned.
568
569 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800570 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800571 refs: The tags to parse for the latest Perfetto version.
572
573 Returns:
574 The latest Perfetto version to use.
575 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800576 valid_refs = []
577 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800578 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800579 valid_refs.append(gitiles.ref)
580
581 if not valid_refs:
582 return None
583
584 # Sort by version and take the latest version.
585 target_version_ref = sorted(valid_refs,
586 key=LooseVersion,
587 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800588 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800589
590
Andrew Lamb9563a152019-12-04 11:42:18 -0700591def _generate_platform_c_files(replication_config, chroot):
592 """Generates platform C files from a platform JSON payload.
593
594 Args:
595 replication_config (replication_config_pb2.ReplicationConfig): A
596 ReplicationConfig that has already been run. If it produced a
597 build_config.json file, that file will be used to generate platform C
598 files. Otherwise, nothing will be generated.
599 chroot (chroot_lib.Chroot): The chroot to use to generate.
600
601 Returns:
602 A list of generated files.
603 """
604 # Generate the platform C files from the build config. Note that it would be
605 # more intuitive to generate the platform C files from the platform config;
606 # however, cros_config_schema does not allow this, because the platform config
607 # payload is not always valid input. For example, if a property is both
608 # 'required' and 'build-only', it will fail schema validation. Thus, use the
609 # build config, and use '-f' to filter.
610 build_config_path = [
611 rule.destination_path
612 for rule in replication_config.file_replication_rules
613 if rule.destination_path.endswith('build_config.json')
614 ]
615
616 if not build_config_path:
617 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700618 'No build_config.json found, will not generate platform C files. '
619 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700620 return []
621
622 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700623 raise ValueError('Expected at most one build_config.json destination path. '
624 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700625
626 build_config_path = build_config_path[0]
627
628 # Paths to the build_config.json and dir to output C files to, in the
629 # chroot.
630 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
631 build_config_path)
632 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
633 os.path.dirname(build_config_path))
634
635 command = [
636 'cros_config_schema', '-m', build_config_chroot_path, '-g',
637 generated_output_chroot_dir, '-f', '"TRUE"'
638 ]
639
640 cros_build_lib.run(
641 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
642
643 # A relative (to the source root) path to the generated C files.
644 generated_output_dir = os.path.dirname(build_config_path)
645 generated_files = []
646 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
647 for f in expected_c_files:
648 if os.path.exists(
649 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
650 generated_files.append(os.path.join(generated_output_dir, f))
651
652 if len(expected_c_files) != len(generated_files):
653 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
654
655 return generated_files
656
657
Andrew Lambe836f222019-12-09 12:27:38 -0700658def _get_private_overlay_package_root(ref, package):
659 """Returns the absolute path to the root of a given private overlay.
660
661 Args:
662 ref (uprev_lib.GitRef): GitRef for the private overlay.
663 package (str): Path to the package in the overlay.
664 """
665 # There might be a cleaner way to map from package -> path within the source
666 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700667 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700668 match = re.match(private_overlay_ref_pattern, ref.path)
669 if not match:
670 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
671 (private_overlay_ref_pattern, ref))
672
673 overlay = match.group(1)
674
675 return os.path.join(constants.SOURCE_ROOT,
676 'src/private-overlays/overlay-%s-private' % overlay,
677 package)
678
679
Andrew Lambea9a8a22019-12-12 14:03:43 -0700680@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
681def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700682 """Replicate a private cros_config change to the corresponding public config.
683
Alex Kleinad6b48a2020-01-08 16:57:41 -0700684 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700685 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700686 package = 'chromeos-base/chromeos-config-bsp'
687
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700688 if len(refs) != 1:
689 raise ValueError('Expected exactly one ref, actual %s' % refs)
690
691 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700692 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700693 replication_config_path = os.path.join(package_root,
694 'replication_config.jsonpb')
695
696 try:
697 replication_config = json_format.Parse(
698 osutils.ReadFile(replication_config_path),
699 replication_config_pb2.ReplicationConfig())
700 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700701 raise ValueError(
702 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700703
704 replication_lib.Replicate(replication_config)
705
706 modified_files = [
707 rule.destination_path
708 for rule in replication_config.file_replication_rules
709 ]
710
Andrew Lamb9563a152019-12-04 11:42:18 -0700711 # The generated platform C files are not easily filtered by replication rules,
712 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
713 # files cannot. Therefore, replicate and filter the JSON payloads, and then
714 # generate filtered C files from the JSON payload.
715 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700716
717 # Use the private repo's commit hash as the new version.
718 new_private_version = refs[0].revision
719
Andrew Lamb988f4da2019-12-10 10:16:43 -0700720 # modified_files should contain only relative paths at this point, but the
721 # returned UprevVersionedPackageResult must contain only absolute paths.
722 for i, modified_file in enumerate(modified_files):
723 assert not os.path.isabs(modified_file)
724 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
725
Chris McDonald38409112020-09-24 11:24:51 -0600726 return uprev_lib.UprevVersionedPackageResult().add_result(
727 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700728
729
Alex Kleinbbef2b32019-08-27 10:38:50 -0600730def get_best_visible(atom, build_target=None):
731 """Returns the best visible CPV for the given atom.
732
733 Args:
734 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600735 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600736 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700737
738 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600739 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600740 """
David Burger1e0fe232019-07-01 14:52:07 -0600741 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600742
743 board = build_target.name if build_target else None
744 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600745
746
Alex Klein149fd3b2019-12-16 16:01:05 -0700747def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600748 """Check if a prebuilt exists.
749
750 Args:
751 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600752 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600753 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700754 useflags: Any additional USE flags that should be set. May be a string
755 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700756
757 Returns:
758 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600759 """
760 assert atom
761
762 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700763 extra_env = None
764 if useflags:
765 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500766 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700767 new_flags = ' '.join(useflags)
768
769 existing = os.environ.get('USE', '')
770 final_flags = '%s %s' % (existing, new_flags)
771 extra_env = {'USE': final_flags.strip()}
772 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600773
774
David Burger0f9dd4e2019-10-08 12:33:42 -0600775def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600776 """Check if |build_target| builds |atom| (has it in its depgraph)."""
777 cros_build_lib.AssertInsideChroot()
778
Alex Kleind8cd4c62020-09-14 13:37:47 -0600779 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600780 # TODO(crbug/1081828): Receive and use sysroot.
781 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600782 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600783 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600784
785
Alex Klein6becabc2020-09-11 14:03:05 -0600786def needs_chrome_source(
787 build_target: 'build_target_lib.BuildTarget',
788 compile_source=False,
789 packages: Optional[List[package_info.PackageInfo]] = None,
790 useflags=None):
791 """Check if the chrome source is needed.
792
793 The chrome source is needed if the build target builds chrome or any of its
794 follower packages, and can't use a prebuilt for them either because it's not
795 available, or because we can't use prebuilts because it must build from
796 source.
797 """
798 cros_build_lib.AssertInsideChroot()
799
800 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700801 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600802 builds_chrome = constants.CHROME_CP in graph
803 builds_follower = {
804 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
805 }
806
807 # When we are compiling source set False since we do not use prebuilts.
808 # When not compiling from source, start with True, i.e. we have every prebuilt
809 # we've checked for up to this point.
810 has_chrome_prebuilt = not compile_source
811 has_follower_prebuilts = not compile_source
812 # Save packages that need prebuilts for reporting.
813 pkgs_needing_prebuilts = []
814 if compile_source:
815 # Need everything.
816 pkgs_needing_prebuilts.append(constants.CHROME_CP)
817 pkgs_needing_prebuilts.extend(
818 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
819 else:
820 # Check chrome itself.
821 if builds_chrome:
822 has_chrome_prebuilt = has_prebuilt(
823 constants.CHROME_CP, build_target=build_target, useflags=useflags)
824 if not has_chrome_prebuilt:
825 pkgs_needing_prebuilts.append(constants.CHROME_CP)
826 # Check follower packages.
827 for pkg, builds_pkg in builds_follower.items():
828 if not builds_pkg:
829 continue
830 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
831 has_follower_prebuilts &= prebuilt
832 if not prebuilt:
833 pkgs_needing_prebuilts.append(pkg)
834 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
835 # reflect whether we actually have the corresponding prebuilts for the build.
836
837 needs_chrome = builds_chrome and not has_chrome_prebuilt
838 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
839
840 return NeedsChromeSourceResult(
841 needs_chrome_source=needs_chrome or needs_follower,
842 builds_chrome=builds_chrome,
843 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
844 missing_chrome_prebuilt=not has_chrome_prebuilt,
845 missing_follower_prebuilt=not has_follower_prebuilts)
846
847
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600848def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600849 """Returns the current Chrome version for the board (or in buildroot).
850
851 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600852 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700853
854 Returns:
855 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600856 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600857 # TODO(crbug/1019770): Long term we should not need the try/catch here once
858 # the builds function above only returns True for chrome when
859 # determine_chrome_version will succeed.
860 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700861 cpv = portage_util.PortageqBestVisible(
862 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600863 except cros_build_lib.RunCommandError as e:
864 # Return None because portage failed when trying to determine the chrome
865 # version.
866 logging.warning('Caught exception in determine_chrome_package: %s', e)
867 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600868 # Something like 78.0.3877.4_rc -> 78.0.3877.4
869 return cpv.version_no_rev.partition('_')[0]
870
871
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600872def determine_android_package(board):
873 """Returns the active Android container package in use by the board.
874
875 Args:
876 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700877
878 Returns:
879 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600880 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600881 try:
882 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600883 except cros_build_lib.RunCommandError as e:
884 # Return None because a command (likely portage) failed when trying to
885 # determine the package.
886 logging.warning('Caught exception in determine_android_package: %s', e)
887 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600888
Alex Kleinad6b48a2020-01-08 16:57:41 -0700889 # We assume there is only one Android package in the depgraph.
890 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400891 if (package.startswith('chromeos-base/android-container-') or
892 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700893 return package
894 return None
895
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600896
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500897def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600898 """Determine the current Android version in buildroot now and return it.
899
900 This uses the typical portage logic to determine which version of Android
901 is active right now in the buildroot.
902
903 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500904 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500905 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600906
907 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500908 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600909
910 Raises:
911 NoAndroidVersionError: if no unique Android version can be determined.
912 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500913 if not package:
914 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500915 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600916 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500917 cpv = package_info.SplitCPV(package)
918 if not cpv:
919 raise NoAndroidVersionError(
920 'Android version could not be determined for %s' % board)
921 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600922
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700923
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500924def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600925 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500926 if not package:
927 package = determine_android_package(board)
928 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600929 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500930 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600931 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900932 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900933 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600934 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
935 for target in targets:
936 if target in ebuild_content:
937 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
938 if branch is not None:
939 return branch.group(1)
940 raise NoAndroidBranchError(
941 'Android branch could not be determined for %s (ebuild empty?)' % board)
942
943
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500944def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600945 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500946 if not package:
947 package = determine_android_package(board)
948 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600949 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500950 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600951 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500952 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600953 return 'cheets'
954
955 raise NoAndroidTargetError(
956 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500957 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600958
959
960def determine_platform_version():
961 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600962 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600963 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
964 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600965
966
967def determine_milestone_version():
968 """Returns the platform version from the source root."""
969 # Milestone version is something like '79'.
970 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
971 return version.chrome_branch
972
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700973
Michael Mortensen009cb662019-10-21 11:38:43 -0600974def determine_full_version():
975 """Returns the full version from the source root."""
976 # Full version is something like 'R79-12575.0.0'.
977 milestone_version = determine_milestone_version()
978 platform_version = determine_platform_version()
979 full_version = ('R%s-%s' % (milestone_version, platform_version))
980 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600981
982
Michael Mortensende716a12020-05-15 11:27:00 -0600983def find_fingerprints(build_target):
984 """Returns a list of fingerprints for this build.
985
986 Args:
987 build_target (build_target_lib.BuildTarget): The build target.
988
989 Returns:
990 list[str] - List of fingerprint strings.
991 """
992 cros_build_lib.AssertInsideChroot()
993 fp_file = 'cheets-fingerprint.txt'
994 fp_path = os.path.join(
995 image_lib.GetLatestImageLink(build_target.name),
996 fp_file)
997 if not os.path.isfile(fp_path):
998 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600999 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001000 logging.info('Reading fingerprint file: %s', fp_path)
1001 fingerprints = osutils.ReadFile(fp_path).splitlines()
1002 return fingerprints
1003
1004
Michael Mortensen59e30872020-05-18 14:12:49 -06001005def get_all_firmware_versions(build_target):
1006 """Extract firmware version for all models present.
1007
1008 Args:
1009 build_target (build_target_lib.BuildTarget): The build target.
1010
1011 Returns:
1012 A dict of FirmwareVersions namedtuple instances by model.
1013 Each element will be populated based on whether it was present in the
1014 command output.
1015 """
1016 cros_build_lib.AssertInsideChroot()
1017 result = {}
1018 # Note that example output for _get_firmware_version_cmd_result is available
1019 # in the packages_unittest.py for testing get_all_firmware_versions.
1020 cmd_result = _get_firmware_version_cmd_result(build_target)
1021
1022 # There is a blank line between the version info for each model.
1023 firmware_version_payloads = cmd_result.split('\n\n')
1024 for firmware_version_payload in firmware_version_payloads:
1025 if 'BIOS' in firmware_version_payload:
1026 firmware_version = _find_firmware_versions(firmware_version_payload)
1027 result[firmware_version.model] = firmware_version
1028 return result
1029
1030
Michael Mortensen71ef5682020-05-07 14:29:24 -06001031FirmwareVersions = collections.namedtuple(
1032 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1033
1034
1035def get_firmware_versions(build_target):
1036 """Extract version information from the firmware updater, if one exists.
1037
1038 Args:
1039 build_target (build_target_lib.BuildTarget): The build target.
1040
1041 Returns:
1042 A FirmwareVersions namedtuple instance.
1043 Each element will either be set to the string output by the firmware
1044 updater shellball, or None if there is no firmware updater.
1045 """
1046 cros_build_lib.AssertInsideChroot()
1047 cmd_result = _get_firmware_version_cmd_result(build_target)
1048 if cmd_result:
1049 return _find_firmware_versions(cmd_result)
1050 else:
1051 return FirmwareVersions(None, None, None, None, None)
1052
1053
1054def _get_firmware_version_cmd_result(build_target):
1055 """Gets the raw result output of the firmware updater version command.
1056
1057 Args:
1058 build_target (build_target_lib.BuildTarget): The build target.
1059
1060 Returns:
1061 Command execution result.
1062 """
1063 updater = os.path.join(build_target.root,
1064 'usr/sbin/chromeos-firmwareupdate')
1065 logging.info('Calling updater %s', updater)
1066 # Call the updater using the chroot-based path.
1067 return cros_build_lib.run([updater, '-V'],
1068 capture_output=True, log_output=True,
1069 encoding='utf-8').stdout
1070
1071
1072def _find_firmware_versions(cmd_output):
1073 """Finds firmware version output via regex matches against the cmd_output.
1074
1075 Args:
1076 cmd_output: The raw output to search against.
1077
1078 Returns:
1079 FirmwareVersions namedtuple with results.
1080 Each element will either be set to the string output by the firmware
1081 updater shellball, or None if there is no match.
1082 """
1083
1084 # Sometimes a firmware bundle includes a special combination of RO+RW
1085 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1086 # version" field. In other cases, the "(RW) version" field is not present.
1087 # Therefore, search for the "(RW)" fields first and if they aren't present,
1088 # fallback to the other format. e.g. just "BIOS version:".
1089 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1090 main = None
1091 main_rw = None
1092 ec = None
1093 ec_rw = None
1094 model = None
1095
1096 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1097 if match:
1098 main = match.group('version')
1099
1100 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1101 if match:
1102 main_rw = match.group('version')
1103
1104 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1105 if match:
1106 ec = match.group('version')
1107
1108 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1109 if match:
1110 ec_rw = match.group('version')
1111
1112 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1113 if match:
1114 model = match.group('model')
1115
1116 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001117
1118
1119MainEcFirmwareVersions = collections.namedtuple(
1120 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1121
1122def determine_firmware_versions(build_target):
1123 """Returns a namedtuple with main and ec firmware versions.
1124
1125 Args:
1126 build_target (build_target_lib.BuildTarget): The build target.
1127
1128 Returns:
1129 MainEcFirmwareVersions namedtuple with results.
1130 """
1131 fw_versions = get_firmware_versions(build_target)
1132 main_fw_version = fw_versions.main_rw or fw_versions.main
1133 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1134
1135 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001136
1137def determine_kernel_version(build_target):
1138 """Returns a string containing the kernel version for this build target.
1139
1140 Args:
1141 build_target (build_target_lib.BuildTarget): The build target.
1142
1143 Returns:
1144 (str) The kernel versions, or None.
1145 """
1146 try:
1147 packages = portage_util.GetPackageDependencies(build_target.name,
1148 'virtual/linux-sources')
1149 except cros_build_lib.RunCommandError as e:
1150 logging.warning('Unable to get package list for metadata: %s', e)
1151 return None
1152 for package in packages:
1153 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001154 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001155 logging.info('Found active kernel version: %s', kernel_version)
1156 return kernel_version
1157 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001158
1159
1160def get_models(build_target, log_output=True):
1161 """Obtain a list of models supported by a unified board.
1162
1163 This ignored whitelabel models since GoldenEye has no specific support for
1164 these at present.
1165
1166 Args:
1167 build_target (build_target_lib.BuildTarget): The build target.
1168 log_output: Whether to log the output of the cros_config_host invocation.
1169
1170 Returns:
1171 A list of models supported by this board, if it is a unified build; None,
1172 if it is not a unified build.
1173 """
1174 return _run_cros_config_host(build_target, ['list-models'],
1175 log_output=log_output)
1176
1177
Michael Mortensen359c1f32020-05-28 19:35:42 -06001178def get_key_id(build_target, model):
1179 """Obtain the key_id for a model within the build_target.
1180
1181 Args:
1182 build_target (build_target_lib.BuildTarget): The build target.
1183 model (str): The model name
1184
1185 Returns:
1186 A key_id (str) or None.
1187 """
1188 model_arg = '--model=' + model
1189 key_id_list = _run_cros_config_host(
1190 build_target,
1191 [model_arg, 'get', '/firmware-signing', 'key-id'])
1192 key_id = None
1193 if len(key_id_list) == 1:
1194 key_id = key_id_list[0]
1195 return key_id
1196
1197
Michael Mortensen125bb012020-05-21 14:02:10 -06001198def _run_cros_config_host(build_target, args, log_output=True):
1199 """Run the cros_config_host tool.
1200
1201 Args:
1202 build_target (build_target_lib.BuildTarget): The build target.
1203 args: List of arguments to pass.
1204 log_output: Whether to log the output of the cros_config_host.
1205
1206 Returns:
1207 Output of the tool
1208 """
1209 cros_build_lib.AssertInsideChroot()
1210 tool = '/usr/bin/cros_config_host'
1211 if not os.path.isfile(tool):
1212 return None
1213
1214 config_fname = build_target.full_path(
1215 'usr/share/chromeos-config/yaml/config.yaml')
1216
1217 result = cros_build_lib.run(
1218 [tool, '-c', config_fname] + args,
1219 capture_output=True,
1220 encoding='utf-8',
1221 log_output=log_output,
1222 check=False)
1223 if result.returncode:
1224 # Show the output for debugging purposes.
1225 if 'No such file or directory' not in result.error:
1226 logging.error('cros_config_host failed: %s\n', result.error)
1227 return None
1228 return result.output.strip().splitlines()