blob: 53ed741360d157d8eebf92551076d339df0ac580 [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
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060011import fileinput
Alex Klein87531182019-08-12 15:23:37 -060012import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060013import json
Evan Hernandezb51f1522019-08-15 11:29:40 -060014import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060015import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060016import sys
Alex Klein87531182019-08-12 15:23:37 -060017
Andrew Lamb2bde9e42019-11-04 13:24:09 -070018from google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060019
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060021from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060022from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060023from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060024from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060025from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060026from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060027from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060028from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070029from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060030from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060031from chromite.lib.parser import package_info
Alex Kleineb77ffa2019-05-28 14:47:44 -060032
Alex Klein36b117f2019-09-30 15:13:46 -060033if cros_build_lib.IsInsideChroot():
34 from chromite.service import dependency
35
Mike Frysingerbafb3182020-02-21 03:15:43 -050036
Alex Klein87531182019-08-12 15:23:37 -060037# Registered handlers for uprevving versioned packages.
38_UPREV_FUNCS = {}
39
Alex Kleineb77ffa2019-05-28 14:47:44 -060040
41class Error(Exception):
42 """Module's base error class."""
43
44
Alex Klein4de25e82019-08-05 15:58:39 -060045class UnknownPackageError(Error):
46 """Uprev attempted for a package without a registered handler."""
47
48
Alex Kleineb77ffa2019-05-28 14:47:44 -060049class UprevError(Error):
50 """An error occurred while uprevving packages."""
51
52
Michael Mortensenb70e8a82019-10-10 18:43:41 -060053class NoAndroidVersionError(Error):
54 """An error occurred while trying to determine the android version."""
55
56
57class NoAndroidBranchError(Error):
58 """An error occurred while trying to determine the android branch."""
59
60
61class NoAndroidTargetError(Error):
62 """An error occurred while trying to determine the android target."""
63
64
Alex Klein4de25e82019-08-05 15:58:39 -060065class AndroidIsPinnedUprevError(UprevError):
66 """Raised when we try to uprev while Android is pinned."""
67
68 def __init__(self, new_android_atom):
69 """Initialize a AndroidIsPinnedUprevError.
70
71 Args:
72 new_android_atom: The Android atom that we failed to
73 uprev to, due to Android being pinned.
74 """
75 assert new_android_atom
76 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
77 new_android_atom)
78 super(AndroidIsPinnedUprevError, self).__init__(msg)
79 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060080
81
Andrew Lamb9563a152019-12-04 11:42:18 -070082class GeneratedCrosConfigFilesError(Error):
83 """Error when cros_config_schema does not produce expected files"""
84
85 def __init__(self, expected_files, found_files):
86 msg = ('Expected to find generated C files: %s. Actually found: %s' %
87 (expected_files, found_files))
88 super(GeneratedCrosConfigFilesError, self).__init__(msg)
89
Alex Klein7a3a7dd2020-01-08 16:44:38 -070090
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060091def patch_ebuild_vars(ebuild_path, variables):
92 """Updates variables in ebuild.
93
94 Use this function rather than portage_util.EBuild.UpdateEBuild when you
95 want to preserve the variable position and quotes within the ebuild.
96
97 Args:
98 ebuild_path: The path of the ebuild.
99 variables: Dictionary of variables to update in ebuild.
100 """
101 try:
102 for line in fileinput.input(ebuild_path, inplace=1):
103 varname, eq, _ = line.partition('=')
104 if eq == '=' and varname.strip() in variables:
105 value = variables[varname]
106 sys.stdout.write('%s="%s"\n' % (varname, value))
107 else:
108 sys.stdout.write(line)
109 finally:
110 fileinput.close()
111
112
Alex Klein87531182019-08-12 15:23:37 -0600113def uprevs_versioned_package(package):
114 """Decorator to register package uprev handlers."""
115 assert package
116
117 def register(func):
118 """Registers |func| as a handler for |package|."""
119 _UPREV_FUNCS[package] = func
120
121 @functools.wraps(func)
122 def pass_through(*args, **kwargs):
123 return func(*args, **kwargs)
124
125 return pass_through
126
127 return register
128
129
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700130def uprev_android(tracking_branch,
131 android_package,
132 android_build_branch,
133 chroot,
134 build_targets=None,
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +0900135 android_version=None):
Alex Klein4de25e82019-08-05 15:58:39 -0600136 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700137 command = [
138 'cros_mark_android_as_stable',
139 '--tracking_branch=%s' % tracking_branch,
140 '--android_package=%s' % android_package,
141 '--android_build_branch=%s' % android_build_branch,
142 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600143 if build_targets:
144 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
145 if android_version:
146 command.append('--force_version=%s' % android_version)
Alex Klein4de25e82019-08-05 15:58:39 -0600147
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700148 result = cros_build_lib.run(
149 command,
150 stdout=True,
151 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500152 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700153 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600154
Mike Frysinger88d96362020-02-14 19:05:45 -0500155 portage_atom_string = result.stdout.strip()
156 android_atom = None
157 if portage_atom_string:
158 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600159 if not android_atom:
160 logging.info('Found nothing to rev.')
161 return None
162
163 for target in build_targets or []:
164 # Sanity check: We should always be able to merge the version of
165 # Android we just unmasked.
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700166 command = ['emerge-%s' % target.name, '-p', '--quiet', '=%s' % android_atom]
Alex Klein4de25e82019-08-05 15:58:39 -0600167 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700168 cros_build_lib.run(
169 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600170 except cros_build_lib.RunCommandError:
171 logging.error(
172 'Cannot emerge-%s =%s\nIs Android pinned to an older '
173 'version?', target, android_atom)
174 raise AndroidIsPinnedUprevError(android_atom)
175
176 return android_atom
177
178
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700179def uprev_build_targets(build_targets,
180 overlay_type,
181 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600182 output_dir=None):
183 """Uprev the set provided build targets, or all if not specified.
184
185 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600186 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600187 whose overlays should be uprevved, empty or None for all.
188 overlay_type (str): One of the valid overlay types except None (see
189 constants.VALID_OVERLAYS).
190 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
191 output_dir (str|None): The path to optionally dump result files.
192 """
193 # Need a valid overlay, but exclude None.
194 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
195
196 if build_targets:
197 overlays = portage_util.FindOverlaysForBoards(
198 overlay_type, boards=[t.name for t in build_targets])
199 else:
200 overlays = portage_util.FindOverlays(overlay_type)
201
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700202 return uprev_overlays(
203 overlays,
204 build_targets=build_targets,
205 chroot=chroot,
206 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600207
208
209def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
210 """Uprev the given overlays.
211
212 Args:
213 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600214 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600215 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
216 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
217 output_dir (str|None): The path to optionally dump result files.
218
219 Returns:
220 list[str] - The paths to all of the modified ebuild files. This includes the
221 new files that were added (i.e. the new versions) and all of the removed
222 files (i.e. the old versions).
223 """
224 assert overlays
225
226 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
227
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700228 uprev_manager = uprev_lib.UprevOverlayManager(
229 overlays,
230 manifest,
231 build_targets=build_targets,
232 chroot=chroot,
233 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600234 uprev_manager.uprev()
235
236 return uprev_manager.modified_ebuilds
237
238
Alex Klein87531182019-08-12 15:23:37 -0600239def uprev_versioned_package(package, build_targets, refs, chroot):
240 """Call registered uprev handler function for the package.
241
242 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600243 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600244 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600245 clean on a successful uprev.
246 refs (list[uprev_lib.GitRef]):
247 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
248
249 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600250 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600251 """
252 assert package
253
254 if package.cp not in _UPREV_FUNCS:
255 raise UnknownPackageError(
256 'Package "%s" does not have a registered handler.' % package.cp)
257
Andrew Lambea9a8a22019-12-12 14:03:43 -0700258 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600259
260
Navil Perezf57ba872020-06-04 22:38:37 +0000261@uprevs_versioned_package('media-libs/virglrenderer')
262def uprev_virglrenderer(_build_targets, refs, _chroot):
263 """Updates virglrenderer ebuilds.
264
265 See: uprev_versioned_package.
266
267 Returns:
268 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
269 """
Navil Perezf57ba872020-06-04 22:38:37 +0000270 overlay = os.path.join(constants.SOURCE_ROOT,
271 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600272 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
273 'virglrenderer')
274 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000275
276 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
277 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000278 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
279 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000280 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
281
George Engelbrechte73f2782020-06-10 14:10:46 -0600282 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600283 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000284 result.add_result(refs[0].revision, updated_files)
285 return result
286
Jose Magana03b5a842020-08-19 12:52:59 +1000287@uprevs_versioned_package('chromeos-base/drivefs')
288def uprev_drivefs(_build_targets, refs, chroot):
289 """Updates drivefs ebuilds.
290
291 See: uprev_versioned_package.
292
293 Returns:
294 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
295 """
296
297 DRIVEFS_REFS = 'refs/tags/drivefs_'
298 DRIVEFS_PATH = 'src/private-overlays/chromeos-overlay/chromeos-base'
299
300 # parse like the example PUpr (go/pupr#steps)
301 valid_refs = [ref.ref for ref in refs if ref.ref.startswith(DRIVEFS_REFS)]
302 if not valid_refs:
303 # False alarm, there is no new package release. So do nothing.
304 return None
305
306 # Take the newest release, always.
307 target_version = sorted(valid_refs,
308 reverse=True)[0][len(DRIVEFS_REFS):]
309
310 result = uprev_lib.UprevVersionedPackageResult()
311
Jose Magana8196d0b2020-10-30 10:15:57 +1100312 pkg_path = os.path.join(DRIVEFS_PATH, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000313
314 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
315 target_version,
316 chroot)
317 all_changed_files = []
318
319 if not uprev_result:
320 return None # alternatively raise Exception
321
322 all_changed_files.extend(uprev_result.changed_files)
323
Jose Magana8196d0b2020-10-30 10:15:57 +1100324 pkg_path = os.path.join(DRIVEFS_PATH, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000325
326 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
327 target_version,
328 chroot)
329
330 if not uprev_result:
331 return None # alternatively raise Exception
332
333 all_changed_files.extend(uprev_result.changed_files)
334
335 result.add_result(target_version, all_changed_files)
336
337 return result
338
Navil Perezf57ba872020-06-04 22:38:37 +0000339
Yaakov Shaul395ae832019-09-09 14:45:32 -0600340@uprevs_versioned_package('afdo/kernel-profiles')
341def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600342 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600343
344 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600345
346 Raises:
347 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600348 """
349 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
350 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
351
David Burger92485342019-09-10 17:52:45 -0600352 with open(path, 'r') as f:
353 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600354
Chris McDonald38409112020-09-24 11:24:51 -0600355 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600356 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600357 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
358 'sys-kernel', version)
359 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
360 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600361 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
362 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600363 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600364 patch_ebuild_vars(ebuild_path,
365 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600366
367 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600368 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400369 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600370 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600371 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600372 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600373 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600374
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600375 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600376
Yaakov Shaul730814a2019-09-10 13:58:25 -0600377 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
378
379 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600380
381
Trent Begineb624182020-07-14 10:09:45 -0600382@uprevs_versioned_package('chromeos-base/termina-dlc')
383def uprev_termina_dlc(_build_targets, _refs, chroot):
384 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600385
386 See: uprev_versioned_package.
387 """
Trent Begineb624182020-07-14 10:09:45 -0600388 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600389 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
390 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000391
392 version_pin_src_path = _get_version_pin_src_path(package_path)
393 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
394
Chris McDonald38409112020-09-24 11:24:51 -0600395 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000396
397
398@uprevs_versioned_package('app-emulation/parallels-desktop')
399def uprev_parallels_desktop(_build_targets, _refs, chroot):
400 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
401
402 See: uprev_versioned_package
403
404 Returns:
405 UprevVersionedPackageResult: The result.
406 """
407 package = 'parallels-desktop'
408 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
409 'app-emulation', package)
410 version_pin_src_path = _get_version_pin_src_path(package_path)
411
412 # Expect a JSON blob like the following:
413 # {
414 # "version": "1.2.3",
415 # "test_image": { "url": "...", "size": 12345678,
416 # "sha256sum": "<32 bytes of hexadecimal>" }
417 # }
418 with open(version_pin_src_path, 'r') as f:
419 pinned = json.load(f)
420
421 if 'version' not in pinned or 'test_image' not in pinned:
422 raise UprevError('VERSION-PIN for %s missing version and/or '
423 'test_image field' % package)
424
425 version = pinned['version']
426 if not isinstance(version, str):
427 raise UprevError('version in VERSION-PIN for %s not a string' % package)
428
429 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600430 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000431
432 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100433 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
434 'local/bundles/crosint/pita/data/'
435 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000436 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
437 with open(test_image_src_path, 'w') as f:
438 json.dump(pinned['test_image'], f, indent=2)
439 result.add_result(version, [test_image_src_path])
440
441 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600442
443
Trent Begin315d9d92019-12-03 21:55:53 -0700444@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600445def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700446 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
447
448 See: uprev_versioned_package.
449 """
450 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700451 package_path = os.path.join('src', 'private-overlays',
452 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000453 version_pin_src_path = _get_version_pin_src_path(package_path)
454 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700455
Chris McDonald38409112020-09-24 11:24:51 -0600456 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700457
458
Patrick Meiring5897add2020-09-16 16:30:17 +1000459def _get_version_pin_src_path(package_path):
460 """Returns the path to the VERSION-PIN file for the given package."""
461 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
462
463
Alex Klein87531182019-08-12 15:23:37 -0600464@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700465def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600466 """Uprev chrome and its related packages.
467
468 See: uprev_versioned_package.
469 """
470 # Determine the version from the refs (tags), i.e. the chrome versions are the
471 # tag names.
472 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600473 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600474
475 uprev_manager = uprev_lib.UprevChromeManager(
476 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600477 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600478 # Start with chrome itself, as we can't do anything else unless chrome
479 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600480 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
481 # attempt. The expected behavior is documented in the following table:
482 #
483 # Outcome of Chrome uprev attempt:
484 # NEWER_VERSION_EXISTS:
485 # Do nothing.
486 # SAME_VERSION_EXISTS or REVISION_BUMP:
487 # Uprev followers
488 # Assert not VERSION_BUMP (any other outcome is fine)
489 # VERSION_BUMP or NEW_EBUILD_CREATED:
490 # Uprev followers
491 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600492 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600493 return result
Alex Klein87531182019-08-12 15:23:37 -0600494
495 # With a successful chrome rev, also uprev related packages.
496 for package in constants.OTHER_CHROME_PACKAGES:
497 uprev_manager.uprev(package)
498
David Burger37f48672019-09-18 17:07:56 -0600499 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600500
501
Andrew Lamb9563a152019-12-04 11:42:18 -0700502def _generate_platform_c_files(replication_config, chroot):
503 """Generates platform C files from a platform JSON payload.
504
505 Args:
506 replication_config (replication_config_pb2.ReplicationConfig): A
507 ReplicationConfig that has already been run. If it produced a
508 build_config.json file, that file will be used to generate platform C
509 files. Otherwise, nothing will be generated.
510 chroot (chroot_lib.Chroot): The chroot to use to generate.
511
512 Returns:
513 A list of generated files.
514 """
515 # Generate the platform C files from the build config. Note that it would be
516 # more intuitive to generate the platform C files from the platform config;
517 # however, cros_config_schema does not allow this, because the platform config
518 # payload is not always valid input. For example, if a property is both
519 # 'required' and 'build-only', it will fail schema validation. Thus, use the
520 # build config, and use '-f' to filter.
521 build_config_path = [
522 rule.destination_path
523 for rule in replication_config.file_replication_rules
524 if rule.destination_path.endswith('build_config.json')
525 ]
526
527 if not build_config_path:
528 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700529 'No build_config.json found, will not generate platform C files. '
530 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700531 return []
532
533 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700534 raise ValueError('Expected at most one build_config.json destination path. '
535 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700536
537 build_config_path = build_config_path[0]
538
539 # Paths to the build_config.json and dir to output C files to, in the
540 # chroot.
541 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
542 build_config_path)
543 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
544 os.path.dirname(build_config_path))
545
546 command = [
547 'cros_config_schema', '-m', build_config_chroot_path, '-g',
548 generated_output_chroot_dir, '-f', '"TRUE"'
549 ]
550
551 cros_build_lib.run(
552 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
553
554 # A relative (to the source root) path to the generated C files.
555 generated_output_dir = os.path.dirname(build_config_path)
556 generated_files = []
557 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
558 for f in expected_c_files:
559 if os.path.exists(
560 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
561 generated_files.append(os.path.join(generated_output_dir, f))
562
563 if len(expected_c_files) != len(generated_files):
564 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
565
566 return generated_files
567
568
Andrew Lambe836f222019-12-09 12:27:38 -0700569def _get_private_overlay_package_root(ref, package):
570 """Returns the absolute path to the root of a given private overlay.
571
572 Args:
573 ref (uprev_lib.GitRef): GitRef for the private overlay.
574 package (str): Path to the package in the overlay.
575 """
576 # There might be a cleaner way to map from package -> path within the source
577 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700578 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700579 match = re.match(private_overlay_ref_pattern, ref.path)
580 if not match:
581 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
582 (private_overlay_ref_pattern, ref))
583
584 overlay = match.group(1)
585
586 return os.path.join(constants.SOURCE_ROOT,
587 'src/private-overlays/overlay-%s-private' % overlay,
588 package)
589
590
Andrew Lambea9a8a22019-12-12 14:03:43 -0700591@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
592def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700593 """Replicate a private cros_config change to the corresponding public config.
594
Alex Kleinad6b48a2020-01-08 16:57:41 -0700595 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700596 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700597 package = 'chromeos-base/chromeos-config-bsp'
598
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700599 if len(refs) != 1:
600 raise ValueError('Expected exactly one ref, actual %s' % refs)
601
602 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700603 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700604 replication_config_path = os.path.join(package_root,
605 'replication_config.jsonpb')
606
607 try:
608 replication_config = json_format.Parse(
609 osutils.ReadFile(replication_config_path),
610 replication_config_pb2.ReplicationConfig())
611 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700612 raise ValueError(
613 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700614
615 replication_lib.Replicate(replication_config)
616
617 modified_files = [
618 rule.destination_path
619 for rule in replication_config.file_replication_rules
620 ]
621
Andrew Lamb9563a152019-12-04 11:42:18 -0700622 # The generated platform C files are not easily filtered by replication rules,
623 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
624 # files cannot. Therefore, replicate and filter the JSON payloads, and then
625 # generate filtered C files from the JSON payload.
626 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700627
628 # Use the private repo's commit hash as the new version.
629 new_private_version = refs[0].revision
630
Andrew Lamb988f4da2019-12-10 10:16:43 -0700631 # modified_files should contain only relative paths at this point, but the
632 # returned UprevVersionedPackageResult must contain only absolute paths.
633 for i, modified_file in enumerate(modified_files):
634 assert not os.path.isabs(modified_file)
635 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
636
Chris McDonald38409112020-09-24 11:24:51 -0600637 return uprev_lib.UprevVersionedPackageResult().add_result(
638 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700639
640
Alex Kleinbbef2b32019-08-27 10:38:50 -0600641def get_best_visible(atom, build_target=None):
642 """Returns the best visible CPV for the given atom.
643
644 Args:
645 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600646 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600647 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700648
649 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600650 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600651 """
David Burger1e0fe232019-07-01 14:52:07 -0600652 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600653
654 board = build_target.name if build_target else None
655 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600656
657
Alex Klein149fd3b2019-12-16 16:01:05 -0700658def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600659 """Check if a prebuilt exists.
660
661 Args:
662 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600663 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600664 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700665 useflags: Any additional USE flags that should be set. May be a string
666 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700667
668 Returns:
669 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600670 """
671 assert atom
672
673 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700674 extra_env = None
675 if useflags:
676 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500677 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700678 new_flags = ' '.join(useflags)
679
680 existing = os.environ.get('USE', '')
681 final_flags = '%s %s' % (existing, new_flags)
682 extra_env = {'USE': final_flags.strip()}
683 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600684
685
David Burger0f9dd4e2019-10-08 12:33:42 -0600686def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600687 """Check if |build_target| builds |atom| (has it in its depgraph)."""
688 cros_build_lib.AssertInsideChroot()
689
Alex Kleind8cd4c62020-09-14 13:37:47 -0600690 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600691 # TODO(crbug/1081828): Receive and use sysroot.
692 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600693 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600694 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600695
696
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600697def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600698 """Returns the current Chrome version for the board (or in buildroot).
699
700 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600701 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700702
703 Returns:
704 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600705 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600706 # TODO(crbug/1019770): Long term we should not need the try/catch here once
707 # the builds function above only returns True for chrome when
708 # determine_chrome_version will succeed.
709 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700710 cpv = portage_util.PortageqBestVisible(
711 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600712 except cros_build_lib.RunCommandError as e:
713 # Return None because portage failed when trying to determine the chrome
714 # version.
715 logging.warning('Caught exception in determine_chrome_package: %s', e)
716 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600717 # Something like 78.0.3877.4_rc -> 78.0.3877.4
718 return cpv.version_no_rev.partition('_')[0]
719
720
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600721def determine_android_package(board):
722 """Returns the active Android container package in use by the board.
723
724 Args:
725 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700726
727 Returns:
728 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600729 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600730 try:
731 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600732 except cros_build_lib.RunCommandError as e:
733 # Return None because a command (likely portage) failed when trying to
734 # determine the package.
735 logging.warning('Caught exception in determine_android_package: %s', e)
736 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600737
Alex Kleinad6b48a2020-01-08 16:57:41 -0700738 # We assume there is only one Android package in the depgraph.
739 for package in packages:
740 if package.startswith('chromeos-base/android-container-') or \
741 package.startswith('chromeos-base/android-vm-'):
742 return package
743 return None
744
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600745
746def determine_android_version(boards=None):
747 """Determine the current Android version in buildroot now and return it.
748
749 This uses the typical portage logic to determine which version of Android
750 is active right now in the buildroot.
751
752 Args:
753 boards: List of boards to check version of.
754
755 Returns:
756 The Android build ID of the container for the boards.
757
758 Raises:
759 NoAndroidVersionError: if no unique Android version can be determined.
760 """
761 if not boards:
762 return None
763 # Verify that all boards have the same version.
764 version = None
765 for board in boards:
766 package = determine_android_package(board)
767 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600768 return None
Alex Klein18a60af2020-06-11 12:08:47 -0600769 cpv = package_info.SplitCPV(package)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600770 if not cpv:
771 raise NoAndroidVersionError(
772 'Android version could not be determined for %s' % board)
773 if not version:
774 version = cpv.version_no_rev
775 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700776 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
777 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600778 return version
779
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700780
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600781def determine_android_branch(board):
782 """Returns the Android branch in use by the active container ebuild."""
783 try:
784 android_package = determine_android_package(board)
785 except cros_build_lib.RunCommandError:
786 raise NoAndroidBranchError(
787 'Android branch could not be determined for %s' % board)
788 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600789 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600790 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
791 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900792 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900793 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600794 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
795 for target in targets:
796 if target in ebuild_content:
797 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
798 if branch is not None:
799 return branch.group(1)
800 raise NoAndroidBranchError(
801 'Android branch could not be determined for %s (ebuild empty?)' % board)
802
803
804def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600805 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600806 try:
807 android_package = determine_android_package(board)
808 except cros_build_lib.RunCommandError:
809 raise NoAndroidTargetError(
810 'Android Target could not be determined for %s' % board)
811 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600812 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600813 if android_package.startswith('chromeos-base/android-vm-'):
814 return 'bertha'
815 elif android_package.startswith('chromeos-base/android-container-'):
816 return 'cheets'
817
818 raise NoAndroidTargetError(
819 'Android Target cannot be determined for the package: %s' %
820 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600821
822
823def determine_platform_version():
824 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600825 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600826 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
827 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600828
829
830def determine_milestone_version():
831 """Returns the platform version from the source root."""
832 # Milestone version is something like '79'.
833 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
834 return version.chrome_branch
835
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700836
Michael Mortensen009cb662019-10-21 11:38:43 -0600837def determine_full_version():
838 """Returns the full version from the source root."""
839 # Full version is something like 'R79-12575.0.0'.
840 milestone_version = determine_milestone_version()
841 platform_version = determine_platform_version()
842 full_version = ('R%s-%s' % (milestone_version, platform_version))
843 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600844
845
Michael Mortensende716a12020-05-15 11:27:00 -0600846def find_fingerprints(build_target):
847 """Returns a list of fingerprints for this build.
848
849 Args:
850 build_target (build_target_lib.BuildTarget): The build target.
851
852 Returns:
853 list[str] - List of fingerprint strings.
854 """
855 cros_build_lib.AssertInsideChroot()
856 fp_file = 'cheets-fingerprint.txt'
857 fp_path = os.path.join(
858 image_lib.GetLatestImageLink(build_target.name),
859 fp_file)
860 if not os.path.isfile(fp_path):
861 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600862 return []
Michael Mortensende716a12020-05-15 11:27:00 -0600863 logging.info('Reading fingerprint file: %s', fp_path)
864 fingerprints = osutils.ReadFile(fp_path).splitlines()
865 return fingerprints
866
867
Michael Mortensen59e30872020-05-18 14:12:49 -0600868def get_all_firmware_versions(build_target):
869 """Extract firmware version for all models present.
870
871 Args:
872 build_target (build_target_lib.BuildTarget): The build target.
873
874 Returns:
875 A dict of FirmwareVersions namedtuple instances by model.
876 Each element will be populated based on whether it was present in the
877 command output.
878 """
879 cros_build_lib.AssertInsideChroot()
880 result = {}
881 # Note that example output for _get_firmware_version_cmd_result is available
882 # in the packages_unittest.py for testing get_all_firmware_versions.
883 cmd_result = _get_firmware_version_cmd_result(build_target)
884
885 # There is a blank line between the version info for each model.
886 firmware_version_payloads = cmd_result.split('\n\n')
887 for firmware_version_payload in firmware_version_payloads:
888 if 'BIOS' in firmware_version_payload:
889 firmware_version = _find_firmware_versions(firmware_version_payload)
890 result[firmware_version.model] = firmware_version
891 return result
892
893
Michael Mortensen71ef5682020-05-07 14:29:24 -0600894FirmwareVersions = collections.namedtuple(
895 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
896
897
898def get_firmware_versions(build_target):
899 """Extract version information from the firmware updater, if one exists.
900
901 Args:
902 build_target (build_target_lib.BuildTarget): The build target.
903
904 Returns:
905 A FirmwareVersions namedtuple instance.
906 Each element will either be set to the string output by the firmware
907 updater shellball, or None if there is no firmware updater.
908 """
909 cros_build_lib.AssertInsideChroot()
910 cmd_result = _get_firmware_version_cmd_result(build_target)
911 if cmd_result:
912 return _find_firmware_versions(cmd_result)
913 else:
914 return FirmwareVersions(None, None, None, None, None)
915
916
917def _get_firmware_version_cmd_result(build_target):
918 """Gets the raw result output of the firmware updater version command.
919
920 Args:
921 build_target (build_target_lib.BuildTarget): The build target.
922
923 Returns:
924 Command execution result.
925 """
926 updater = os.path.join(build_target.root,
927 'usr/sbin/chromeos-firmwareupdate')
928 logging.info('Calling updater %s', updater)
929 # Call the updater using the chroot-based path.
930 return cros_build_lib.run([updater, '-V'],
931 capture_output=True, log_output=True,
932 encoding='utf-8').stdout
933
934
935def _find_firmware_versions(cmd_output):
936 """Finds firmware version output via regex matches against the cmd_output.
937
938 Args:
939 cmd_output: The raw output to search against.
940
941 Returns:
942 FirmwareVersions namedtuple with results.
943 Each element will either be set to the string output by the firmware
944 updater shellball, or None if there is no match.
945 """
946
947 # Sometimes a firmware bundle includes a special combination of RO+RW
948 # firmware. In this case, the RW firmware version is indicated with a "(RW)
949 # version" field. In other cases, the "(RW) version" field is not present.
950 # Therefore, search for the "(RW)" fields first and if they aren't present,
951 # fallback to the other format. e.g. just "BIOS version:".
952 # TODO(mmortensen): Use JSON once the firmware updater supports it.
953 main = None
954 main_rw = None
955 ec = None
956 ec_rw = None
957 model = None
958
959 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
960 if match:
961 main = match.group('version')
962
963 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
964 if match:
965 main_rw = match.group('version')
966
967 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
968 if match:
969 ec = match.group('version')
970
971 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
972 if match:
973 ec_rw = match.group('version')
974
975 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
976 if match:
977 model = match.group('model')
978
979 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -0600980
981
982MainEcFirmwareVersions = collections.namedtuple(
983 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
984
985def determine_firmware_versions(build_target):
986 """Returns a namedtuple with main and ec firmware versions.
987
988 Args:
989 build_target (build_target_lib.BuildTarget): The build target.
990
991 Returns:
992 MainEcFirmwareVersions namedtuple with results.
993 """
994 fw_versions = get_firmware_versions(build_target)
995 main_fw_version = fw_versions.main_rw or fw_versions.main
996 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
997
998 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -0600999
1000def determine_kernel_version(build_target):
1001 """Returns a string containing the kernel version for this build target.
1002
1003 Args:
1004 build_target (build_target_lib.BuildTarget): The build target.
1005
1006 Returns:
1007 (str) The kernel versions, or None.
1008 """
1009 try:
1010 packages = portage_util.GetPackageDependencies(build_target.name,
1011 'virtual/linux-sources')
1012 except cros_build_lib.RunCommandError as e:
1013 logging.warning('Unable to get package list for metadata: %s', e)
1014 return None
1015 for package in packages:
1016 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001017 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001018 logging.info('Found active kernel version: %s', kernel_version)
1019 return kernel_version
1020 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001021
1022
1023def get_models(build_target, log_output=True):
1024 """Obtain a list of models supported by a unified board.
1025
1026 This ignored whitelabel models since GoldenEye has no specific support for
1027 these at present.
1028
1029 Args:
1030 build_target (build_target_lib.BuildTarget): The build target.
1031 log_output: Whether to log the output of the cros_config_host invocation.
1032
1033 Returns:
1034 A list of models supported by this board, if it is a unified build; None,
1035 if it is not a unified build.
1036 """
1037 return _run_cros_config_host(build_target, ['list-models'],
1038 log_output=log_output)
1039
1040
Michael Mortensen359c1f32020-05-28 19:35:42 -06001041def get_key_id(build_target, model):
1042 """Obtain the key_id for a model within the build_target.
1043
1044 Args:
1045 build_target (build_target_lib.BuildTarget): The build target.
1046 model (str): The model name
1047
1048 Returns:
1049 A key_id (str) or None.
1050 """
1051 model_arg = '--model=' + model
1052 key_id_list = _run_cros_config_host(
1053 build_target,
1054 [model_arg, 'get', '/firmware-signing', 'key-id'])
1055 key_id = None
1056 if len(key_id_list) == 1:
1057 key_id = key_id_list[0]
1058 return key_id
1059
1060
Michael Mortensen125bb012020-05-21 14:02:10 -06001061def _run_cros_config_host(build_target, args, log_output=True):
1062 """Run the cros_config_host tool.
1063
1064 Args:
1065 build_target (build_target_lib.BuildTarget): The build target.
1066 args: List of arguments to pass.
1067 log_output: Whether to log the output of the cros_config_host.
1068
1069 Returns:
1070 Output of the tool
1071 """
1072 cros_build_lib.AssertInsideChroot()
1073 tool = '/usr/bin/cros_config_host'
1074 if not os.path.isfile(tool):
1075 return None
1076
1077 config_fname = build_target.full_path(
1078 'usr/share/chromeos-config/yaml/config.yaml')
1079
1080 result = cros_build_lib.run(
1081 [tool, '-c', config_fname] + args,
1082 capture_output=True,
1083 encoding='utf-8',
1084 log_output=log_output,
1085 check=False)
1086 if result.returncode:
1087 # Show the output for debugging purposes.
1088 if 'No such file or directory' not in result.error:
1089 logging.error('cros_config_host failed: %s\n', result.error)
1090 return None
1091 return result.output.strip().splitlines()