blob: 92312205c8783d51847bbfc27b58465ea4b3331f [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Package utility functionality."""
7
8from __future__ import print_function
9
Yaakov Shaul730814a2019-09-10 13:58:25 -060010import collections
Ben Reiche779cf42020-12-15 03:21:31 +000011from distutils.version import LooseVersion
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060012import fileinput
Alex Klein87531182019-08-12 15:23:37 -060013import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060014import json
Evan Hernandezb51f1522019-08-15 11:29:40 -060015import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060016import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060017import sys
Alex Klein6becabc2020-09-11 14:03:05 -060018from typing import List, Optional
Alex Klein87531182019-08-12 15:23:37 -060019
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060021
Andrew Lamb2bde9e42019-11-04 13:24:09 -070022from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060023from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060025from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060026from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060028from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060029from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060030from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070031from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060032from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060033from chromite.lib.parser import package_info
Alex Kleineb77ffa2019-05-28 14:47:44 -060034
Alex Klein36b117f2019-09-30 15:13:46 -060035if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060036 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060037 from chromite.service import dependency
38
Alex Klein87531182019-08-12 15:23:37 -060039# Registered handlers for uprevving versioned packages.
40_UPREV_FUNCS = {}
41
Alex Kleineb77ffa2019-05-28 14:47:44 -060042
43class Error(Exception):
44 """Module's base error class."""
45
46
Alex Klein4de25e82019-08-05 15:58:39 -060047class UnknownPackageError(Error):
48 """Uprev attempted for a package without a registered handler."""
49
50
Alex Kleineb77ffa2019-05-28 14:47:44 -060051class UprevError(Error):
52 """An error occurred while uprevving packages."""
53
54
Michael Mortensenb70e8a82019-10-10 18:43:41 -060055class NoAndroidVersionError(Error):
56 """An error occurred while trying to determine the android version."""
57
58
59class NoAndroidBranchError(Error):
60 """An error occurred while trying to determine the android branch."""
61
62
63class NoAndroidTargetError(Error):
64 """An error occurred while trying to determine the android target."""
65
66
Alex Klein4de25e82019-08-05 15:58:39 -060067class AndroidIsPinnedUprevError(UprevError):
68 """Raised when we try to uprev while Android is pinned."""
69
70 def __init__(self, new_android_atom):
71 """Initialize a AndroidIsPinnedUprevError.
72
73 Args:
74 new_android_atom: The Android atom that we failed to
75 uprev to, due to Android being pinned.
76 """
77 assert new_android_atom
78 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
79 new_android_atom)
80 super(AndroidIsPinnedUprevError, self).__init__(msg)
81 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060082
83
Andrew Lamb9563a152019-12-04 11:42:18 -070084class GeneratedCrosConfigFilesError(Error):
85 """Error when cros_config_schema does not produce expected files"""
86
87 def __init__(self, expected_files, found_files):
88 msg = ('Expected to find generated C files: %s. Actually found: %s' %
89 (expected_files, found_files))
90 super(GeneratedCrosConfigFilesError, self).__init__(msg)
91
Alex Klein7a3a7dd2020-01-08 16:44:38 -070092
Alex Klein6becabc2020-09-11 14:03:05 -060093NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
94 'needs_chrome_source',
95 'builds_chrome',
96 'packages',
97 'missing_chrome_prebuilt',
98 'missing_follower_prebuilt',
99))
100
101
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600102def patch_ebuild_vars(ebuild_path, variables):
103 """Updates variables in ebuild.
104
105 Use this function rather than portage_util.EBuild.UpdateEBuild when you
106 want to preserve the variable position and quotes within the ebuild.
107
108 Args:
109 ebuild_path: The path of the ebuild.
110 variables: Dictionary of variables to update in ebuild.
111 """
112 try:
113 for line in fileinput.input(ebuild_path, inplace=1):
114 varname, eq, _ = line.partition('=')
115 if eq == '=' and varname.strip() in variables:
116 value = variables[varname]
117 sys.stdout.write('%s="%s"\n' % (varname, value))
118 else:
119 sys.stdout.write(line)
120 finally:
121 fileinput.close()
122
123
Alex Klein87531182019-08-12 15:23:37 -0600124def uprevs_versioned_package(package):
125 """Decorator to register package uprev handlers."""
126 assert package
127
128 def register(func):
129 """Registers |func| as a handler for |package|."""
130 _UPREV_FUNCS[package] = func
131
132 @functools.wraps(func)
133 def pass_through(*args, **kwargs):
134 return func(*args, **kwargs)
135
136 return pass_through
137
138 return register
139
140
Shao-Chuan Leeb6a2cb62021-02-19 14:18:59 +0900141def uprev_android(android_package,
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700142 chroot,
143 build_targets=None,
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900144 android_build_branch=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900145 android_version=None,
146 skip_commit=False):
Alex Klein4de25e82019-08-05 15:58:39 -0600147 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700148 command = [
149 'cros_mark_android_as_stable',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900150 f'--android_package={android_package}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700151 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600152 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900153 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Shao-Chuan Leea4b4f302021-05-12 14:40:20 +0900154 if android_build_branch:
155 command.append(f'--android_build_branch={android_build_branch}')
Alex Klein4de25e82019-08-05 15:58:39 -0600156 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900157 command.append(f'--force_version={android_version}')
158 if skip_commit:
159 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600160
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700161 result = cros_build_lib.run(
162 command,
163 stdout=True,
164 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500165 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700166 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600167
Mike Frysinger88d96362020-02-14 19:05:45 -0500168 portage_atom_string = result.stdout.strip()
169 android_atom = None
170 if portage_atom_string:
171 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600172 if not android_atom:
173 logging.info('Found nothing to rev.')
174 return None
175
176 for target in build_targets or []:
177 # Sanity check: We should always be able to merge the version of
178 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900179 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600180 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700181 cros_build_lib.run(
182 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600183 except cros_build_lib.RunCommandError:
184 logging.error(
185 'Cannot emerge-%s =%s\nIs Android pinned to an older '
186 'version?', target, android_atom)
187 raise AndroidIsPinnedUprevError(android_atom)
188
189 return android_atom
190
191
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700192def uprev_build_targets(build_targets,
193 overlay_type,
194 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600195 output_dir=None):
196 """Uprev the set provided build targets, or all if not specified.
197
198 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600199 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600200 whose overlays should be uprevved, empty or None for all.
201 overlay_type (str): One of the valid overlay types except None (see
202 constants.VALID_OVERLAYS).
203 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
204 output_dir (str|None): The path to optionally dump result files.
205 """
206 # Need a valid overlay, but exclude None.
207 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
208
209 if build_targets:
210 overlays = portage_util.FindOverlaysForBoards(
211 overlay_type, boards=[t.name for t in build_targets])
212 else:
213 overlays = portage_util.FindOverlays(overlay_type)
214
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700215 return uprev_overlays(
216 overlays,
217 build_targets=build_targets,
218 chroot=chroot,
219 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600220
221
222def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
223 """Uprev the given overlays.
224
225 Args:
226 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600227 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600228 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
229 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
230 output_dir (str|None): The path to optionally dump result files.
231
232 Returns:
233 list[str] - The paths to all of the modified ebuild files. This includes the
234 new files that were added (i.e. the new versions) and all of the removed
235 files (i.e. the old versions).
236 """
237 assert overlays
238
239 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
240
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700241 uprev_manager = uprev_lib.UprevOverlayManager(
242 overlays,
243 manifest,
244 build_targets=build_targets,
245 chroot=chroot,
246 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600247 uprev_manager.uprev()
248
249 return uprev_manager.modified_ebuilds
250
251
Alex Klein87531182019-08-12 15:23:37 -0600252def uprev_versioned_package(package, build_targets, refs, chroot):
253 """Call registered uprev handler function for the package.
254
255 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600256 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600257 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600258 clean on a successful uprev.
259 refs (list[uprev_lib.GitRef]):
260 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
261
262 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600263 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600264 """
265 assert package
266
267 if package.cp not in _UPREV_FUNCS:
268 raise UnknownPackageError(
269 'Package "%s" does not have a registered handler.' % package.cp)
270
Andrew Lambea9a8a22019-12-12 14:03:43 -0700271 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600272
273
Navil Perezf57ba872020-06-04 22:38:37 +0000274@uprevs_versioned_package('media-libs/virglrenderer')
275def uprev_virglrenderer(_build_targets, refs, _chroot):
276 """Updates virglrenderer ebuilds.
277
278 See: uprev_versioned_package.
279
280 Returns:
281 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
282 """
Navil Perezf57ba872020-06-04 22:38:37 +0000283 overlay = os.path.join(constants.SOURCE_ROOT,
284 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600285 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
286 'virglrenderer')
287 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000288
289 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
290 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000291 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
292 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000293 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
294
George Engelbrechte73f2782020-06-10 14:10:46 -0600295 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600296 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000297 result.add_result(refs[0].revision, updated_files)
298 return result
299
Jose Magana03b5a842020-08-19 12:52:59 +1000300@uprevs_versioned_package('chromeos-base/drivefs')
301def uprev_drivefs(_build_targets, refs, chroot):
302 """Updates drivefs ebuilds.
303
Harvey Yang3eee06c2021-03-18 15:47:56 +0800304 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000305 See: uprev_versioned_package.
306
307 Returns:
308 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
309 """
310
Ben Reiche779cf42020-12-15 03:21:31 +0000311 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000312 result = uprev_lib.UprevVersionedPackageResult()
313 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000314
Harvey Yang3eee06c2021-03-18 15:47:56 +0800315 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
316 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000317 if not drivefs_version:
318 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000319 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000320
Ben Reiche779cf42020-12-15 03:21:31 +0000321 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000322
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000323 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000324 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000325 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000326 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800327 chroot,
328 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000329
330 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000331 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000332 all_changed_files.extend(uprev_result.changed_files)
333
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000334 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000335 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000336 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000337 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800338 chroot,
339 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000340
341 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000342 logging.warning(
343 'drivefs package has changed files %s but drivefs-ipc does not',
344 all_changed_files)
345 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000346
347 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000348 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000349
350 return result
351
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800352@uprevs_versioned_package('chromeos-base/perfetto')
353def uprev_perfetto(_build_targets, refs, chroot):
354 """Updates Perfetto ebuilds.
355
Harvey Yang3eee06c2021-03-18 15:47:56 +0800356 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800357 See: uprev_versioned_package.
358
359 Returns:
360 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
361 """
362 result = uprev_lib.UprevVersionedPackageResult()
363
Harvey Yang3eee06c2021-03-18 15:47:56 +0800364 PERFETTO_REFS_PREFIX = 'refs/tags/v'
365 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800366 if not perfetto_version:
367 # No valid Perfetto version is identified.
368 return result
369
370 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
371
372 # Attempt to uprev perfetto package.
373 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
374
Harvey Yang3eee06c2021-03-18 15:47:56 +0800375 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
376 PERFETTO_PATH,
377 perfetto_version,
378 chroot,
379 allow_downrev=False,
380 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800381
382 if not uprev_result:
383 return result
384
385 result.add_result(perfetto_version, uprev_result.changed_files)
386
387 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000388
Yaakov Shaul395ae832019-09-09 14:45:32 -0600389@uprevs_versioned_package('afdo/kernel-profiles')
390def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600391 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600392
393 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600394
395 Raises:
396 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600397 """
398 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
399 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
400
David Burger92485342019-09-10 17:52:45 -0600401 with open(path, 'r') as f:
402 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600403
Chris McDonald38409112020-09-24 11:24:51 -0600404 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600405 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600406 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
407 'sys-kernel', version)
408 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
409 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600410 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
411 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600412 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600413 patch_ebuild_vars(ebuild_path,
414 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600415
416 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600417 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400418 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600419 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600420 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600421 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600422 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600423
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600424 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600425
Yaakov Shaul730814a2019-09-10 13:58:25 -0600426 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
427
428 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600429
430
Trent Begineb624182020-07-14 10:09:45 -0600431@uprevs_versioned_package('chromeos-base/termina-dlc')
432def uprev_termina_dlc(_build_targets, _refs, chroot):
433 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600434
435 See: uprev_versioned_package.
436 """
Trent Begineb624182020-07-14 10:09:45 -0600437 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600438 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
439 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000440
441 version_pin_src_path = _get_version_pin_src_path(package_path)
442 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
443
Chris McDonald38409112020-09-24 11:24:51 -0600444 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000445
446
Julio Hurtadof1befec2021-05-05 21:34:26 +0000447@uprevs_versioned_package('chromeos-base/chromeos-lacros')
448def uprev_lacros(_build_targets, refs, chroot):
449 """Updates lacros ebuilds.
450
451 Information used is gathered from the QA qualified version tracking file
452 stored in chromium/src.
453
454 See: uprev_versioned_package.
455 """
456 path = os.path.join(
457 constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base','chromeos-lacros')
458 return uprev_lib.uprev_ebuild_from_pin(path, refs[0].revision, chroot)
459
460
Patrick Meiring5897add2020-09-16 16:30:17 +1000461@uprevs_versioned_package('app-emulation/parallels-desktop')
462def uprev_parallels_desktop(_build_targets, _refs, chroot):
463 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
464
465 See: uprev_versioned_package
466
467 Returns:
468 UprevVersionedPackageResult: The result.
469 """
470 package = 'parallels-desktop'
471 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
472 'app-emulation', package)
473 version_pin_src_path = _get_version_pin_src_path(package_path)
474
475 # Expect a JSON blob like the following:
476 # {
477 # "version": "1.2.3",
478 # "test_image": { "url": "...", "size": 12345678,
479 # "sha256sum": "<32 bytes of hexadecimal>" }
480 # }
481 with open(version_pin_src_path, 'r') as f:
482 pinned = json.load(f)
483
484 if 'version' not in pinned or 'test_image' not in pinned:
485 raise UprevError('VERSION-PIN for %s missing version and/or '
486 'test_image field' % package)
487
488 version = pinned['version']
489 if not isinstance(version, str):
490 raise UprevError('version in VERSION-PIN for %s not a string' % package)
491
492 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600493 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000494
495 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100496 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
497 'local/bundles/crosint/pita/data/'
498 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000499 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
500 with open(test_image_src_path, 'w') as f:
501 json.dump(pinned['test_image'], f, indent=2)
502 result.add_result(version, [test_image_src_path])
503
504 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600505
506
Trent Begin315d9d92019-12-03 21:55:53 -0700507@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600508def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700509 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
510
511 See: uprev_versioned_package.
512 """
513 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700514 package_path = os.path.join('src', 'private-overlays',
515 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000516 version_pin_src_path = _get_version_pin_src_path(package_path)
517 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700518
Chris McDonald38409112020-09-24 11:24:51 -0600519 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700520
521
Patrick Meiring5897add2020-09-16 16:30:17 +1000522def _get_version_pin_src_path(package_path):
523 """Returns the path to the VERSION-PIN file for the given package."""
524 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
525
526
Alex Klein87531182019-08-12 15:23:37 -0600527@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700528def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600529 """Uprev chrome and its related packages.
530
531 See: uprev_versioned_package.
532 """
533 # Determine the version from the refs (tags), i.e. the chrome versions are the
534 # tag names.
535 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600536 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600537
538 uprev_manager = uprev_lib.UprevChromeManager(
539 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600540 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600541 # Start with chrome itself, as we can't do anything else unless chrome
542 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600543 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
544 # attempt. The expected behavior is documented in the following table:
545 #
546 # Outcome of Chrome uprev attempt:
547 # NEWER_VERSION_EXISTS:
548 # Do nothing.
549 # SAME_VERSION_EXISTS or REVISION_BUMP:
550 # Uprev followers
551 # Assert not VERSION_BUMP (any other outcome is fine)
552 # VERSION_BUMP or NEW_EBUILD_CREATED:
553 # Uprev followers
554 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600555 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600556 return result
Alex Klein87531182019-08-12 15:23:37 -0600557
558 # With a successful chrome rev, also uprev related packages.
559 for package in constants.OTHER_CHROME_PACKAGES:
560 uprev_manager.uprev(package)
561
David Burger37f48672019-09-18 17:07:56 -0600562 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600563
564
Harvey Yang3eee06c2021-03-18 15:47:56 +0800565def _get_latest_version_from_refs(refs_prefix: str,
566 refs: List[uprev_lib.GitRef]) -> str:
567 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000568
Ben Reiche779cf42020-12-15 03:21:31 +0000569 Versions are compared using |distutils.version.LooseVersion| and
570 the latest version is returned.
571
572 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800573 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800574 refs: The tags to parse for the latest Perfetto version.
575
576 Returns:
577 The latest Perfetto version to use.
578 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800579 valid_refs = []
580 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800581 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800582 valid_refs.append(gitiles.ref)
583
584 if not valid_refs:
585 return None
586
587 # Sort by version and take the latest version.
588 target_version_ref = sorted(valid_refs,
589 key=LooseVersion,
590 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800591 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800592
593
Andrew Lamb9563a152019-12-04 11:42:18 -0700594def _generate_platform_c_files(replication_config, chroot):
595 """Generates platform C files from a platform JSON payload.
596
597 Args:
598 replication_config (replication_config_pb2.ReplicationConfig): A
599 ReplicationConfig that has already been run. If it produced a
600 build_config.json file, that file will be used to generate platform C
601 files. Otherwise, nothing will be generated.
602 chroot (chroot_lib.Chroot): The chroot to use to generate.
603
604 Returns:
605 A list of generated files.
606 """
607 # Generate the platform C files from the build config. Note that it would be
608 # more intuitive to generate the platform C files from the platform config;
609 # however, cros_config_schema does not allow this, because the platform config
610 # payload is not always valid input. For example, if a property is both
611 # 'required' and 'build-only', it will fail schema validation. Thus, use the
612 # build config, and use '-f' to filter.
613 build_config_path = [
614 rule.destination_path
615 for rule in replication_config.file_replication_rules
616 if rule.destination_path.endswith('build_config.json')
617 ]
618
619 if not build_config_path:
620 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700621 'No build_config.json found, will not generate platform C files. '
622 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700623 return []
624
625 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700626 raise ValueError('Expected at most one build_config.json destination path. '
627 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700628
629 build_config_path = build_config_path[0]
630
631 # Paths to the build_config.json and dir to output C files to, in the
632 # chroot.
633 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
634 build_config_path)
635 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
636 os.path.dirname(build_config_path))
637
638 command = [
639 'cros_config_schema', '-m', build_config_chroot_path, '-g',
640 generated_output_chroot_dir, '-f', '"TRUE"'
641 ]
642
643 cros_build_lib.run(
644 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
645
646 # A relative (to the source root) path to the generated C files.
647 generated_output_dir = os.path.dirname(build_config_path)
648 generated_files = []
649 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
650 for f in expected_c_files:
651 if os.path.exists(
652 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
653 generated_files.append(os.path.join(generated_output_dir, f))
654
655 if len(expected_c_files) != len(generated_files):
656 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
657
658 return generated_files
659
660
Andrew Lambe836f222019-12-09 12:27:38 -0700661def _get_private_overlay_package_root(ref, package):
662 """Returns the absolute path to the root of a given private overlay.
663
664 Args:
665 ref (uprev_lib.GitRef): GitRef for the private overlay.
666 package (str): Path to the package in the overlay.
667 """
668 # There might be a cleaner way to map from package -> path within the source
669 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700670 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700671 match = re.match(private_overlay_ref_pattern, ref.path)
672 if not match:
673 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
674 (private_overlay_ref_pattern, ref))
675
676 overlay = match.group(1)
677
678 return os.path.join(constants.SOURCE_ROOT,
679 'src/private-overlays/overlay-%s-private' % overlay,
680 package)
681
682
Andrew Lambea9a8a22019-12-12 14:03:43 -0700683@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
684def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700685 """Replicate a private cros_config change to the corresponding public config.
686
Alex Kleinad6b48a2020-01-08 16:57:41 -0700687 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700688 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700689 package = 'chromeos-base/chromeos-config-bsp'
690
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700691 if len(refs) != 1:
692 raise ValueError('Expected exactly one ref, actual %s' % refs)
693
694 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700695 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700696 replication_config_path = os.path.join(package_root,
697 'replication_config.jsonpb')
698
699 try:
700 replication_config = json_format.Parse(
701 osutils.ReadFile(replication_config_path),
702 replication_config_pb2.ReplicationConfig())
703 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700704 raise ValueError(
705 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700706
707 replication_lib.Replicate(replication_config)
708
709 modified_files = [
710 rule.destination_path
711 for rule in replication_config.file_replication_rules
712 ]
713
Andrew Lamb9563a152019-12-04 11:42:18 -0700714 # The generated platform C files are not easily filtered by replication rules,
715 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
716 # files cannot. Therefore, replicate and filter the JSON payloads, and then
717 # generate filtered C files from the JSON payload.
718 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700719
720 # Use the private repo's commit hash as the new version.
721 new_private_version = refs[0].revision
722
Andrew Lamb988f4da2019-12-10 10:16:43 -0700723 # modified_files should contain only relative paths at this point, but the
724 # returned UprevVersionedPackageResult must contain only absolute paths.
725 for i, modified_file in enumerate(modified_files):
726 assert not os.path.isabs(modified_file)
727 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
728
Chris McDonald38409112020-09-24 11:24:51 -0600729 return uprev_lib.UprevVersionedPackageResult().add_result(
730 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700731
732
Alex Kleinbbef2b32019-08-27 10:38:50 -0600733def get_best_visible(atom, build_target=None):
734 """Returns the best visible CPV for the given atom.
735
736 Args:
737 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600738 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600739 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700740
741 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600742 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600743 """
David Burger1e0fe232019-07-01 14:52:07 -0600744 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600745
746 board = build_target.name if build_target else None
747 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600748
749
Alex Klein149fd3b2019-12-16 16:01:05 -0700750def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600751 """Check if a prebuilt exists.
752
753 Args:
754 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600755 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600756 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700757 useflags: Any additional USE flags that should be set. May be a string
758 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700759
760 Returns:
761 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600762 """
763 assert atom
764
765 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700766 extra_env = None
767 if useflags:
768 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500769 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700770 new_flags = ' '.join(useflags)
771
772 existing = os.environ.get('USE', '')
773 final_flags = '%s %s' % (existing, new_flags)
774 extra_env = {'USE': final_flags.strip()}
775 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600776
777
David Burger0f9dd4e2019-10-08 12:33:42 -0600778def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600779 """Check if |build_target| builds |atom| (has it in its depgraph)."""
780 cros_build_lib.AssertInsideChroot()
781
Alex Kleind8cd4c62020-09-14 13:37:47 -0600782 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600783 # TODO(crbug/1081828): Receive and use sysroot.
784 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600785 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600786 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600787
788
Alex Klein6becabc2020-09-11 14:03:05 -0600789def needs_chrome_source(
790 build_target: 'build_target_lib.BuildTarget',
791 compile_source=False,
792 packages: Optional[List[package_info.PackageInfo]] = None,
793 useflags=None):
794 """Check if the chrome source is needed.
795
796 The chrome source is needed if the build target builds chrome or any of its
797 follower packages, and can't use a prebuilt for them either because it's not
798 available, or because we can't use prebuilts because it must build from
799 source.
800 """
801 cros_build_lib.AssertInsideChroot()
802
803 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700804 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600805 builds_chrome = constants.CHROME_CP in graph
806 builds_follower = {
807 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
808 }
809
810 # When we are compiling source set False since we do not use prebuilts.
811 # When not compiling from source, start with True, i.e. we have every prebuilt
812 # we've checked for up to this point.
813 has_chrome_prebuilt = not compile_source
814 has_follower_prebuilts = not compile_source
815 # Save packages that need prebuilts for reporting.
816 pkgs_needing_prebuilts = []
817 if compile_source:
818 # Need everything.
819 pkgs_needing_prebuilts.append(constants.CHROME_CP)
820 pkgs_needing_prebuilts.extend(
821 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
822 else:
823 # Check chrome itself.
824 if builds_chrome:
825 has_chrome_prebuilt = has_prebuilt(
826 constants.CHROME_CP, build_target=build_target, useflags=useflags)
827 if not has_chrome_prebuilt:
828 pkgs_needing_prebuilts.append(constants.CHROME_CP)
829 # Check follower packages.
830 for pkg, builds_pkg in builds_follower.items():
831 if not builds_pkg:
832 continue
833 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
834 has_follower_prebuilts &= prebuilt
835 if not prebuilt:
836 pkgs_needing_prebuilts.append(pkg)
837 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
838 # reflect whether we actually have the corresponding prebuilts for the build.
839
840 needs_chrome = builds_chrome and not has_chrome_prebuilt
841 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
842
843 return NeedsChromeSourceResult(
844 needs_chrome_source=needs_chrome or needs_follower,
845 builds_chrome=builds_chrome,
846 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
847 missing_chrome_prebuilt=not has_chrome_prebuilt,
848 missing_follower_prebuilt=not has_follower_prebuilts)
849
850
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600851def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600852 """Returns the current Chrome version for the board (or in buildroot).
853
854 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600855 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700856
857 Returns:
858 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600859 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600860 # TODO(crbug/1019770): Long term we should not need the try/catch here once
861 # the builds function above only returns True for chrome when
862 # determine_chrome_version will succeed.
863 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700864 cpv = portage_util.PortageqBestVisible(
865 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600866 except cros_build_lib.RunCommandError as e:
867 # Return None because portage failed when trying to determine the chrome
868 # version.
869 logging.warning('Caught exception in determine_chrome_package: %s', e)
870 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600871 # Something like 78.0.3877.4_rc -> 78.0.3877.4
872 return cpv.version_no_rev.partition('_')[0]
873
874
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600875def determine_android_package(board):
876 """Returns the active Android container package in use by the board.
877
878 Args:
879 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700880
881 Returns:
882 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600883 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600884 try:
885 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600886 except cros_build_lib.RunCommandError as e:
887 # Return None because a command (likely portage) failed when trying to
888 # determine the package.
889 logging.warning('Caught exception in determine_android_package: %s', e)
890 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600891
Alex Kleinad6b48a2020-01-08 16:57:41 -0700892 # We assume there is only one Android package in the depgraph.
893 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400894 if (package.startswith('chromeos-base/android-container-') or
895 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700896 return package
897 return None
898
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600899
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500900def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600901 """Determine the current Android version in buildroot now and return it.
902
903 This uses the typical portage logic to determine which version of Android
904 is active right now in the buildroot.
905
906 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500907 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500908 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600909
910 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500911 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600912
913 Raises:
914 NoAndroidVersionError: if no unique Android version can be determined.
915 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500916 if not package:
917 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500918 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600919 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500920 cpv = package_info.SplitCPV(package)
921 if not cpv:
922 raise NoAndroidVersionError(
923 'Android version could not be determined for %s' % board)
924 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600925
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700926
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500927def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600928 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500929 if not package:
930 package = determine_android_package(board)
931 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600932 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500933 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600934 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900935 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900936 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600937 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
938 for target in targets:
939 if target in ebuild_content:
940 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
941 if branch is not None:
942 return branch.group(1)
943 raise NoAndroidBranchError(
944 'Android branch could not be determined for %s (ebuild empty?)' % board)
945
946
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500947def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600948 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500949 if not package:
950 package = determine_android_package(board)
951 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600952 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500953 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600954 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500955 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600956 return 'cheets'
957
958 raise NoAndroidTargetError(
959 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500960 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600961
962
963def determine_platform_version():
964 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600965 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600966 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
967 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600968
969
970def determine_milestone_version():
971 """Returns the platform version from the source root."""
972 # Milestone version is something like '79'.
973 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
974 return version.chrome_branch
975
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700976
Michael Mortensen009cb662019-10-21 11:38:43 -0600977def determine_full_version():
978 """Returns the full version from the source root."""
979 # Full version is something like 'R79-12575.0.0'.
980 milestone_version = determine_milestone_version()
981 platform_version = determine_platform_version()
982 full_version = ('R%s-%s' % (milestone_version, platform_version))
983 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600984
985
Michael Mortensende716a12020-05-15 11:27:00 -0600986def find_fingerprints(build_target):
987 """Returns a list of fingerprints for this build.
988
989 Args:
990 build_target (build_target_lib.BuildTarget): The build target.
991
992 Returns:
993 list[str] - List of fingerprint strings.
994 """
995 cros_build_lib.AssertInsideChroot()
996 fp_file = 'cheets-fingerprint.txt'
997 fp_path = os.path.join(
998 image_lib.GetLatestImageLink(build_target.name),
999 fp_file)
1000 if not os.path.isfile(fp_path):
1001 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001002 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001003 logging.info('Reading fingerprint file: %s', fp_path)
1004 fingerprints = osutils.ReadFile(fp_path).splitlines()
1005 return fingerprints
1006
1007
Michael Mortensen59e30872020-05-18 14:12:49 -06001008def get_all_firmware_versions(build_target):
1009 """Extract firmware version for all models present.
1010
1011 Args:
1012 build_target (build_target_lib.BuildTarget): The build target.
1013
1014 Returns:
1015 A dict of FirmwareVersions namedtuple instances by model.
1016 Each element will be populated based on whether it was present in the
1017 command output.
1018 """
1019 cros_build_lib.AssertInsideChroot()
1020 result = {}
1021 # Note that example output for _get_firmware_version_cmd_result is available
1022 # in the packages_unittest.py for testing get_all_firmware_versions.
1023 cmd_result = _get_firmware_version_cmd_result(build_target)
1024
1025 # There is a blank line between the version info for each model.
1026 firmware_version_payloads = cmd_result.split('\n\n')
1027 for firmware_version_payload in firmware_version_payloads:
1028 if 'BIOS' in firmware_version_payload:
1029 firmware_version = _find_firmware_versions(firmware_version_payload)
1030 result[firmware_version.model] = firmware_version
1031 return result
1032
1033
Michael Mortensen71ef5682020-05-07 14:29:24 -06001034FirmwareVersions = collections.namedtuple(
1035 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1036
1037
1038def get_firmware_versions(build_target):
1039 """Extract version information from the firmware updater, if one exists.
1040
1041 Args:
1042 build_target (build_target_lib.BuildTarget): The build target.
1043
1044 Returns:
1045 A FirmwareVersions namedtuple instance.
1046 Each element will either be set to the string output by the firmware
1047 updater shellball, or None if there is no firmware updater.
1048 """
1049 cros_build_lib.AssertInsideChroot()
1050 cmd_result = _get_firmware_version_cmd_result(build_target)
1051 if cmd_result:
1052 return _find_firmware_versions(cmd_result)
1053 else:
1054 return FirmwareVersions(None, None, None, None, None)
1055
1056
1057def _get_firmware_version_cmd_result(build_target):
1058 """Gets the raw result output of the firmware updater version command.
1059
1060 Args:
1061 build_target (build_target_lib.BuildTarget): The build target.
1062
1063 Returns:
1064 Command execution result.
1065 """
1066 updater = os.path.join(build_target.root,
1067 'usr/sbin/chromeos-firmwareupdate')
1068 logging.info('Calling updater %s', updater)
1069 # Call the updater using the chroot-based path.
1070 return cros_build_lib.run([updater, '-V'],
1071 capture_output=True, log_output=True,
1072 encoding='utf-8').stdout
1073
1074
1075def _find_firmware_versions(cmd_output):
1076 """Finds firmware version output via regex matches against the cmd_output.
1077
1078 Args:
1079 cmd_output: The raw output to search against.
1080
1081 Returns:
1082 FirmwareVersions namedtuple with results.
1083 Each element will either be set to the string output by the firmware
1084 updater shellball, or None if there is no match.
1085 """
1086
1087 # Sometimes a firmware bundle includes a special combination of RO+RW
1088 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1089 # version" field. In other cases, the "(RW) version" field is not present.
1090 # Therefore, search for the "(RW)" fields first and if they aren't present,
1091 # fallback to the other format. e.g. just "BIOS version:".
1092 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1093 main = None
1094 main_rw = None
1095 ec = None
1096 ec_rw = None
1097 model = None
1098
1099 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1100 if match:
1101 main = match.group('version')
1102
1103 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1104 if match:
1105 main_rw = match.group('version')
1106
1107 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1108 if match:
1109 ec = match.group('version')
1110
1111 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1112 if match:
1113 ec_rw = match.group('version')
1114
1115 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1116 if match:
1117 model = match.group('model')
1118
1119 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001120
1121
1122MainEcFirmwareVersions = collections.namedtuple(
1123 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1124
1125def determine_firmware_versions(build_target):
1126 """Returns a namedtuple with main and ec firmware versions.
1127
1128 Args:
1129 build_target (build_target_lib.BuildTarget): The build target.
1130
1131 Returns:
1132 MainEcFirmwareVersions namedtuple with results.
1133 """
1134 fw_versions = get_firmware_versions(build_target)
1135 main_fw_version = fw_versions.main_rw or fw_versions.main
1136 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1137
1138 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001139
1140def determine_kernel_version(build_target):
1141 """Returns a string containing the kernel version for this build target.
1142
1143 Args:
1144 build_target (build_target_lib.BuildTarget): The build target.
1145
1146 Returns:
1147 (str) The kernel versions, or None.
1148 """
1149 try:
1150 packages = portage_util.GetPackageDependencies(build_target.name,
1151 'virtual/linux-sources')
1152 except cros_build_lib.RunCommandError as e:
1153 logging.warning('Unable to get package list for metadata: %s', e)
1154 return None
1155 for package in packages:
1156 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001157 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001158 logging.info('Found active kernel version: %s', kernel_version)
1159 return kernel_version
1160 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001161
1162
1163def get_models(build_target, log_output=True):
1164 """Obtain a list of models supported by a unified board.
1165
1166 This ignored whitelabel models since GoldenEye has no specific support for
1167 these at present.
1168
1169 Args:
1170 build_target (build_target_lib.BuildTarget): The build target.
1171 log_output: Whether to log the output of the cros_config_host invocation.
1172
1173 Returns:
1174 A list of models supported by this board, if it is a unified build; None,
1175 if it is not a unified build.
1176 """
1177 return _run_cros_config_host(build_target, ['list-models'],
1178 log_output=log_output)
1179
1180
Michael Mortensen359c1f32020-05-28 19:35:42 -06001181def get_key_id(build_target, model):
1182 """Obtain the key_id for a model within the build_target.
1183
1184 Args:
1185 build_target (build_target_lib.BuildTarget): The build target.
1186 model (str): The model name
1187
1188 Returns:
1189 A key_id (str) or None.
1190 """
1191 model_arg = '--model=' + model
1192 key_id_list = _run_cros_config_host(
1193 build_target,
1194 [model_arg, 'get', '/firmware-signing', 'key-id'])
1195 key_id = None
1196 if len(key_id_list) == 1:
1197 key_id = key_id_list[0]
1198 return key_id
1199
1200
Michael Mortensen125bb012020-05-21 14:02:10 -06001201def _run_cros_config_host(build_target, args, log_output=True):
1202 """Run the cros_config_host tool.
1203
1204 Args:
1205 build_target (build_target_lib.BuildTarget): The build target.
1206 args: List of arguments to pass.
1207 log_output: Whether to log the output of the cros_config_host.
1208
1209 Returns:
1210 Output of the tool
1211 """
1212 cros_build_lib.AssertInsideChroot()
1213 tool = '/usr/bin/cros_config_host'
1214 if not os.path.isfile(tool):
1215 return None
1216
1217 config_fname = build_target.full_path(
1218 'usr/share/chromeos-config/yaml/config.yaml')
1219
1220 result = cros_build_lib.run(
1221 [tool, '-c', config_fname] + args,
1222 capture_output=True,
1223 encoding='utf-8',
1224 log_output=log_output,
1225 check=False)
1226 if result.returncode:
1227 # Show the output for debugging purposes.
1228 if 'No such file or directory' not in result.error:
1229 logging.error('cros_config_host failed: %s\n', result.error)
1230 return None
1231 return result.output.strip().splitlines()