blob: 95f68fe397ce99cda5eea049d19485878eb42104 [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
Ben Reiche779cf42020-12-15 03:21:31 +000018from typing import List
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():
36 from chromite.service import dependency
37
Mike Frysingerbafb3182020-02-21 03:15:43 -050038
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
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060093def patch_ebuild_vars(ebuild_path, variables):
94 """Updates variables in ebuild.
95
96 Use this function rather than portage_util.EBuild.UpdateEBuild when you
97 want to preserve the variable position and quotes within the ebuild.
98
99 Args:
100 ebuild_path: The path of the ebuild.
101 variables: Dictionary of variables to update in ebuild.
102 """
103 try:
104 for line in fileinput.input(ebuild_path, inplace=1):
105 varname, eq, _ = line.partition('=')
106 if eq == '=' and varname.strip() in variables:
107 value = variables[varname]
108 sys.stdout.write('%s="%s"\n' % (varname, value))
109 else:
110 sys.stdout.write(line)
111 finally:
112 fileinput.close()
113
114
Alex Klein87531182019-08-12 15:23:37 -0600115def uprevs_versioned_package(package):
116 """Decorator to register package uprev handlers."""
117 assert package
118
119 def register(func):
120 """Registers |func| as a handler for |package|."""
121 _UPREV_FUNCS[package] = func
122
123 @functools.wraps(func)
124 def pass_through(*args, **kwargs):
125 return func(*args, **kwargs)
126
127 return pass_through
128
129 return register
130
131
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700132def uprev_android(tracking_branch,
133 android_package,
134 android_build_branch,
135 chroot,
136 build_targets=None,
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +0900137 android_version=None):
Alex Klein4de25e82019-08-05 15:58:39 -0600138 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700139 command = [
140 'cros_mark_android_as_stable',
141 '--tracking_branch=%s' % tracking_branch,
142 '--android_package=%s' % android_package,
143 '--android_build_branch=%s' % android_build_branch,
144 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600145 if build_targets:
146 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
147 if android_version:
148 command.append('--force_version=%s' % android_version)
Alex Klein4de25e82019-08-05 15:58:39 -0600149
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700150 result = cros_build_lib.run(
151 command,
152 stdout=True,
153 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500154 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700155 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600156
Mike Frysinger88d96362020-02-14 19:05:45 -0500157 portage_atom_string = result.stdout.strip()
158 android_atom = None
159 if portage_atom_string:
160 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600161 if not android_atom:
162 logging.info('Found nothing to rev.')
163 return None
164
165 for target in build_targets or []:
166 # Sanity check: We should always be able to merge the version of
167 # Android we just unmasked.
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700168 command = ['emerge-%s' % target.name, '-p', '--quiet', '=%s' % android_atom]
Alex Klein4de25e82019-08-05 15:58:39 -0600169 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700170 cros_build_lib.run(
171 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600172 except cros_build_lib.RunCommandError:
173 logging.error(
174 'Cannot emerge-%s =%s\nIs Android pinned to an older '
175 'version?', target, android_atom)
176 raise AndroidIsPinnedUprevError(android_atom)
177
178 return android_atom
179
180
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700181def uprev_build_targets(build_targets,
182 overlay_type,
183 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600184 output_dir=None):
185 """Uprev the set provided build targets, or all if not specified.
186
187 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600188 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600189 whose overlays should be uprevved, empty or None for all.
190 overlay_type (str): One of the valid overlay types except None (see
191 constants.VALID_OVERLAYS).
192 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
193 output_dir (str|None): The path to optionally dump result files.
194 """
195 # Need a valid overlay, but exclude None.
196 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
197
198 if build_targets:
199 overlays = portage_util.FindOverlaysForBoards(
200 overlay_type, boards=[t.name for t in build_targets])
201 else:
202 overlays = portage_util.FindOverlays(overlay_type)
203
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700204 return uprev_overlays(
205 overlays,
206 build_targets=build_targets,
207 chroot=chroot,
208 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600209
210
211def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
212 """Uprev the given overlays.
213
214 Args:
215 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600216 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600217 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
218 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
219 output_dir (str|None): The path to optionally dump result files.
220
221 Returns:
222 list[str] - The paths to all of the modified ebuild files. This includes the
223 new files that were added (i.e. the new versions) and all of the removed
224 files (i.e. the old versions).
225 """
226 assert overlays
227
228 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
229
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700230 uprev_manager = uprev_lib.UprevOverlayManager(
231 overlays,
232 manifest,
233 build_targets=build_targets,
234 chroot=chroot,
235 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600236 uprev_manager.uprev()
237
238 return uprev_manager.modified_ebuilds
239
240
Alex Klein87531182019-08-12 15:23:37 -0600241def uprev_versioned_package(package, build_targets, refs, chroot):
242 """Call registered uprev handler function for the package.
243
244 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600245 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600246 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600247 clean on a successful uprev.
248 refs (list[uprev_lib.GitRef]):
249 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
250
251 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600252 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600253 """
254 assert package
255
256 if package.cp not in _UPREV_FUNCS:
257 raise UnknownPackageError(
258 'Package "%s" does not have a registered handler.' % package.cp)
259
Andrew Lambea9a8a22019-12-12 14:03:43 -0700260 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600261
262
Navil Perezf57ba872020-06-04 22:38:37 +0000263@uprevs_versioned_package('media-libs/virglrenderer')
264def uprev_virglrenderer(_build_targets, refs, _chroot):
265 """Updates virglrenderer ebuilds.
266
267 See: uprev_versioned_package.
268
269 Returns:
270 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
271 """
Navil Perezf57ba872020-06-04 22:38:37 +0000272 overlay = os.path.join(constants.SOURCE_ROOT,
273 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600274 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
275 'virglrenderer')
276 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000277
278 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
279 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000280 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
281 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000282 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
283
George Engelbrechte73f2782020-06-10 14:10:46 -0600284 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600285 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000286 result.add_result(refs[0].revision, updated_files)
287 return result
288
Jose Magana03b5a842020-08-19 12:52:59 +1000289@uprevs_versioned_package('chromeos-base/drivefs')
290def uprev_drivefs(_build_targets, refs, chroot):
291 """Updates drivefs ebuilds.
292
293 See: uprev_versioned_package.
294
295 Returns:
296 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
297 """
298
Ben Reiche779cf42020-12-15 03:21:31 +0000299 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000300 result = uprev_lib.UprevVersionedPackageResult()
301 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000302
Ben Reiche779cf42020-12-15 03:21:31 +0000303 drivefs_version = get_latest_drivefs_version_from_refs(refs)
304 if not drivefs_version:
305 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000306 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000307
Ben Reiche779cf42020-12-15 03:21:31 +0000308 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000309
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000310 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000311 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000312 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000313 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000314 chroot)
Jose Magana03b5a842020-08-19 12:52:59 +1000315
316 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000317 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000318 all_changed_files.extend(uprev_result.changed_files)
319
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000320 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000321 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000322 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000323 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000324 chroot)
325
326 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000327 logging.warning(
328 'drivefs package has changed files %s but drivefs-ipc does not',
329 all_changed_files)
330 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000331
332 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000333 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000334
335 return result
336
Navil Perezf57ba872020-06-04 22:38:37 +0000337
Yaakov Shaul395ae832019-09-09 14:45:32 -0600338@uprevs_versioned_package('afdo/kernel-profiles')
339def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600340 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600341
342 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600343
344 Raises:
345 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600346 """
347 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
348 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
349
David Burger92485342019-09-10 17:52:45 -0600350 with open(path, 'r') as f:
351 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600352
Chris McDonald38409112020-09-24 11:24:51 -0600353 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600354 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600355 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
356 'sys-kernel', version)
357 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
358 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600359 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
360 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600361 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600362 patch_ebuild_vars(ebuild_path,
363 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600364
365 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600366 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400367 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600368 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600369 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600370 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600371 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600372
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600373 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600374
Yaakov Shaul730814a2019-09-10 13:58:25 -0600375 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
376
377 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600378
379
Trent Begineb624182020-07-14 10:09:45 -0600380@uprevs_versioned_package('chromeos-base/termina-dlc')
381def uprev_termina_dlc(_build_targets, _refs, chroot):
382 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600383
384 See: uprev_versioned_package.
385 """
Trent Begineb624182020-07-14 10:09:45 -0600386 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600387 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
388 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000389
390 version_pin_src_path = _get_version_pin_src_path(package_path)
391 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
392
Chris McDonald38409112020-09-24 11:24:51 -0600393 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000394
395
396@uprevs_versioned_package('app-emulation/parallels-desktop')
397def uprev_parallels_desktop(_build_targets, _refs, chroot):
398 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
399
400 See: uprev_versioned_package
401
402 Returns:
403 UprevVersionedPackageResult: The result.
404 """
405 package = 'parallels-desktop'
406 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
407 'app-emulation', package)
408 version_pin_src_path = _get_version_pin_src_path(package_path)
409
410 # Expect a JSON blob like the following:
411 # {
412 # "version": "1.2.3",
413 # "test_image": { "url": "...", "size": 12345678,
414 # "sha256sum": "<32 bytes of hexadecimal>" }
415 # }
416 with open(version_pin_src_path, 'r') as f:
417 pinned = json.load(f)
418
419 if 'version' not in pinned or 'test_image' not in pinned:
420 raise UprevError('VERSION-PIN for %s missing version and/or '
421 'test_image field' % package)
422
423 version = pinned['version']
424 if not isinstance(version, str):
425 raise UprevError('version in VERSION-PIN for %s not a string' % package)
426
427 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600428 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000429
430 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100431 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
432 'local/bundles/crosint/pita/data/'
433 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000434 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
435 with open(test_image_src_path, 'w') as f:
436 json.dump(pinned['test_image'], f, indent=2)
437 result.add_result(version, [test_image_src_path])
438
439 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600440
441
Trent Begin315d9d92019-12-03 21:55:53 -0700442@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600443def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700444 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
445
446 See: uprev_versioned_package.
447 """
448 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700449 package_path = os.path.join('src', 'private-overlays',
450 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000451 version_pin_src_path = _get_version_pin_src_path(package_path)
452 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700453
Chris McDonald38409112020-09-24 11:24:51 -0600454 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700455
456
Patrick Meiring5897add2020-09-16 16:30:17 +1000457def _get_version_pin_src_path(package_path):
458 """Returns the path to the VERSION-PIN file for the given package."""
459 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
460
461
Alex Klein87531182019-08-12 15:23:37 -0600462@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700463def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600464 """Uprev chrome and its related packages.
465
466 See: uprev_versioned_package.
467 """
468 # Determine the version from the refs (tags), i.e. the chrome versions are the
469 # tag names.
470 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600471 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600472
473 uprev_manager = uprev_lib.UprevChromeManager(
474 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600475 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600476 # Start with chrome itself, as we can't do anything else unless chrome
477 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600478 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
479 # attempt. The expected behavior is documented in the following table:
480 #
481 # Outcome of Chrome uprev attempt:
482 # NEWER_VERSION_EXISTS:
483 # Do nothing.
484 # SAME_VERSION_EXISTS or REVISION_BUMP:
485 # Uprev followers
486 # Assert not VERSION_BUMP (any other outcome is fine)
487 # VERSION_BUMP or NEW_EBUILD_CREATED:
488 # Uprev followers
489 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600490 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600491 return result
Alex Klein87531182019-08-12 15:23:37 -0600492
493 # With a successful chrome rev, also uprev related packages.
494 for package in constants.OTHER_CHROME_PACKAGES:
495 uprev_manager.uprev(package)
496
David Burger37f48672019-09-18 17:07:56 -0600497 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600498
499
Ben Reiche779cf42020-12-15 03:21:31 +0000500def get_latest_drivefs_version_from_refs(refs: List[uprev_lib.GitRef]) -> str:
501 """Get the latest DriveFS version from refs
502
503 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
504 Versions are compared using |distutils.version.LooseVersion| and
505 the latest version is returned.
506
507 Args:
508 refs: The tags to parse for the latest DriveFS version.
509
510 Returns:
511 The latest DriveFS version to use.
512 """
513 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
514
515 valid_refs = []
516 for gitiles in refs:
517 if gitiles.ref.startswith(DRIVEFS_REFS_PREFIX):
518 valid_refs.append(gitiles.ref)
519
520 if not valid_refs:
521 return None
522
523 # Sort by version and take the latest version.
524 target_version_ref = sorted(valid_refs,
525 key=LooseVersion,
526 reverse=True)[0]
527 return target_version_ref.replace(DRIVEFS_REFS_PREFIX, '')
528
529
Andrew Lamb9563a152019-12-04 11:42:18 -0700530def _generate_platform_c_files(replication_config, chroot):
531 """Generates platform C files from a platform JSON payload.
532
533 Args:
534 replication_config (replication_config_pb2.ReplicationConfig): A
535 ReplicationConfig that has already been run. If it produced a
536 build_config.json file, that file will be used to generate platform C
537 files. Otherwise, nothing will be generated.
538 chroot (chroot_lib.Chroot): The chroot to use to generate.
539
540 Returns:
541 A list of generated files.
542 """
543 # Generate the platform C files from the build config. Note that it would be
544 # more intuitive to generate the platform C files from the platform config;
545 # however, cros_config_schema does not allow this, because the platform config
546 # payload is not always valid input. For example, if a property is both
547 # 'required' and 'build-only', it will fail schema validation. Thus, use the
548 # build config, and use '-f' to filter.
549 build_config_path = [
550 rule.destination_path
551 for rule in replication_config.file_replication_rules
552 if rule.destination_path.endswith('build_config.json')
553 ]
554
555 if not build_config_path:
556 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700557 'No build_config.json found, will not generate platform C files. '
558 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700559 return []
560
561 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700562 raise ValueError('Expected at most one build_config.json destination path. '
563 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700564
565 build_config_path = build_config_path[0]
566
567 # Paths to the build_config.json and dir to output C files to, in the
568 # chroot.
569 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
570 build_config_path)
571 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
572 os.path.dirname(build_config_path))
573
574 command = [
575 'cros_config_schema', '-m', build_config_chroot_path, '-g',
576 generated_output_chroot_dir, '-f', '"TRUE"'
577 ]
578
579 cros_build_lib.run(
580 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
581
582 # A relative (to the source root) path to the generated C files.
583 generated_output_dir = os.path.dirname(build_config_path)
584 generated_files = []
585 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
586 for f in expected_c_files:
587 if os.path.exists(
588 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
589 generated_files.append(os.path.join(generated_output_dir, f))
590
591 if len(expected_c_files) != len(generated_files):
592 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
593
594 return generated_files
595
596
Andrew Lambe836f222019-12-09 12:27:38 -0700597def _get_private_overlay_package_root(ref, package):
598 """Returns the absolute path to the root of a given private overlay.
599
600 Args:
601 ref (uprev_lib.GitRef): GitRef for the private overlay.
602 package (str): Path to the package in the overlay.
603 """
604 # There might be a cleaner way to map from package -> path within the source
605 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700606 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700607 match = re.match(private_overlay_ref_pattern, ref.path)
608 if not match:
609 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
610 (private_overlay_ref_pattern, ref))
611
612 overlay = match.group(1)
613
614 return os.path.join(constants.SOURCE_ROOT,
615 'src/private-overlays/overlay-%s-private' % overlay,
616 package)
617
618
Andrew Lambea9a8a22019-12-12 14:03:43 -0700619@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
620def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700621 """Replicate a private cros_config change to the corresponding public config.
622
Alex Kleinad6b48a2020-01-08 16:57:41 -0700623 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700624 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700625 package = 'chromeos-base/chromeos-config-bsp'
626
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700627 if len(refs) != 1:
628 raise ValueError('Expected exactly one ref, actual %s' % refs)
629
630 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700631 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700632 replication_config_path = os.path.join(package_root,
633 'replication_config.jsonpb')
634
635 try:
636 replication_config = json_format.Parse(
637 osutils.ReadFile(replication_config_path),
638 replication_config_pb2.ReplicationConfig())
639 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700640 raise ValueError(
641 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700642
643 replication_lib.Replicate(replication_config)
644
645 modified_files = [
646 rule.destination_path
647 for rule in replication_config.file_replication_rules
648 ]
649
Andrew Lamb9563a152019-12-04 11:42:18 -0700650 # The generated platform C files are not easily filtered by replication rules,
651 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
652 # files cannot. Therefore, replicate and filter the JSON payloads, and then
653 # generate filtered C files from the JSON payload.
654 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700655
656 # Use the private repo's commit hash as the new version.
657 new_private_version = refs[0].revision
658
Andrew Lamb988f4da2019-12-10 10:16:43 -0700659 # modified_files should contain only relative paths at this point, but the
660 # returned UprevVersionedPackageResult must contain only absolute paths.
661 for i, modified_file in enumerate(modified_files):
662 assert not os.path.isabs(modified_file)
663 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
664
Chris McDonald38409112020-09-24 11:24:51 -0600665 return uprev_lib.UprevVersionedPackageResult().add_result(
666 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700667
668
Alex Kleinbbef2b32019-08-27 10:38:50 -0600669def get_best_visible(atom, build_target=None):
670 """Returns the best visible CPV for the given atom.
671
672 Args:
673 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600674 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600675 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700676
677 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600678 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600679 """
David Burger1e0fe232019-07-01 14:52:07 -0600680 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600681
682 board = build_target.name if build_target else None
683 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600684
685
Alex Klein149fd3b2019-12-16 16:01:05 -0700686def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600687 """Check if a prebuilt exists.
688
689 Args:
690 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600691 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600692 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700693 useflags: Any additional USE flags that should be set. May be a string
694 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700695
696 Returns:
697 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600698 """
699 assert atom
700
701 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700702 extra_env = None
703 if useflags:
704 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500705 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700706 new_flags = ' '.join(useflags)
707
708 existing = os.environ.get('USE', '')
709 final_flags = '%s %s' % (existing, new_flags)
710 extra_env = {'USE': final_flags.strip()}
711 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600712
713
David Burger0f9dd4e2019-10-08 12:33:42 -0600714def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600715 """Check if |build_target| builds |atom| (has it in its depgraph)."""
716 cros_build_lib.AssertInsideChroot()
717
Alex Kleind8cd4c62020-09-14 13:37:47 -0600718 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600719 # TODO(crbug/1081828): Receive and use sysroot.
720 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600721 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600722 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600723
724
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600725def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600726 """Returns the current Chrome version for the board (or in buildroot).
727
728 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600729 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700730
731 Returns:
732 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600733 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600734 # TODO(crbug/1019770): Long term we should not need the try/catch here once
735 # the builds function above only returns True for chrome when
736 # determine_chrome_version will succeed.
737 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700738 cpv = portage_util.PortageqBestVisible(
739 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600740 except cros_build_lib.RunCommandError as e:
741 # Return None because portage failed when trying to determine the chrome
742 # version.
743 logging.warning('Caught exception in determine_chrome_package: %s', e)
744 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600745 # Something like 78.0.3877.4_rc -> 78.0.3877.4
746 return cpv.version_no_rev.partition('_')[0]
747
748
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600749def determine_android_package(board):
750 """Returns the active Android container package in use by the board.
751
752 Args:
753 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700754
755 Returns:
756 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600757 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600758 try:
759 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600760 except cros_build_lib.RunCommandError as e:
761 # Return None because a command (likely portage) failed when trying to
762 # determine the package.
763 logging.warning('Caught exception in determine_android_package: %s', e)
764 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600765
Alex Kleinad6b48a2020-01-08 16:57:41 -0700766 # We assume there is only one Android package in the depgraph.
767 for package in packages:
768 if package.startswith('chromeos-base/android-container-') or \
769 package.startswith('chromeos-base/android-vm-'):
770 return package
771 return None
772
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600773
774def determine_android_version(boards=None):
775 """Determine the current Android version in buildroot now and return it.
776
777 This uses the typical portage logic to determine which version of Android
778 is active right now in the buildroot.
779
780 Args:
781 boards: List of boards to check version of.
782
783 Returns:
784 The Android build ID of the container for the boards.
785
786 Raises:
787 NoAndroidVersionError: if no unique Android version can be determined.
788 """
789 if not boards:
790 return None
791 # Verify that all boards have the same version.
792 version = None
793 for board in boards:
794 package = determine_android_package(board)
795 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600796 return None
Alex Klein18a60af2020-06-11 12:08:47 -0600797 cpv = package_info.SplitCPV(package)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600798 if not cpv:
799 raise NoAndroidVersionError(
800 'Android version could not be determined for %s' % board)
801 if not version:
802 version = cpv.version_no_rev
803 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700804 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
805 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600806 return version
807
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700808
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600809def determine_android_branch(board):
810 """Returns the Android branch in use by the active container ebuild."""
811 try:
812 android_package = determine_android_package(board)
813 except cros_build_lib.RunCommandError:
814 raise NoAndroidBranchError(
815 'Android branch could not be determined for %s' % board)
816 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600817 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600818 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
819 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900820 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900821 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600822 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
823 for target in targets:
824 if target in ebuild_content:
825 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
826 if branch is not None:
827 return branch.group(1)
828 raise NoAndroidBranchError(
829 'Android branch could not be determined for %s (ebuild empty?)' % board)
830
831
832def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600833 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600834 try:
835 android_package = determine_android_package(board)
836 except cros_build_lib.RunCommandError:
837 raise NoAndroidTargetError(
838 'Android Target could not be determined for %s' % board)
839 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600840 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600841 if android_package.startswith('chromeos-base/android-vm-'):
842 return 'bertha'
843 elif android_package.startswith('chromeos-base/android-container-'):
844 return 'cheets'
845
846 raise NoAndroidTargetError(
847 'Android Target cannot be determined for the package: %s' %
848 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600849
850
851def determine_platform_version():
852 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600853 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600854 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
855 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600856
857
858def determine_milestone_version():
859 """Returns the platform version from the source root."""
860 # Milestone version is something like '79'.
861 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
862 return version.chrome_branch
863
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700864
Michael Mortensen009cb662019-10-21 11:38:43 -0600865def determine_full_version():
866 """Returns the full version from the source root."""
867 # Full version is something like 'R79-12575.0.0'.
868 milestone_version = determine_milestone_version()
869 platform_version = determine_platform_version()
870 full_version = ('R%s-%s' % (milestone_version, platform_version))
871 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600872
873
Michael Mortensende716a12020-05-15 11:27:00 -0600874def find_fingerprints(build_target):
875 """Returns a list of fingerprints for this build.
876
877 Args:
878 build_target (build_target_lib.BuildTarget): The build target.
879
880 Returns:
881 list[str] - List of fingerprint strings.
882 """
883 cros_build_lib.AssertInsideChroot()
884 fp_file = 'cheets-fingerprint.txt'
885 fp_path = os.path.join(
886 image_lib.GetLatestImageLink(build_target.name),
887 fp_file)
888 if not os.path.isfile(fp_path):
889 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600890 return []
Michael Mortensende716a12020-05-15 11:27:00 -0600891 logging.info('Reading fingerprint file: %s', fp_path)
892 fingerprints = osutils.ReadFile(fp_path).splitlines()
893 return fingerprints
894
895
Michael Mortensen59e30872020-05-18 14:12:49 -0600896def get_all_firmware_versions(build_target):
897 """Extract firmware version for all models present.
898
899 Args:
900 build_target (build_target_lib.BuildTarget): The build target.
901
902 Returns:
903 A dict of FirmwareVersions namedtuple instances by model.
904 Each element will be populated based on whether it was present in the
905 command output.
906 """
907 cros_build_lib.AssertInsideChroot()
908 result = {}
909 # Note that example output for _get_firmware_version_cmd_result is available
910 # in the packages_unittest.py for testing get_all_firmware_versions.
911 cmd_result = _get_firmware_version_cmd_result(build_target)
912
913 # There is a blank line between the version info for each model.
914 firmware_version_payloads = cmd_result.split('\n\n')
915 for firmware_version_payload in firmware_version_payloads:
916 if 'BIOS' in firmware_version_payload:
917 firmware_version = _find_firmware_versions(firmware_version_payload)
918 result[firmware_version.model] = firmware_version
919 return result
920
921
Michael Mortensen71ef5682020-05-07 14:29:24 -0600922FirmwareVersions = collections.namedtuple(
923 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
924
925
926def get_firmware_versions(build_target):
927 """Extract version information from the firmware updater, if one exists.
928
929 Args:
930 build_target (build_target_lib.BuildTarget): The build target.
931
932 Returns:
933 A FirmwareVersions namedtuple instance.
934 Each element will either be set to the string output by the firmware
935 updater shellball, or None if there is no firmware updater.
936 """
937 cros_build_lib.AssertInsideChroot()
938 cmd_result = _get_firmware_version_cmd_result(build_target)
939 if cmd_result:
940 return _find_firmware_versions(cmd_result)
941 else:
942 return FirmwareVersions(None, None, None, None, None)
943
944
945def _get_firmware_version_cmd_result(build_target):
946 """Gets the raw result output of the firmware updater version command.
947
948 Args:
949 build_target (build_target_lib.BuildTarget): The build target.
950
951 Returns:
952 Command execution result.
953 """
954 updater = os.path.join(build_target.root,
955 'usr/sbin/chromeos-firmwareupdate')
956 logging.info('Calling updater %s', updater)
957 # Call the updater using the chroot-based path.
958 return cros_build_lib.run([updater, '-V'],
959 capture_output=True, log_output=True,
960 encoding='utf-8').stdout
961
962
963def _find_firmware_versions(cmd_output):
964 """Finds firmware version output via regex matches against the cmd_output.
965
966 Args:
967 cmd_output: The raw output to search against.
968
969 Returns:
970 FirmwareVersions namedtuple with results.
971 Each element will either be set to the string output by the firmware
972 updater shellball, or None if there is no match.
973 """
974
975 # Sometimes a firmware bundle includes a special combination of RO+RW
976 # firmware. In this case, the RW firmware version is indicated with a "(RW)
977 # version" field. In other cases, the "(RW) version" field is not present.
978 # Therefore, search for the "(RW)" fields first and if they aren't present,
979 # fallback to the other format. e.g. just "BIOS version:".
980 # TODO(mmortensen): Use JSON once the firmware updater supports it.
981 main = None
982 main_rw = None
983 ec = None
984 ec_rw = None
985 model = None
986
987 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
988 if match:
989 main = match.group('version')
990
991 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
992 if match:
993 main_rw = match.group('version')
994
995 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
996 if match:
997 ec = match.group('version')
998
999 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1000 if match:
1001 ec_rw = match.group('version')
1002
1003 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1004 if match:
1005 model = match.group('model')
1006
1007 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001008
1009
1010MainEcFirmwareVersions = collections.namedtuple(
1011 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1012
1013def determine_firmware_versions(build_target):
1014 """Returns a namedtuple with main and ec firmware versions.
1015
1016 Args:
1017 build_target (build_target_lib.BuildTarget): The build target.
1018
1019 Returns:
1020 MainEcFirmwareVersions namedtuple with results.
1021 """
1022 fw_versions = get_firmware_versions(build_target)
1023 main_fw_version = fw_versions.main_rw or fw_versions.main
1024 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1025
1026 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001027
1028def determine_kernel_version(build_target):
1029 """Returns a string containing the kernel version for this build target.
1030
1031 Args:
1032 build_target (build_target_lib.BuildTarget): The build target.
1033
1034 Returns:
1035 (str) The kernel versions, or None.
1036 """
1037 try:
1038 packages = portage_util.GetPackageDependencies(build_target.name,
1039 'virtual/linux-sources')
1040 except cros_build_lib.RunCommandError as e:
1041 logging.warning('Unable to get package list for metadata: %s', e)
1042 return None
1043 for package in packages:
1044 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001045 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001046 logging.info('Found active kernel version: %s', kernel_version)
1047 return kernel_version
1048 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001049
1050
1051def get_models(build_target, log_output=True):
1052 """Obtain a list of models supported by a unified board.
1053
1054 This ignored whitelabel models since GoldenEye has no specific support for
1055 these at present.
1056
1057 Args:
1058 build_target (build_target_lib.BuildTarget): The build target.
1059 log_output: Whether to log the output of the cros_config_host invocation.
1060
1061 Returns:
1062 A list of models supported by this board, if it is a unified build; None,
1063 if it is not a unified build.
1064 """
1065 return _run_cros_config_host(build_target, ['list-models'],
1066 log_output=log_output)
1067
1068
Michael Mortensen359c1f32020-05-28 19:35:42 -06001069def get_key_id(build_target, model):
1070 """Obtain the key_id for a model within the build_target.
1071
1072 Args:
1073 build_target (build_target_lib.BuildTarget): The build target.
1074 model (str): The model name
1075
1076 Returns:
1077 A key_id (str) or None.
1078 """
1079 model_arg = '--model=' + model
1080 key_id_list = _run_cros_config_host(
1081 build_target,
1082 [model_arg, 'get', '/firmware-signing', 'key-id'])
1083 key_id = None
1084 if len(key_id_list) == 1:
1085 key_id = key_id_list[0]
1086 return key_id
1087
1088
Michael Mortensen125bb012020-05-21 14:02:10 -06001089def _run_cros_config_host(build_target, args, log_output=True):
1090 """Run the cros_config_host tool.
1091
1092 Args:
1093 build_target (build_target_lib.BuildTarget): The build target.
1094 args: List of arguments to pass.
1095 log_output: Whether to log the output of the cros_config_host.
1096
1097 Returns:
1098 Output of the tool
1099 """
1100 cros_build_lib.AssertInsideChroot()
1101 tool = '/usr/bin/cros_config_host'
1102 if not os.path.isfile(tool):
1103 return None
1104
1105 config_fname = build_target.full_path(
1106 'usr/share/chromeos-config/yaml/config.yaml')
1107
1108 result = cros_build_lib.run(
1109 [tool, '-c', config_fname] + args,
1110 capture_output=True,
1111 encoding='utf-8',
1112 log_output=log_output,
1113 check=False)
1114 if result.returncode:
1115 # Show the output for debugging purposes.
1116 if 'No such file or directory' not in result.error:
1117 logging.error('cros_config_host failed: %s\n', result.error)
1118 return None
1119 return result.output.strip().splitlines()