blob: 5cb37c3fde960fa4a6746dbe7d80dabbe5c83559 [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
Alex Klein149fd3b2019-12-16 16:01:05 -070018import six
19
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
299 DRIVEFS_REFS = 'refs/tags/drivefs_'
300 DRIVEFS_PATH = 'src/private-overlays/chromeos-overlay/chromeos-base'
301
302 # parse like the example PUpr (go/pupr#steps)
303 valid_refs = [ref.ref for ref in refs if ref.ref.startswith(DRIVEFS_REFS)]
304 if not valid_refs:
305 # False alarm, there is no new package release. So do nothing.
306 return None
307
308 # Take the newest release, always.
309 target_version = sorted(valid_refs,
310 reverse=True)[0][len(DRIVEFS_REFS):]
311
312 result = uprev_lib.UprevVersionedPackageResult()
313
Jose Magana8196d0b2020-10-30 10:15:57 +1100314 pkg_path = os.path.join(DRIVEFS_PATH, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000315
316 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
317 target_version,
318 chroot)
319 all_changed_files = []
320
321 if not uprev_result:
322 return None # alternatively raise Exception
323
324 all_changed_files.extend(uprev_result.changed_files)
325
Jose Magana8196d0b2020-10-30 10:15:57 +1100326 pkg_path = os.path.join(DRIVEFS_PATH, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000327
328 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
329 target_version,
330 chroot)
331
332 if not uprev_result:
333 return None # alternatively raise Exception
334
335 all_changed_files.extend(uprev_result.changed_files)
336
337 result.add_result(target_version, all_changed_files)
338
339 return result
340
Navil Perezf57ba872020-06-04 22:38:37 +0000341
Yaakov Shaul395ae832019-09-09 14:45:32 -0600342@uprevs_versioned_package('afdo/kernel-profiles')
343def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600344 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600345
346 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600347
348 Raises:
349 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600350 """
351 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
352 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
353
David Burger92485342019-09-10 17:52:45 -0600354 with open(path, 'r') as f:
355 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600356
Chris McDonald38409112020-09-24 11:24:51 -0600357 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600358 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600359 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
360 'sys-kernel', version)
361 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
362 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600363 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
364 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600365 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600366 patch_ebuild_vars(ebuild_path,
367 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600368
369 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600370 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400371 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600372 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600373 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600374 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600375 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600376
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600377 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600378
Yaakov Shaul730814a2019-09-10 13:58:25 -0600379 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
380
381 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600382
383
Trent Begineb624182020-07-14 10:09:45 -0600384@uprevs_versioned_package('chromeos-base/termina-dlc')
385def uprev_termina_dlc(_build_targets, _refs, chroot):
386 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600387
388 See: uprev_versioned_package.
389 """
Trent Begineb624182020-07-14 10:09:45 -0600390 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600391 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
392 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000393
394 version_pin_src_path = _get_version_pin_src_path(package_path)
395 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
396
Chris McDonald38409112020-09-24 11:24:51 -0600397 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000398
399
400@uprevs_versioned_package('app-emulation/parallels-desktop')
401def uprev_parallels_desktop(_build_targets, _refs, chroot):
402 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
403
404 See: uprev_versioned_package
405
406 Returns:
407 UprevVersionedPackageResult: The result.
408 """
409 package = 'parallels-desktop'
410 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
411 'app-emulation', package)
412 version_pin_src_path = _get_version_pin_src_path(package_path)
413
414 # Expect a JSON blob like the following:
415 # {
416 # "version": "1.2.3",
417 # "test_image": { "url": "...", "size": 12345678,
418 # "sha256sum": "<32 bytes of hexadecimal>" }
419 # }
420 with open(version_pin_src_path, 'r') as f:
421 pinned = json.load(f)
422
423 if 'version' not in pinned or 'test_image' not in pinned:
424 raise UprevError('VERSION-PIN for %s missing version and/or '
425 'test_image field' % package)
426
427 version = pinned['version']
428 if not isinstance(version, str):
429 raise UprevError('version in VERSION-PIN for %s not a string' % package)
430
431 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600432 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000433
434 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100435 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
436 'local/bundles/crosint/pita/data/'
437 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000438 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
439 with open(test_image_src_path, 'w') as f:
440 json.dump(pinned['test_image'], f, indent=2)
441 result.add_result(version, [test_image_src_path])
442
443 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600444
445
Trent Begin315d9d92019-12-03 21:55:53 -0700446@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600447def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700448 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
449
450 See: uprev_versioned_package.
451 """
452 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700453 package_path = os.path.join('src', 'private-overlays',
454 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000455 version_pin_src_path = _get_version_pin_src_path(package_path)
456 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700457
Chris McDonald38409112020-09-24 11:24:51 -0600458 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700459
460
Patrick Meiring5897add2020-09-16 16:30:17 +1000461def _get_version_pin_src_path(package_path):
462 """Returns the path to the VERSION-PIN file for the given package."""
463 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
464
465
Alex Klein87531182019-08-12 15:23:37 -0600466@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700467def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600468 """Uprev chrome and its related packages.
469
470 See: uprev_versioned_package.
471 """
472 # Determine the version from the refs (tags), i.e. the chrome versions are the
473 # tag names.
474 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600475 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600476
477 uprev_manager = uprev_lib.UprevChromeManager(
478 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600479 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600480 # Start with chrome itself, as we can't do anything else unless chrome
481 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600482 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
483 # attempt. The expected behavior is documented in the following table:
484 #
485 # Outcome of Chrome uprev attempt:
486 # NEWER_VERSION_EXISTS:
487 # Do nothing.
488 # SAME_VERSION_EXISTS or REVISION_BUMP:
489 # Uprev followers
490 # Assert not VERSION_BUMP (any other outcome is fine)
491 # VERSION_BUMP or NEW_EBUILD_CREATED:
492 # Uprev followers
493 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600494 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600495 return result
Alex Klein87531182019-08-12 15:23:37 -0600496
497 # With a successful chrome rev, also uprev related packages.
498 for package in constants.OTHER_CHROME_PACKAGES:
499 uprev_manager.uprev(package)
500
David Burger37f48672019-09-18 17:07:56 -0600501 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600502
503
Andrew Lamb9563a152019-12-04 11:42:18 -0700504def _generate_platform_c_files(replication_config, chroot):
505 """Generates platform C files from a platform JSON payload.
506
507 Args:
508 replication_config (replication_config_pb2.ReplicationConfig): A
509 ReplicationConfig that has already been run. If it produced a
510 build_config.json file, that file will be used to generate platform C
511 files. Otherwise, nothing will be generated.
512 chroot (chroot_lib.Chroot): The chroot to use to generate.
513
514 Returns:
515 A list of generated files.
516 """
517 # Generate the platform C files from the build config. Note that it would be
518 # more intuitive to generate the platform C files from the platform config;
519 # however, cros_config_schema does not allow this, because the platform config
520 # payload is not always valid input. For example, if a property is both
521 # 'required' and 'build-only', it will fail schema validation. Thus, use the
522 # build config, and use '-f' to filter.
523 build_config_path = [
524 rule.destination_path
525 for rule in replication_config.file_replication_rules
526 if rule.destination_path.endswith('build_config.json')
527 ]
528
529 if not build_config_path:
530 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700531 'No build_config.json found, will not generate platform C files. '
532 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700533 return []
534
535 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700536 raise ValueError('Expected at most one build_config.json destination path. '
537 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700538
539 build_config_path = build_config_path[0]
540
541 # Paths to the build_config.json and dir to output C files to, in the
542 # chroot.
543 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
544 build_config_path)
545 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
546 os.path.dirname(build_config_path))
547
548 command = [
549 'cros_config_schema', '-m', build_config_chroot_path, '-g',
550 generated_output_chroot_dir, '-f', '"TRUE"'
551 ]
552
553 cros_build_lib.run(
554 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
555
556 # A relative (to the source root) path to the generated C files.
557 generated_output_dir = os.path.dirname(build_config_path)
558 generated_files = []
559 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
560 for f in expected_c_files:
561 if os.path.exists(
562 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
563 generated_files.append(os.path.join(generated_output_dir, f))
564
565 if len(expected_c_files) != len(generated_files):
566 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
567
568 return generated_files
569
570
Andrew Lambe836f222019-12-09 12:27:38 -0700571def _get_private_overlay_package_root(ref, package):
572 """Returns the absolute path to the root of a given private overlay.
573
574 Args:
575 ref (uprev_lib.GitRef): GitRef for the private overlay.
576 package (str): Path to the package in the overlay.
577 """
578 # There might be a cleaner way to map from package -> path within the source
579 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700580 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700581 match = re.match(private_overlay_ref_pattern, ref.path)
582 if not match:
583 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
584 (private_overlay_ref_pattern, ref))
585
586 overlay = match.group(1)
587
588 return os.path.join(constants.SOURCE_ROOT,
589 'src/private-overlays/overlay-%s-private' % overlay,
590 package)
591
592
Andrew Lambea9a8a22019-12-12 14:03:43 -0700593@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
594def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700595 """Replicate a private cros_config change to the corresponding public config.
596
Alex Kleinad6b48a2020-01-08 16:57:41 -0700597 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700598 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700599 package = 'chromeos-base/chromeos-config-bsp'
600
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700601 if len(refs) != 1:
602 raise ValueError('Expected exactly one ref, actual %s' % refs)
603
604 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700605 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700606 replication_config_path = os.path.join(package_root,
607 'replication_config.jsonpb')
608
609 try:
610 replication_config = json_format.Parse(
611 osutils.ReadFile(replication_config_path),
612 replication_config_pb2.ReplicationConfig())
613 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700614 raise ValueError(
615 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700616
617 replication_lib.Replicate(replication_config)
618
619 modified_files = [
620 rule.destination_path
621 for rule in replication_config.file_replication_rules
622 ]
623
Andrew Lamb9563a152019-12-04 11:42:18 -0700624 # The generated platform C files are not easily filtered by replication rules,
625 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
626 # files cannot. Therefore, replicate and filter the JSON payloads, and then
627 # generate filtered C files from the JSON payload.
628 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700629
630 # Use the private repo's commit hash as the new version.
631 new_private_version = refs[0].revision
632
Andrew Lamb988f4da2019-12-10 10:16:43 -0700633 # modified_files should contain only relative paths at this point, but the
634 # returned UprevVersionedPackageResult must contain only absolute paths.
635 for i, modified_file in enumerate(modified_files):
636 assert not os.path.isabs(modified_file)
637 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
638
Chris McDonald38409112020-09-24 11:24:51 -0600639 return uprev_lib.UprevVersionedPackageResult().add_result(
640 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700641
642
Alex Kleinbbef2b32019-08-27 10:38:50 -0600643def get_best_visible(atom, build_target=None):
644 """Returns the best visible CPV for the given atom.
645
646 Args:
647 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600648 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600649 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700650
651 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600652 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600653 """
David Burger1e0fe232019-07-01 14:52:07 -0600654 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600655
656 board = build_target.name if build_target else None
657 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600658
659
Alex Klein149fd3b2019-12-16 16:01:05 -0700660def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600661 """Check if a prebuilt exists.
662
663 Args:
664 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600665 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600666 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700667 useflags: Any additional USE flags that should be set. May be a string
668 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700669
670 Returns:
671 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600672 """
673 assert atom
674
675 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700676 extra_env = None
677 if useflags:
678 new_flags = useflags
679 if not isinstance(useflags, six.string_types):
680 new_flags = ' '.join(useflags)
681
682 existing = os.environ.get('USE', '')
683 final_flags = '%s %s' % (existing, new_flags)
684 extra_env = {'USE': final_flags.strip()}
685 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600686
687
David Burger0f9dd4e2019-10-08 12:33:42 -0600688def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600689 """Check if |build_target| builds |atom| (has it in its depgraph)."""
690 cros_build_lib.AssertInsideChroot()
691
Alex Kleind8cd4c62020-09-14 13:37:47 -0600692 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600693 # TODO(crbug/1081828): Receive and use sysroot.
694 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600695 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600696 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600697
698
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600699def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600700 """Returns the current Chrome version for the board (or in buildroot).
701
702 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600703 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700704
705 Returns:
706 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600707 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600708 # TODO(crbug/1019770): Long term we should not need the try/catch here once
709 # the builds function above only returns True for chrome when
710 # determine_chrome_version will succeed.
711 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700712 cpv = portage_util.PortageqBestVisible(
713 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600714 except cros_build_lib.RunCommandError as e:
715 # Return None because portage failed when trying to determine the chrome
716 # version.
717 logging.warning('Caught exception in determine_chrome_package: %s', e)
718 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600719 # Something like 78.0.3877.4_rc -> 78.0.3877.4
720 return cpv.version_no_rev.partition('_')[0]
721
722
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600723def determine_android_package(board):
724 """Returns the active Android container package in use by the board.
725
726 Args:
727 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700728
729 Returns:
730 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600731 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600732 try:
733 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600734 except cros_build_lib.RunCommandError as e:
735 # Return None because a command (likely portage) failed when trying to
736 # determine the package.
737 logging.warning('Caught exception in determine_android_package: %s', e)
738 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600739
Alex Kleinad6b48a2020-01-08 16:57:41 -0700740 # We assume there is only one Android package in the depgraph.
741 for package in packages:
742 if package.startswith('chromeos-base/android-container-') or \
743 package.startswith('chromeos-base/android-vm-'):
744 return package
745 return None
746
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600747
748def determine_android_version(boards=None):
749 """Determine the current Android version in buildroot now and return it.
750
751 This uses the typical portage logic to determine which version of Android
752 is active right now in the buildroot.
753
754 Args:
755 boards: List of boards to check version of.
756
757 Returns:
758 The Android build ID of the container for the boards.
759
760 Raises:
761 NoAndroidVersionError: if no unique Android version can be determined.
762 """
763 if not boards:
764 return None
765 # Verify that all boards have the same version.
766 version = None
767 for board in boards:
768 package = determine_android_package(board)
769 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600770 return None
Alex Klein18a60af2020-06-11 12:08:47 -0600771 cpv = package_info.SplitCPV(package)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600772 if not cpv:
773 raise NoAndroidVersionError(
774 'Android version could not be determined for %s' % board)
775 if not version:
776 version = cpv.version_no_rev
777 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700778 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
779 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600780 return version
781
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700782
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600783def determine_android_branch(board):
784 """Returns the Android branch in use by the active container ebuild."""
785 try:
786 android_package = determine_android_package(board)
787 except cros_build_lib.RunCommandError:
788 raise NoAndroidBranchError(
789 'Android branch could not be determined for %s' % board)
790 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600791 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600792 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
793 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900794 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900795 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600796 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
797 for target in targets:
798 if target in ebuild_content:
799 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
800 if branch is not None:
801 return branch.group(1)
802 raise NoAndroidBranchError(
803 'Android branch could not be determined for %s (ebuild empty?)' % board)
804
805
806def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600807 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600808 try:
809 android_package = determine_android_package(board)
810 except cros_build_lib.RunCommandError:
811 raise NoAndroidTargetError(
812 'Android Target could not be determined for %s' % board)
813 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600814 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600815 if android_package.startswith('chromeos-base/android-vm-'):
816 return 'bertha'
817 elif android_package.startswith('chromeos-base/android-container-'):
818 return 'cheets'
819
820 raise NoAndroidTargetError(
821 'Android Target cannot be determined for the package: %s' %
822 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600823
824
825def determine_platform_version():
826 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600827 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600828 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
829 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600830
831
832def determine_milestone_version():
833 """Returns the platform version from the source root."""
834 # Milestone version is something like '79'.
835 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
836 return version.chrome_branch
837
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700838
Michael Mortensen009cb662019-10-21 11:38:43 -0600839def determine_full_version():
840 """Returns the full version from the source root."""
841 # Full version is something like 'R79-12575.0.0'.
842 milestone_version = determine_milestone_version()
843 platform_version = determine_platform_version()
844 full_version = ('R%s-%s' % (milestone_version, platform_version))
845 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600846
847
Michael Mortensende716a12020-05-15 11:27:00 -0600848def find_fingerprints(build_target):
849 """Returns a list of fingerprints for this build.
850
851 Args:
852 build_target (build_target_lib.BuildTarget): The build target.
853
854 Returns:
855 list[str] - List of fingerprint strings.
856 """
857 cros_build_lib.AssertInsideChroot()
858 fp_file = 'cheets-fingerprint.txt'
859 fp_path = os.path.join(
860 image_lib.GetLatestImageLink(build_target.name),
861 fp_file)
862 if not os.path.isfile(fp_path):
863 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600864 return []
Michael Mortensende716a12020-05-15 11:27:00 -0600865 logging.info('Reading fingerprint file: %s', fp_path)
866 fingerprints = osutils.ReadFile(fp_path).splitlines()
867 return fingerprints
868
869
Michael Mortensen59e30872020-05-18 14:12:49 -0600870def get_all_firmware_versions(build_target):
871 """Extract firmware version for all models present.
872
873 Args:
874 build_target (build_target_lib.BuildTarget): The build target.
875
876 Returns:
877 A dict of FirmwareVersions namedtuple instances by model.
878 Each element will be populated based on whether it was present in the
879 command output.
880 """
881 cros_build_lib.AssertInsideChroot()
882 result = {}
883 # Note that example output for _get_firmware_version_cmd_result is available
884 # in the packages_unittest.py for testing get_all_firmware_versions.
885 cmd_result = _get_firmware_version_cmd_result(build_target)
886
887 # There is a blank line between the version info for each model.
888 firmware_version_payloads = cmd_result.split('\n\n')
889 for firmware_version_payload in firmware_version_payloads:
890 if 'BIOS' in firmware_version_payload:
891 firmware_version = _find_firmware_versions(firmware_version_payload)
892 result[firmware_version.model] = firmware_version
893 return result
894
895
Michael Mortensen71ef5682020-05-07 14:29:24 -0600896FirmwareVersions = collections.namedtuple(
897 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
898
899
900def get_firmware_versions(build_target):
901 """Extract version information from the firmware updater, if one exists.
902
903 Args:
904 build_target (build_target_lib.BuildTarget): The build target.
905
906 Returns:
907 A FirmwareVersions namedtuple instance.
908 Each element will either be set to the string output by the firmware
909 updater shellball, or None if there is no firmware updater.
910 """
911 cros_build_lib.AssertInsideChroot()
912 cmd_result = _get_firmware_version_cmd_result(build_target)
913 if cmd_result:
914 return _find_firmware_versions(cmd_result)
915 else:
916 return FirmwareVersions(None, None, None, None, None)
917
918
919def _get_firmware_version_cmd_result(build_target):
920 """Gets the raw result output of the firmware updater version command.
921
922 Args:
923 build_target (build_target_lib.BuildTarget): The build target.
924
925 Returns:
926 Command execution result.
927 """
928 updater = os.path.join(build_target.root,
929 'usr/sbin/chromeos-firmwareupdate')
930 logging.info('Calling updater %s', updater)
931 # Call the updater using the chroot-based path.
932 return cros_build_lib.run([updater, '-V'],
933 capture_output=True, log_output=True,
934 encoding='utf-8').stdout
935
936
937def _find_firmware_versions(cmd_output):
938 """Finds firmware version output via regex matches against the cmd_output.
939
940 Args:
941 cmd_output: The raw output to search against.
942
943 Returns:
944 FirmwareVersions namedtuple with results.
945 Each element will either be set to the string output by the firmware
946 updater shellball, or None if there is no match.
947 """
948
949 # Sometimes a firmware bundle includes a special combination of RO+RW
950 # firmware. In this case, the RW firmware version is indicated with a "(RW)
951 # version" field. In other cases, the "(RW) version" field is not present.
952 # Therefore, search for the "(RW)" fields first and if they aren't present,
953 # fallback to the other format. e.g. just "BIOS version:".
954 # TODO(mmortensen): Use JSON once the firmware updater supports it.
955 main = None
956 main_rw = None
957 ec = None
958 ec_rw = None
959 model = None
960
961 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
962 if match:
963 main = match.group('version')
964
965 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
966 if match:
967 main_rw = match.group('version')
968
969 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
970 if match:
971 ec = match.group('version')
972
973 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
974 if match:
975 ec_rw = match.group('version')
976
977 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
978 if match:
979 model = match.group('model')
980
981 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -0600982
983
984MainEcFirmwareVersions = collections.namedtuple(
985 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
986
987def determine_firmware_versions(build_target):
988 """Returns a namedtuple with main and ec firmware versions.
989
990 Args:
991 build_target (build_target_lib.BuildTarget): The build target.
992
993 Returns:
994 MainEcFirmwareVersions namedtuple with results.
995 """
996 fw_versions = get_firmware_versions(build_target)
997 main_fw_version = fw_versions.main_rw or fw_versions.main
998 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
999
1000 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001001
1002def determine_kernel_version(build_target):
1003 """Returns a string containing the kernel version for this build target.
1004
1005 Args:
1006 build_target (build_target_lib.BuildTarget): The build target.
1007
1008 Returns:
1009 (str) The kernel versions, or None.
1010 """
1011 try:
1012 packages = portage_util.GetPackageDependencies(build_target.name,
1013 'virtual/linux-sources')
1014 except cros_build_lib.RunCommandError as e:
1015 logging.warning('Unable to get package list for metadata: %s', e)
1016 return None
1017 for package in packages:
1018 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001019 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001020 logging.info('Found active kernel version: %s', kernel_version)
1021 return kernel_version
1022 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001023
1024
1025def get_models(build_target, log_output=True):
1026 """Obtain a list of models supported by a unified board.
1027
1028 This ignored whitelabel models since GoldenEye has no specific support for
1029 these at present.
1030
1031 Args:
1032 build_target (build_target_lib.BuildTarget): The build target.
1033 log_output: Whether to log the output of the cros_config_host invocation.
1034
1035 Returns:
1036 A list of models supported by this board, if it is a unified build; None,
1037 if it is not a unified build.
1038 """
1039 return _run_cros_config_host(build_target, ['list-models'],
1040 log_output=log_output)
1041
1042
Michael Mortensen359c1f32020-05-28 19:35:42 -06001043def get_key_id(build_target, model):
1044 """Obtain the key_id for a model within the build_target.
1045
1046 Args:
1047 build_target (build_target_lib.BuildTarget): The build target.
1048 model (str): The model name
1049
1050 Returns:
1051 A key_id (str) or None.
1052 """
1053 model_arg = '--model=' + model
1054 key_id_list = _run_cros_config_host(
1055 build_target,
1056 [model_arg, 'get', '/firmware-signing', 'key-id'])
1057 key_id = None
1058 if len(key_id_list) == 1:
1059 key_id = key_id_list[0]
1060 return key_id
1061
1062
Michael Mortensen125bb012020-05-21 14:02:10 -06001063def _run_cros_config_host(build_target, args, log_output=True):
1064 """Run the cros_config_host tool.
1065
1066 Args:
1067 build_target (build_target_lib.BuildTarget): The build target.
1068 args: List of arguments to pass.
1069 log_output: Whether to log the output of the cros_config_host.
1070
1071 Returns:
1072 Output of the tool
1073 """
1074 cros_build_lib.AssertInsideChroot()
1075 tool = '/usr/bin/cros_config_host'
1076 if not os.path.isfile(tool):
1077 return None
1078
1079 config_fname = build_target.full_path(
1080 'usr/share/chromeos-config/yaml/config.yaml')
1081
1082 result = cros_build_lib.run(
1083 [tool, '-c', config_fname] + args,
1084 capture_output=True,
1085 encoding='utf-8',
1086 log_output=log_output,
1087 check=False)
1088 if result.returncode:
1089 # Show the output for debugging purposes.
1090 if 'No such file or directory' not in result.error:
1091 logging.error('cros_config_host failed: %s\n', result.error)
1092 return None
1093 return result.output.strip().splitlines()