blob: 88c43d79855f93104ff83e66b478534bfc98e644 [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
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700141def uprev_android(tracking_branch,
142 android_package,
143 android_build_branch,
144 chroot,
145 build_targets=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900146 android_version=None,
147 skip_commit=False):
Alex Klein4de25e82019-08-05 15:58:39 -0600148 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700149 command = [
150 'cros_mark_android_as_stable',
Shao-Chuan Leec3406922021-02-19 13:58:14 +0900151 f'--tracking_branch={tracking_branch}',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900152 f'--android_package={android_package}',
153 f'--android_build_branch={android_build_branch}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700154 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600155 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900156 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Alex Klein4de25e82019-08-05 15:58:39 -0600157 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900158 command.append(f'--force_version={android_version}')
159 if skip_commit:
160 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600161
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700162 result = cros_build_lib.run(
163 command,
164 stdout=True,
165 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500166 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700167 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600168
Mike Frysinger88d96362020-02-14 19:05:45 -0500169 portage_atom_string = result.stdout.strip()
170 android_atom = None
171 if portage_atom_string:
172 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600173 if not android_atom:
174 logging.info('Found nothing to rev.')
175 return None
176
177 for target in build_targets or []:
178 # Sanity check: We should always be able to merge the version of
179 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900180 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600181 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700182 cros_build_lib.run(
183 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600184 except cros_build_lib.RunCommandError:
185 logging.error(
186 'Cannot emerge-%s =%s\nIs Android pinned to an older '
187 'version?', target, android_atom)
188 raise AndroidIsPinnedUprevError(android_atom)
189
190 return android_atom
191
192
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700193def uprev_build_targets(build_targets,
194 overlay_type,
195 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600196 output_dir=None):
197 """Uprev the set provided build targets, or all if not specified.
198
199 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600200 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600201 whose overlays should be uprevved, empty or None for all.
202 overlay_type (str): One of the valid overlay types except None (see
203 constants.VALID_OVERLAYS).
204 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
205 output_dir (str|None): The path to optionally dump result files.
206 """
207 # Need a valid overlay, but exclude None.
208 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
209
210 if build_targets:
211 overlays = portage_util.FindOverlaysForBoards(
212 overlay_type, boards=[t.name for t in build_targets])
213 else:
214 overlays = portage_util.FindOverlays(overlay_type)
215
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700216 return uprev_overlays(
217 overlays,
218 build_targets=build_targets,
219 chroot=chroot,
220 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600221
222
223def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
224 """Uprev the given overlays.
225
226 Args:
227 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600228 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600229 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
230 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
231 output_dir (str|None): The path to optionally dump result files.
232
233 Returns:
234 list[str] - The paths to all of the modified ebuild files. This includes the
235 new files that were added (i.e. the new versions) and all of the removed
236 files (i.e. the old versions).
237 """
238 assert overlays
239
240 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
241
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700242 uprev_manager = uprev_lib.UprevOverlayManager(
243 overlays,
244 manifest,
245 build_targets=build_targets,
246 chroot=chroot,
247 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600248 uprev_manager.uprev()
249
250 return uprev_manager.modified_ebuilds
251
252
Alex Klein87531182019-08-12 15:23:37 -0600253def uprev_versioned_package(package, build_targets, refs, chroot):
254 """Call registered uprev handler function for the package.
255
256 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600257 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600258 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600259 clean on a successful uprev.
260 refs (list[uprev_lib.GitRef]):
261 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
262
263 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600264 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600265 """
266 assert package
267
268 if package.cp not in _UPREV_FUNCS:
269 raise UnknownPackageError(
270 'Package "%s" does not have a registered handler.' % package.cp)
271
Andrew Lambea9a8a22019-12-12 14:03:43 -0700272 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600273
274
Navil Perezf57ba872020-06-04 22:38:37 +0000275@uprevs_versioned_package('media-libs/virglrenderer')
276def uprev_virglrenderer(_build_targets, refs, _chroot):
277 """Updates virglrenderer ebuilds.
278
279 See: uprev_versioned_package.
280
281 Returns:
282 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
283 """
Navil Perezf57ba872020-06-04 22:38:37 +0000284 overlay = os.path.join(constants.SOURCE_ROOT,
285 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600286 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
287 'virglrenderer')
288 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000289
290 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
291 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000292 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
293 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000294 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
295
George Engelbrechte73f2782020-06-10 14:10:46 -0600296 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600297 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000298 result.add_result(refs[0].revision, updated_files)
299 return result
300
Jose Magana03b5a842020-08-19 12:52:59 +1000301@uprevs_versioned_package('chromeos-base/drivefs')
302def uprev_drivefs(_build_targets, refs, chroot):
303 """Updates drivefs ebuilds.
304
305 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
Ben Reiche779cf42020-12-15 03:21:31 +0000315 drivefs_version = get_latest_drivefs_version_from_refs(refs)
316 if not drivefs_version:
317 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000318 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000319
Ben Reiche779cf42020-12-15 03:21:31 +0000320 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000321
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000322 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000323 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000324 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000325 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000326 chroot)
Jose Magana03b5a842020-08-19 12:52:59 +1000327
328 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000329 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000330 all_changed_files.extend(uprev_result.changed_files)
331
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000332 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000333 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000334 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000335 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000336 chroot)
337
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
Navil Perezf57ba872020-06-04 22:38:37 +0000349
Yaakov Shaul395ae832019-09-09 14:45:32 -0600350@uprevs_versioned_package('afdo/kernel-profiles')
351def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600352 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600353
354 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600355
356 Raises:
357 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600358 """
359 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
360 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
361
David Burger92485342019-09-10 17:52:45 -0600362 with open(path, 'r') as f:
363 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600364
Chris McDonald38409112020-09-24 11:24:51 -0600365 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600366 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600367 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
368 'sys-kernel', version)
369 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
370 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600371 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
372 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600373 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600374 patch_ebuild_vars(ebuild_path,
375 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600376
377 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600378 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400379 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600380 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600381 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600382 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600383 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600384
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600385 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600386
Yaakov Shaul730814a2019-09-10 13:58:25 -0600387 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
388
389 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600390
391
Trent Begineb624182020-07-14 10:09:45 -0600392@uprevs_versioned_package('chromeos-base/termina-dlc')
393def uprev_termina_dlc(_build_targets, _refs, chroot):
394 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600395
396 See: uprev_versioned_package.
397 """
Trent Begineb624182020-07-14 10:09:45 -0600398 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600399 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
400 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000401
402 version_pin_src_path = _get_version_pin_src_path(package_path)
403 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
404
Chris McDonald38409112020-09-24 11:24:51 -0600405 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000406
407
408@uprevs_versioned_package('app-emulation/parallels-desktop')
409def uprev_parallels_desktop(_build_targets, _refs, chroot):
410 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
411
412 See: uprev_versioned_package
413
414 Returns:
415 UprevVersionedPackageResult: The result.
416 """
417 package = 'parallels-desktop'
418 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
419 'app-emulation', package)
420 version_pin_src_path = _get_version_pin_src_path(package_path)
421
422 # Expect a JSON blob like the following:
423 # {
424 # "version": "1.2.3",
425 # "test_image": { "url": "...", "size": 12345678,
426 # "sha256sum": "<32 bytes of hexadecimal>" }
427 # }
428 with open(version_pin_src_path, 'r') as f:
429 pinned = json.load(f)
430
431 if 'version' not in pinned or 'test_image' not in pinned:
432 raise UprevError('VERSION-PIN for %s missing version and/or '
433 'test_image field' % package)
434
435 version = pinned['version']
436 if not isinstance(version, str):
437 raise UprevError('version in VERSION-PIN for %s not a string' % package)
438
439 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600440 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000441
442 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100443 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
444 'local/bundles/crosint/pita/data/'
445 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000446 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
447 with open(test_image_src_path, 'w') as f:
448 json.dump(pinned['test_image'], f, indent=2)
449 result.add_result(version, [test_image_src_path])
450
451 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600452
453
Trent Begin315d9d92019-12-03 21:55:53 -0700454@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600455def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700456 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
457
458 See: uprev_versioned_package.
459 """
460 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700461 package_path = os.path.join('src', 'private-overlays',
462 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000463 version_pin_src_path = _get_version_pin_src_path(package_path)
464 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700465
Chris McDonald38409112020-09-24 11:24:51 -0600466 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700467
468
Patrick Meiring5897add2020-09-16 16:30:17 +1000469def _get_version_pin_src_path(package_path):
470 """Returns the path to the VERSION-PIN file for the given package."""
471 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
472
473
Alex Klein87531182019-08-12 15:23:37 -0600474@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700475def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600476 """Uprev chrome and its related packages.
477
478 See: uprev_versioned_package.
479 """
480 # Determine the version from the refs (tags), i.e. the chrome versions are the
481 # tag names.
482 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600483 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600484
485 uprev_manager = uprev_lib.UprevChromeManager(
486 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600487 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600488 # Start with chrome itself, as we can't do anything else unless chrome
489 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600490 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
491 # attempt. The expected behavior is documented in the following table:
492 #
493 # Outcome of Chrome uprev attempt:
494 # NEWER_VERSION_EXISTS:
495 # Do nothing.
496 # SAME_VERSION_EXISTS or REVISION_BUMP:
497 # Uprev followers
498 # Assert not VERSION_BUMP (any other outcome is fine)
499 # VERSION_BUMP or NEW_EBUILD_CREATED:
500 # Uprev followers
501 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600502 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600503 return result
Alex Klein87531182019-08-12 15:23:37 -0600504
505 # With a successful chrome rev, also uprev related packages.
506 for package in constants.OTHER_CHROME_PACKAGES:
507 uprev_manager.uprev(package)
508
David Burger37f48672019-09-18 17:07:56 -0600509 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600510
511
Ben Reiche779cf42020-12-15 03:21:31 +0000512def get_latest_drivefs_version_from_refs(refs: List[uprev_lib.GitRef]) -> str:
513 """Get the latest DriveFS version from refs
514
515 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
516 Versions are compared using |distutils.version.LooseVersion| and
517 the latest version is returned.
518
519 Args:
520 refs: The tags to parse for the latest DriveFS version.
521
522 Returns:
523 The latest DriveFS version to use.
524 """
525 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
526
527 valid_refs = []
528 for gitiles in refs:
529 if gitiles.ref.startswith(DRIVEFS_REFS_PREFIX):
530 valid_refs.append(gitiles.ref)
531
532 if not valid_refs:
533 return None
534
535 # Sort by version and take the latest version.
536 target_version_ref = sorted(valid_refs,
537 key=LooseVersion,
538 reverse=True)[0]
539 return target_version_ref.replace(DRIVEFS_REFS_PREFIX, '')
540
541
Andrew Lamb9563a152019-12-04 11:42:18 -0700542def _generate_platform_c_files(replication_config, chroot):
543 """Generates platform C files from a platform JSON payload.
544
545 Args:
546 replication_config (replication_config_pb2.ReplicationConfig): A
547 ReplicationConfig that has already been run. If it produced a
548 build_config.json file, that file will be used to generate platform C
549 files. Otherwise, nothing will be generated.
550 chroot (chroot_lib.Chroot): The chroot to use to generate.
551
552 Returns:
553 A list of generated files.
554 """
555 # Generate the platform C files from the build config. Note that it would be
556 # more intuitive to generate the platform C files from the platform config;
557 # however, cros_config_schema does not allow this, because the platform config
558 # payload is not always valid input. For example, if a property is both
559 # 'required' and 'build-only', it will fail schema validation. Thus, use the
560 # build config, and use '-f' to filter.
561 build_config_path = [
562 rule.destination_path
563 for rule in replication_config.file_replication_rules
564 if rule.destination_path.endswith('build_config.json')
565 ]
566
567 if not build_config_path:
568 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700569 'No build_config.json found, will not generate platform C files. '
570 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700571 return []
572
573 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700574 raise ValueError('Expected at most one build_config.json destination path. '
575 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700576
577 build_config_path = build_config_path[0]
578
579 # Paths to the build_config.json and dir to output C files to, in the
580 # chroot.
581 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
582 build_config_path)
583 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
584 os.path.dirname(build_config_path))
585
586 command = [
587 'cros_config_schema', '-m', build_config_chroot_path, '-g',
588 generated_output_chroot_dir, '-f', '"TRUE"'
589 ]
590
591 cros_build_lib.run(
592 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
593
594 # A relative (to the source root) path to the generated C files.
595 generated_output_dir = os.path.dirname(build_config_path)
596 generated_files = []
597 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
598 for f in expected_c_files:
599 if os.path.exists(
600 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
601 generated_files.append(os.path.join(generated_output_dir, f))
602
603 if len(expected_c_files) != len(generated_files):
604 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
605
606 return generated_files
607
608
Andrew Lambe836f222019-12-09 12:27:38 -0700609def _get_private_overlay_package_root(ref, package):
610 """Returns the absolute path to the root of a given private overlay.
611
612 Args:
613 ref (uprev_lib.GitRef): GitRef for the private overlay.
614 package (str): Path to the package in the overlay.
615 """
616 # There might be a cleaner way to map from package -> path within the source
617 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700618 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700619 match = re.match(private_overlay_ref_pattern, ref.path)
620 if not match:
621 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
622 (private_overlay_ref_pattern, ref))
623
624 overlay = match.group(1)
625
626 return os.path.join(constants.SOURCE_ROOT,
627 'src/private-overlays/overlay-%s-private' % overlay,
628 package)
629
630
Andrew Lambea9a8a22019-12-12 14:03:43 -0700631@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
632def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700633 """Replicate a private cros_config change to the corresponding public config.
634
Alex Kleinad6b48a2020-01-08 16:57:41 -0700635 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700636 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700637 package = 'chromeos-base/chromeos-config-bsp'
638
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700639 if len(refs) != 1:
640 raise ValueError('Expected exactly one ref, actual %s' % refs)
641
642 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700643 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700644 replication_config_path = os.path.join(package_root,
645 'replication_config.jsonpb')
646
647 try:
648 replication_config = json_format.Parse(
649 osutils.ReadFile(replication_config_path),
650 replication_config_pb2.ReplicationConfig())
651 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700652 raise ValueError(
653 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700654
655 replication_lib.Replicate(replication_config)
656
657 modified_files = [
658 rule.destination_path
659 for rule in replication_config.file_replication_rules
660 ]
661
Andrew Lamb9563a152019-12-04 11:42:18 -0700662 # The generated platform C files are not easily filtered by replication rules,
663 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
664 # files cannot. Therefore, replicate and filter the JSON payloads, and then
665 # generate filtered C files from the JSON payload.
666 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700667
668 # Use the private repo's commit hash as the new version.
669 new_private_version = refs[0].revision
670
Andrew Lamb988f4da2019-12-10 10:16:43 -0700671 # modified_files should contain only relative paths at this point, but the
672 # returned UprevVersionedPackageResult must contain only absolute paths.
673 for i, modified_file in enumerate(modified_files):
674 assert not os.path.isabs(modified_file)
675 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
676
Chris McDonald38409112020-09-24 11:24:51 -0600677 return uprev_lib.UprevVersionedPackageResult().add_result(
678 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700679
680
Alex Kleinbbef2b32019-08-27 10:38:50 -0600681def get_best_visible(atom, build_target=None):
682 """Returns the best visible CPV for the given atom.
683
684 Args:
685 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600686 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600687 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700688
689 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600690 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600691 """
David Burger1e0fe232019-07-01 14:52:07 -0600692 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600693
694 board = build_target.name if build_target else None
695 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600696
697
Alex Klein149fd3b2019-12-16 16:01:05 -0700698def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600699 """Check if a prebuilt exists.
700
701 Args:
702 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600703 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600704 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700705 useflags: Any additional USE flags that should be set. May be a string
706 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700707
708 Returns:
709 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600710 """
711 assert atom
712
713 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700714 extra_env = None
715 if useflags:
716 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500717 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700718 new_flags = ' '.join(useflags)
719
720 existing = os.environ.get('USE', '')
721 final_flags = '%s %s' % (existing, new_flags)
722 extra_env = {'USE': final_flags.strip()}
723 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600724
725
David Burger0f9dd4e2019-10-08 12:33:42 -0600726def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600727 """Check if |build_target| builds |atom| (has it in its depgraph)."""
728 cros_build_lib.AssertInsideChroot()
729
Alex Kleind8cd4c62020-09-14 13:37:47 -0600730 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600731 # TODO(crbug/1081828): Receive and use sysroot.
732 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600733 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600734 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600735
736
Alex Klein6becabc2020-09-11 14:03:05 -0600737def needs_chrome_source(
738 build_target: 'build_target_lib.BuildTarget',
739 compile_source=False,
740 packages: Optional[List[package_info.PackageInfo]] = None,
741 useflags=None):
742 """Check if the chrome source is needed.
743
744 The chrome source is needed if the build target builds chrome or any of its
745 follower packages, and can't use a prebuilt for them either because it's not
746 available, or because we can't use prebuilts because it must build from
747 source.
748 """
749 cros_build_lib.AssertInsideChroot()
750
751 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700752 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600753 builds_chrome = constants.CHROME_CP in graph
754 builds_follower = {
755 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
756 }
757
758 # When we are compiling source set False since we do not use prebuilts.
759 # When not compiling from source, start with True, i.e. we have every prebuilt
760 # we've checked for up to this point.
761 has_chrome_prebuilt = not compile_source
762 has_follower_prebuilts = not compile_source
763 # Save packages that need prebuilts for reporting.
764 pkgs_needing_prebuilts = []
765 if compile_source:
766 # Need everything.
767 pkgs_needing_prebuilts.append(constants.CHROME_CP)
768 pkgs_needing_prebuilts.extend(
769 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
770 else:
771 # Check chrome itself.
772 if builds_chrome:
773 has_chrome_prebuilt = has_prebuilt(
774 constants.CHROME_CP, build_target=build_target, useflags=useflags)
775 if not has_chrome_prebuilt:
776 pkgs_needing_prebuilts.append(constants.CHROME_CP)
777 # Check follower packages.
778 for pkg, builds_pkg in builds_follower.items():
779 if not builds_pkg:
780 continue
781 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
782 has_follower_prebuilts &= prebuilt
783 if not prebuilt:
784 pkgs_needing_prebuilts.append(pkg)
785 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
786 # reflect whether we actually have the corresponding prebuilts for the build.
787
788 needs_chrome = builds_chrome and not has_chrome_prebuilt
789 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
790
791 return NeedsChromeSourceResult(
792 needs_chrome_source=needs_chrome or needs_follower,
793 builds_chrome=builds_chrome,
794 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
795 missing_chrome_prebuilt=not has_chrome_prebuilt,
796 missing_follower_prebuilt=not has_follower_prebuilts)
797
798
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600799def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600800 """Returns the current Chrome version for the board (or in buildroot).
801
802 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600803 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700804
805 Returns:
806 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600807 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600808 # TODO(crbug/1019770): Long term we should not need the try/catch here once
809 # the builds function above only returns True for chrome when
810 # determine_chrome_version will succeed.
811 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700812 cpv = portage_util.PortageqBestVisible(
813 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600814 except cros_build_lib.RunCommandError as e:
815 # Return None because portage failed when trying to determine the chrome
816 # version.
817 logging.warning('Caught exception in determine_chrome_package: %s', e)
818 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600819 # Something like 78.0.3877.4_rc -> 78.0.3877.4
820 return cpv.version_no_rev.partition('_')[0]
821
822
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600823def determine_android_package(board):
824 """Returns the active Android container package in use by the board.
825
826 Args:
827 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700828
829 Returns:
830 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600831 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600832 try:
833 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600834 except cros_build_lib.RunCommandError as e:
835 # Return None because a command (likely portage) failed when trying to
836 # determine the package.
837 logging.warning('Caught exception in determine_android_package: %s', e)
838 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600839
Alex Kleinad6b48a2020-01-08 16:57:41 -0700840 # We assume there is only one Android package in the depgraph.
841 for package in packages:
842 if package.startswith('chromeos-base/android-container-') or \
843 package.startswith('chromeos-base/android-vm-'):
844 return package
845 return None
846
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600847
848def determine_android_version(boards=None):
849 """Determine the current Android version in buildroot now and return it.
850
851 This uses the typical portage logic to determine which version of Android
852 is active right now in the buildroot.
853
854 Args:
855 boards: List of boards to check version of.
856
857 Returns:
858 The Android build ID of the container for the boards.
859
860 Raises:
861 NoAndroidVersionError: if no unique Android version can be determined.
862 """
863 if not boards:
864 return None
865 # Verify that all boards have the same version.
866 version = None
867 for board in boards:
868 package = determine_android_package(board)
869 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600870 return None
Alex Klein18a60af2020-06-11 12:08:47 -0600871 cpv = package_info.SplitCPV(package)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600872 if not cpv:
873 raise NoAndroidVersionError(
874 'Android version could not be determined for %s' % board)
875 if not version:
876 version = cpv.version_no_rev
877 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700878 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
879 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600880 return version
881
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700882
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600883def determine_android_branch(board):
884 """Returns the Android branch in use by the active container ebuild."""
885 try:
886 android_package = determine_android_package(board)
887 except cros_build_lib.RunCommandError:
888 raise NoAndroidBranchError(
889 'Android branch could not be determined for %s' % board)
890 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600891 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600892 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
893 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900894 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900895 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600896 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
897 for target in targets:
898 if target in ebuild_content:
899 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
900 if branch is not None:
901 return branch.group(1)
902 raise NoAndroidBranchError(
903 'Android branch could not be determined for %s (ebuild empty?)' % board)
904
905
906def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600907 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600908 try:
909 android_package = determine_android_package(board)
910 except cros_build_lib.RunCommandError:
911 raise NoAndroidTargetError(
912 'Android Target could not be determined for %s' % board)
913 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600914 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600915 if android_package.startswith('chromeos-base/android-vm-'):
916 return 'bertha'
917 elif android_package.startswith('chromeos-base/android-container-'):
918 return 'cheets'
919
920 raise NoAndroidTargetError(
921 'Android Target cannot be determined for the package: %s' %
922 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600923
924
925def determine_platform_version():
926 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600927 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600928 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
929 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600930
931
932def determine_milestone_version():
933 """Returns the platform version from the source root."""
934 # Milestone version is something like '79'.
935 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
936 return version.chrome_branch
937
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700938
Michael Mortensen009cb662019-10-21 11:38:43 -0600939def determine_full_version():
940 """Returns the full version from the source root."""
941 # Full version is something like 'R79-12575.0.0'.
942 milestone_version = determine_milestone_version()
943 platform_version = determine_platform_version()
944 full_version = ('R%s-%s' % (milestone_version, platform_version))
945 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600946
947
Michael Mortensende716a12020-05-15 11:27:00 -0600948def find_fingerprints(build_target):
949 """Returns a list of fingerprints for this build.
950
951 Args:
952 build_target (build_target_lib.BuildTarget): The build target.
953
954 Returns:
955 list[str] - List of fingerprint strings.
956 """
957 cros_build_lib.AssertInsideChroot()
958 fp_file = 'cheets-fingerprint.txt'
959 fp_path = os.path.join(
960 image_lib.GetLatestImageLink(build_target.name),
961 fp_file)
962 if not os.path.isfile(fp_path):
963 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600964 return []
Michael Mortensende716a12020-05-15 11:27:00 -0600965 logging.info('Reading fingerprint file: %s', fp_path)
966 fingerprints = osutils.ReadFile(fp_path).splitlines()
967 return fingerprints
968
969
Michael Mortensen59e30872020-05-18 14:12:49 -0600970def get_all_firmware_versions(build_target):
971 """Extract firmware version for all models present.
972
973 Args:
974 build_target (build_target_lib.BuildTarget): The build target.
975
976 Returns:
977 A dict of FirmwareVersions namedtuple instances by model.
978 Each element will be populated based on whether it was present in the
979 command output.
980 """
981 cros_build_lib.AssertInsideChroot()
982 result = {}
983 # Note that example output for _get_firmware_version_cmd_result is available
984 # in the packages_unittest.py for testing get_all_firmware_versions.
985 cmd_result = _get_firmware_version_cmd_result(build_target)
986
987 # There is a blank line between the version info for each model.
988 firmware_version_payloads = cmd_result.split('\n\n')
989 for firmware_version_payload in firmware_version_payloads:
990 if 'BIOS' in firmware_version_payload:
991 firmware_version = _find_firmware_versions(firmware_version_payload)
992 result[firmware_version.model] = firmware_version
993 return result
994
995
Michael Mortensen71ef5682020-05-07 14:29:24 -0600996FirmwareVersions = collections.namedtuple(
997 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
998
999
1000def get_firmware_versions(build_target):
1001 """Extract version information from the firmware updater, if one exists.
1002
1003 Args:
1004 build_target (build_target_lib.BuildTarget): The build target.
1005
1006 Returns:
1007 A FirmwareVersions namedtuple instance.
1008 Each element will either be set to the string output by the firmware
1009 updater shellball, or None if there is no firmware updater.
1010 """
1011 cros_build_lib.AssertInsideChroot()
1012 cmd_result = _get_firmware_version_cmd_result(build_target)
1013 if cmd_result:
1014 return _find_firmware_versions(cmd_result)
1015 else:
1016 return FirmwareVersions(None, None, None, None, None)
1017
1018
1019def _get_firmware_version_cmd_result(build_target):
1020 """Gets the raw result output of the firmware updater version command.
1021
1022 Args:
1023 build_target (build_target_lib.BuildTarget): The build target.
1024
1025 Returns:
1026 Command execution result.
1027 """
1028 updater = os.path.join(build_target.root,
1029 'usr/sbin/chromeos-firmwareupdate')
1030 logging.info('Calling updater %s', updater)
1031 # Call the updater using the chroot-based path.
1032 return cros_build_lib.run([updater, '-V'],
1033 capture_output=True, log_output=True,
1034 encoding='utf-8').stdout
1035
1036
1037def _find_firmware_versions(cmd_output):
1038 """Finds firmware version output via regex matches against the cmd_output.
1039
1040 Args:
1041 cmd_output: The raw output to search against.
1042
1043 Returns:
1044 FirmwareVersions namedtuple with results.
1045 Each element will either be set to the string output by the firmware
1046 updater shellball, or None if there is no match.
1047 """
1048
1049 # Sometimes a firmware bundle includes a special combination of RO+RW
1050 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1051 # version" field. In other cases, the "(RW) version" field is not present.
1052 # Therefore, search for the "(RW)" fields first and if they aren't present,
1053 # fallback to the other format. e.g. just "BIOS version:".
1054 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1055 main = None
1056 main_rw = None
1057 ec = None
1058 ec_rw = None
1059 model = None
1060
1061 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1062 if match:
1063 main = match.group('version')
1064
1065 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1066 if match:
1067 main_rw = match.group('version')
1068
1069 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1070 if match:
1071 ec = match.group('version')
1072
1073 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1074 if match:
1075 ec_rw = match.group('version')
1076
1077 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1078 if match:
1079 model = match.group('model')
1080
1081 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001082
1083
1084MainEcFirmwareVersions = collections.namedtuple(
1085 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1086
1087def determine_firmware_versions(build_target):
1088 """Returns a namedtuple with main and ec firmware versions.
1089
1090 Args:
1091 build_target (build_target_lib.BuildTarget): The build target.
1092
1093 Returns:
1094 MainEcFirmwareVersions namedtuple with results.
1095 """
1096 fw_versions = get_firmware_versions(build_target)
1097 main_fw_version = fw_versions.main_rw or fw_versions.main
1098 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1099
1100 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001101
1102def determine_kernel_version(build_target):
1103 """Returns a string containing the kernel version for this build target.
1104
1105 Args:
1106 build_target (build_target_lib.BuildTarget): The build target.
1107
1108 Returns:
1109 (str) The kernel versions, or None.
1110 """
1111 try:
1112 packages = portage_util.GetPackageDependencies(build_target.name,
1113 'virtual/linux-sources')
1114 except cros_build_lib.RunCommandError as e:
1115 logging.warning('Unable to get package list for metadata: %s', e)
1116 return None
1117 for package in packages:
1118 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001119 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001120 logging.info('Found active kernel version: %s', kernel_version)
1121 return kernel_version
1122 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001123
1124
1125def get_models(build_target, log_output=True):
1126 """Obtain a list of models supported by a unified board.
1127
1128 This ignored whitelabel models since GoldenEye has no specific support for
1129 these at present.
1130
1131 Args:
1132 build_target (build_target_lib.BuildTarget): The build target.
1133 log_output: Whether to log the output of the cros_config_host invocation.
1134
1135 Returns:
1136 A list of models supported by this board, if it is a unified build; None,
1137 if it is not a unified build.
1138 """
1139 return _run_cros_config_host(build_target, ['list-models'],
1140 log_output=log_output)
1141
1142
Michael Mortensen359c1f32020-05-28 19:35:42 -06001143def get_key_id(build_target, model):
1144 """Obtain the key_id for a model within the build_target.
1145
1146 Args:
1147 build_target (build_target_lib.BuildTarget): The build target.
1148 model (str): The model name
1149
1150 Returns:
1151 A key_id (str) or None.
1152 """
1153 model_arg = '--model=' + model
1154 key_id_list = _run_cros_config_host(
1155 build_target,
1156 [model_arg, 'get', '/firmware-signing', 'key-id'])
1157 key_id = None
1158 if len(key_id_list) == 1:
1159 key_id = key_id_list[0]
1160 return key_id
1161
1162
Michael Mortensen125bb012020-05-21 14:02:10 -06001163def _run_cros_config_host(build_target, args, log_output=True):
1164 """Run the cros_config_host tool.
1165
1166 Args:
1167 build_target (build_target_lib.BuildTarget): The build target.
1168 args: List of arguments to pass.
1169 log_output: Whether to log the output of the cros_config_host.
1170
1171 Returns:
1172 Output of the tool
1173 """
1174 cros_build_lib.AssertInsideChroot()
1175 tool = '/usr/bin/cros_config_host'
1176 if not os.path.isfile(tool):
1177 return None
1178
1179 config_fname = build_target.full_path(
1180 'usr/share/chromeos-config/yaml/config.yaml')
1181
1182 result = cros_build_lib.run(
1183 [tool, '-c', config_fname] + args,
1184 capture_output=True,
1185 encoding='utf-8',
1186 log_output=log_output,
1187 check=False)
1188 if result.returncode:
1189 # Show the output for debugging purposes.
1190 if 'No such file or directory' not in result.error:
1191 logging.error('cros_config_host failed: %s\n', result.error)
1192 return None
1193 return result.output.strip().splitlines()