blob: 39d85239c62def652854478a3afb62f1c0f496fe [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 Kleineb77ffa2019-05-28 14:47:44 -060033
Alex Klein36b117f2019-09-30 15:13:46 -060034if cros_build_lib.IsInsideChroot():
35 from chromite.service import dependency
36
Mike Frysingerbafb3182020-02-21 03:15:43 -050037
Alex Klein87531182019-08-12 15:23:37 -060038# Registered handlers for uprevving versioned packages.
39_UPREV_FUNCS = {}
40
Alex Kleineb77ffa2019-05-28 14:47:44 -060041
42class Error(Exception):
43 """Module's base error class."""
44
45
Alex Klein4de25e82019-08-05 15:58:39 -060046class UnknownPackageError(Error):
47 """Uprev attempted for a package without a registered handler."""
48
49
Alex Kleineb77ffa2019-05-28 14:47:44 -060050class UprevError(Error):
51 """An error occurred while uprevving packages."""
52
53
Michael Mortensenb70e8a82019-10-10 18:43:41 -060054class NoAndroidVersionError(Error):
55 """An error occurred while trying to determine the android version."""
56
57
58class NoAndroidBranchError(Error):
59 """An error occurred while trying to determine the android branch."""
60
61
62class NoAndroidTargetError(Error):
63 """An error occurred while trying to determine the android target."""
64
65
Alex Klein4de25e82019-08-05 15:58:39 -060066class AndroidIsPinnedUprevError(UprevError):
67 """Raised when we try to uprev while Android is pinned."""
68
69 def __init__(self, new_android_atom):
70 """Initialize a AndroidIsPinnedUprevError.
71
72 Args:
73 new_android_atom: The Android atom that we failed to
74 uprev to, due to Android being pinned.
75 """
76 assert new_android_atom
77 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
78 new_android_atom)
79 super(AndroidIsPinnedUprevError, self).__init__(msg)
80 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060081
82
Yaakov Shaul1eafe832019-09-10 16:50:26 -060083class EbuildManifestError(Error):
84 """Error when running ebuild manifest."""
85
86
Andrew Lamb9563a152019-12-04 11:42:18 -070087class GeneratedCrosConfigFilesError(Error):
88 """Error when cros_config_schema does not produce expected files"""
89
90 def __init__(self, expected_files, found_files):
91 msg = ('Expected to find generated C files: %s. Actually found: %s' %
92 (expected_files, found_files))
93 super(GeneratedCrosConfigFilesError, self).__init__(msg)
94
Alex Klein7a3a7dd2020-01-08 16:44:38 -070095
Yaakov Shaul730814a2019-09-10 13:58:25 -060096UprevVersionedPackageModifications = collections.namedtuple(
97 'UprevVersionedPackageModifications', ('new_version', 'files'))
Alex Klein34afcbc2019-08-22 16:14:31 -060098
Yaakov Shaul730814a2019-09-10 13:58:25 -060099
100class UprevVersionedPackageResult(object):
101 """Data object for uprev_versioned_package."""
102
103 def __init__(self):
104 self.modified = []
105
106 def add_result(self, new_version, modified_files):
107 """Adds version/ebuilds tuple to result.
108
109 Args:
110 new_version: New version number of package.
111 modified_files: List of files modified for the given version.
112 """
113 result = UprevVersionedPackageModifications(new_version, modified_files)
114 self.modified.append(result)
115 return self
Alex Klein34afcbc2019-08-22 16:14:31 -0600116
117 @property
118 def uprevved(self):
Yaakov Shaul730814a2019-09-10 13:58:25 -0600119 return bool(self.modified)
Alex Klein34afcbc2019-08-22 16:14:31 -0600120
121
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600122def patch_ebuild_vars(ebuild_path, variables):
123 """Updates variables in ebuild.
124
125 Use this function rather than portage_util.EBuild.UpdateEBuild when you
126 want to preserve the variable position and quotes within the ebuild.
127
128 Args:
129 ebuild_path: The path of the ebuild.
130 variables: Dictionary of variables to update in ebuild.
131 """
132 try:
133 for line in fileinput.input(ebuild_path, inplace=1):
134 varname, eq, _ = line.partition('=')
135 if eq == '=' and varname.strip() in variables:
136 value = variables[varname]
137 sys.stdout.write('%s="%s"\n' % (varname, value))
138 else:
139 sys.stdout.write(line)
140 finally:
141 fileinput.close()
142
143
Alex Klein87531182019-08-12 15:23:37 -0600144def uprevs_versioned_package(package):
145 """Decorator to register package uprev handlers."""
146 assert package
147
148 def register(func):
149 """Registers |func| as a handler for |package|."""
150 _UPREV_FUNCS[package] = func
151
152 @functools.wraps(func)
153 def pass_through(*args, **kwargs):
154 return func(*args, **kwargs)
155
156 return pass_through
157
158 return register
159
160
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700161def uprev_android(tracking_branch,
162 android_package,
163 android_build_branch,
164 chroot,
165 build_targets=None,
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +0900166 android_version=None):
Alex Klein4de25e82019-08-05 15:58:39 -0600167 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700168 command = [
169 'cros_mark_android_as_stable',
170 '--tracking_branch=%s' % tracking_branch,
171 '--android_package=%s' % android_package,
172 '--android_build_branch=%s' % android_build_branch,
173 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600174 if build_targets:
175 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
176 if android_version:
177 command.append('--force_version=%s' % android_version)
Alex Klein4de25e82019-08-05 15:58:39 -0600178
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700179 result = cros_build_lib.run(
180 command,
181 stdout=True,
182 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500183 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700184 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600185
Mike Frysinger88d96362020-02-14 19:05:45 -0500186 portage_atom_string = result.stdout.strip()
187 android_atom = None
188 if portage_atom_string:
189 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600190 if not android_atom:
191 logging.info('Found nothing to rev.')
192 return None
193
194 for target in build_targets or []:
195 # Sanity check: We should always be able to merge the version of
196 # Android we just unmasked.
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700197 command = ['emerge-%s' % target.name, '-p', '--quiet', '=%s' % android_atom]
Alex Klein4de25e82019-08-05 15:58:39 -0600198 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700199 cros_build_lib.run(
200 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600201 except cros_build_lib.RunCommandError:
202 logging.error(
203 'Cannot emerge-%s =%s\nIs Android pinned to an older '
204 'version?', target, android_atom)
205 raise AndroidIsPinnedUprevError(android_atom)
206
207 return android_atom
208
209
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700210def uprev_build_targets(build_targets,
211 overlay_type,
212 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600213 output_dir=None):
214 """Uprev the set provided build targets, or all if not specified.
215
216 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600217 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600218 whose overlays should be uprevved, empty or None for all.
219 overlay_type (str): One of the valid overlay types except None (see
220 constants.VALID_OVERLAYS).
221 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
222 output_dir (str|None): The path to optionally dump result files.
223 """
224 # Need a valid overlay, but exclude None.
225 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
226
227 if build_targets:
228 overlays = portage_util.FindOverlaysForBoards(
229 overlay_type, boards=[t.name for t in build_targets])
230 else:
231 overlays = portage_util.FindOverlays(overlay_type)
232
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700233 return uprev_overlays(
234 overlays,
235 build_targets=build_targets,
236 chroot=chroot,
237 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600238
239
240def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
241 """Uprev the given overlays.
242
243 Args:
244 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600245 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600246 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
247 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
248 output_dir (str|None): The path to optionally dump result files.
249
250 Returns:
251 list[str] - The paths to all of the modified ebuild files. This includes the
252 new files that were added (i.e. the new versions) and all of the removed
253 files (i.e. the old versions).
254 """
255 assert overlays
256
257 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
258
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700259 uprev_manager = uprev_lib.UprevOverlayManager(
260 overlays,
261 manifest,
262 build_targets=build_targets,
263 chroot=chroot,
264 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600265 uprev_manager.uprev()
266
267 return uprev_manager.modified_ebuilds
268
269
Alex Klein87531182019-08-12 15:23:37 -0600270def uprev_versioned_package(package, build_targets, refs, chroot):
271 """Call registered uprev handler function for the package.
272
273 Args:
274 package (portage_util.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600275 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600276 clean on a successful uprev.
277 refs (list[uprev_lib.GitRef]):
278 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
279
280 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600281 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600282 """
283 assert package
284
285 if package.cp not in _UPREV_FUNCS:
286 raise UnknownPackageError(
287 'Package "%s" does not have a registered handler.' % package.cp)
288
Andrew Lambea9a8a22019-12-12 14:03:43 -0700289 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600290
291
Navil Perezf57ba872020-06-04 22:38:37 +0000292@uprevs_versioned_package('media-libs/virglrenderer')
293def uprev_virglrenderer(_build_targets, refs, _chroot):
294 """Updates virglrenderer ebuilds.
295
296 See: uprev_versioned_package.
297
298 Returns:
299 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
300 """
301 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
302 'virglrenderer')
303 manifest_path = os.path.join(constants.SOURCE_ROOT, repo_path, 'Manifest')
304 manifest = git.ManifestCheckout.Cached(manifest_path)
305 overlay = os.path.join(constants.SOURCE_ROOT,
306 constants.CHROMIUMOS_OVERLAY_DIR)
307
308 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
309 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
310 # blacklisted. Do not force uprevs after builder is stable and ebuilds are no
311 # longer blacklisted.
312 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
313
314 updated_files = uprev_manager.modified_ebuilds + [manifest_path]
315 result = UprevVersionedPackageResult()
316 result.add_result(refs[0].revision, updated_files)
317 return result
318
319
Yaakov Shaul395ae832019-09-09 14:45:32 -0600320@uprevs_versioned_package('afdo/kernel-profiles')
321def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600322 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600323
324 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600325
326 Raises:
327 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600328 """
329 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
330 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
331
David Burger92485342019-09-10 17:52:45 -0600332 with open(path, 'r') as f:
333 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600334
Yaakov Shaul730814a2019-09-10 13:58:25 -0600335 result = UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600336 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600337 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
338 'sys-kernel', version)
339 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
340 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600341 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
342 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600343 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600344 patch_ebuild_vars(ebuild_path,
345 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600346
347 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600348 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400349 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600350 except cros_build_lib.RunCommandError as e:
351 raise EbuildManifestError(
352 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600353 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600354
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600355 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600356
Yaakov Shaul730814a2019-09-10 13:58:25 -0600357 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
358
359 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600360
361
Trent Beginaf51f1b2020-03-09 17:35:31 -0600362@uprevs_versioned_package('chromeos-base/termina-image-amd64')
363def uprev_termina_amd64(_build_targets, _refs, chroot):
364 """Updates termina amd64 VM - chromeos-base/termina-image-amd64.
365
366 See: uprev_versioned_package.
367 """
368 return uprev_termina('termina-image-amd64', chroot)
369
370
371@uprevs_versioned_package('chromeos-base/termina-image-arm')
372def uprev_termina_arm(_build_targets, _refs, chroot):
373 """Updates termina arm VM - chromeos-base/termina-image-arm.
374
375 See: uprev_versioned_package.
376 """
377 return uprev_termina('termina-image-arm', chroot)
378
379
380def uprev_termina(package, chroot):
381 """Helper function to uprev termina VM.
382
383 Args:
384 package (string): name of the package
385 chroot (chroot_lib.Chroot): specify a chroot to enter.
386
387 Returns:
388 UprevVersionedPackageResult: The result.
389 """
390 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
391 package)
392 version_pin_path = os.path.join(package_path, 'VERSION-PIN')
393 return uprev_ebuild_from_pin(package_path, version_pin_path, chroot)
394
395
Trent Begin315d9d92019-12-03 21:55:53 -0700396@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600397def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700398 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
399
400 See: uprev_versioned_package.
401 """
402 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700403 package_path = os.path.join('src', 'private-overlays',
404 'project-wilco-private', 'chromeos-base', package)
405 version_pin_path = os.path.join(package_path, 'VERSION-PIN')
Trent Begin315d9d92019-12-03 21:55:53 -0700406
Trent Begin6daa8702020-01-29 14:58:12 -0700407 return uprev_ebuild_from_pin(package_path, version_pin_path, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700408
409
Trent Begin6daa8702020-01-29 14:58:12 -0700410def uprev_ebuild_from_pin(package_path, version_pin_path, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700411 """Changes the package ebuild's version to match the version pin file.
412
413 Args:
414 package_path: The path of the package relative to the src root. This path
415 should contain a single ebuild with the same name as the package.
Trent Begind943df92020-02-25 10:30:10 -0700416 version_pin_path: The path of the version_pin file that contains only a
417 version string. The ebuild's version will be directly set to this
Trent Begin315d9d92019-12-03 21:55:53 -0700418 number.
Trent Begin6daa8702020-01-29 14:58:12 -0700419 chroot (chroot_lib.Chroot): specify a chroot to enter.
Trent Begin315d9d92019-12-03 21:55:53 -0700420
421 Returns:
422 UprevVersionedPackageResult: The result.
423 """
424 package = os.path.basename(package_path)
Trent Begind943df92020-02-25 10:30:10 -0700425
426 package_src_path = os.path.join(constants.SOURCE_ROOT, package_path)
427 ebuild_paths = list(portage_util.EBuild.List(package_src_path))
Trent Begin315d9d92019-12-03 21:55:53 -0700428 if not ebuild_paths:
429 raise UprevError('No ebuilds found for %s' % package)
430 elif len(ebuild_paths) > 1:
431 raise UprevError('Multiple ebuilds found for %s' % package)
432 else:
433 ebuild_path = ebuild_paths[0]
434
Trent Begind943df92020-02-25 10:30:10 -0700435 version_pin_src_path = os.path.join(constants.SOURCE_ROOT, version_pin_path)
436 version = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700437 new_ebuild_path = os.path.join(package_path,
438 '%s-%s-r1.ebuild' % (package, version))
Trent Begind943df92020-02-25 10:30:10 -0700439 new_ebuild_src_path = os.path.join(constants.SOURCE_ROOT, new_ebuild_path)
440 os.rename(ebuild_path, new_ebuild_src_path)
Trent Begin4a11a632020-02-28 12:59:58 -0700441 manifest_src_path = os.path.join(package_src_path, 'Manifest')
Trent Begind943df92020-02-25 10:30:10 -0700442 new_ebuild_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
443 new_ebuild_path)
Trent Begin315d9d92019-12-03 21:55:53 -0700444
Trent Begin6daa8702020-01-29 14:58:12 -0700445 try:
Trent Begind943df92020-02-25 10:30:10 -0700446 portage_util.UpdateEbuildManifest(new_ebuild_chroot_path, chroot=chroot)
Trent Begin6daa8702020-01-29 14:58:12 -0700447 except cros_build_lib.RunCommandError as e:
Trent Begind943df92020-02-25 10:30:10 -0700448 raise EbuildManifestError(
Trent Begin6daa8702020-01-29 14:58:12 -0700449 'Unable to update manifest for %s: %s' % (package, e.stderr))
450
Trent Begin315d9d92019-12-03 21:55:53 -0700451 result = UprevVersionedPackageResult()
Trent Begin4a11a632020-02-28 12:59:58 -0700452 result.add_result(version,
453 [new_ebuild_src_path, ebuild_path, manifest_src_path])
Trent Begin315d9d92019-12-03 21:55:53 -0700454 return result
455
456
Alex Klein87531182019-08-12 15:23:37 -0600457@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700458def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600459 """Uprev chrome and its related packages.
460
461 See: uprev_versioned_package.
462 """
463 # Determine the version from the refs (tags), i.e. the chrome versions are the
464 # tag names.
465 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600466 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600467
468 uprev_manager = uprev_lib.UprevChromeManager(
469 chrome_version, build_targets=build_targets, chroot=chroot)
David Burger37f48672019-09-18 17:07:56 -0600470 result = UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600471 # Start with chrome itself, as we can't do anything else unless chrome
472 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600473 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
474 # attempt. The expected behavior is documented in the following table:
475 #
476 # Outcome of Chrome uprev attempt:
477 # NEWER_VERSION_EXISTS:
478 # Do nothing.
479 # SAME_VERSION_EXISTS or REVISION_BUMP:
480 # Uprev followers
481 # Assert not VERSION_BUMP (any other outcome is fine)
482 # VERSION_BUMP or NEW_EBUILD_CREATED:
483 # Uprev followers
484 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600485 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600486 return result
Alex Klein87531182019-08-12 15:23:37 -0600487
488 # With a successful chrome rev, also uprev related packages.
489 for package in constants.OTHER_CHROME_PACKAGES:
490 uprev_manager.uprev(package)
491
David Burger37f48672019-09-18 17:07:56 -0600492 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600493
494
Andrew Lamb9563a152019-12-04 11:42:18 -0700495def _generate_platform_c_files(replication_config, chroot):
496 """Generates platform C files from a platform JSON payload.
497
498 Args:
499 replication_config (replication_config_pb2.ReplicationConfig): A
500 ReplicationConfig that has already been run. If it produced a
501 build_config.json file, that file will be used to generate platform C
502 files. Otherwise, nothing will be generated.
503 chroot (chroot_lib.Chroot): The chroot to use to generate.
504
505 Returns:
506 A list of generated files.
507 """
508 # Generate the platform C files from the build config. Note that it would be
509 # more intuitive to generate the platform C files from the platform config;
510 # however, cros_config_schema does not allow this, because the platform config
511 # payload is not always valid input. For example, if a property is both
512 # 'required' and 'build-only', it will fail schema validation. Thus, use the
513 # build config, and use '-f' to filter.
514 build_config_path = [
515 rule.destination_path
516 for rule in replication_config.file_replication_rules
517 if rule.destination_path.endswith('build_config.json')
518 ]
519
520 if not build_config_path:
521 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700522 'No build_config.json found, will not generate platform C files. '
523 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700524 return []
525
526 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700527 raise ValueError('Expected at most one build_config.json destination path. '
528 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700529
530 build_config_path = build_config_path[0]
531
532 # Paths to the build_config.json and dir to output C files to, in the
533 # chroot.
534 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
535 build_config_path)
536 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
537 os.path.dirname(build_config_path))
538
539 command = [
540 'cros_config_schema', '-m', build_config_chroot_path, '-g',
541 generated_output_chroot_dir, '-f', '"TRUE"'
542 ]
543
544 cros_build_lib.run(
545 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
546
547 # A relative (to the source root) path to the generated C files.
548 generated_output_dir = os.path.dirname(build_config_path)
549 generated_files = []
550 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
551 for f in expected_c_files:
552 if os.path.exists(
553 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
554 generated_files.append(os.path.join(generated_output_dir, f))
555
556 if len(expected_c_files) != len(generated_files):
557 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
558
559 return generated_files
560
561
Andrew Lambe836f222019-12-09 12:27:38 -0700562def _get_private_overlay_package_root(ref, package):
563 """Returns the absolute path to the root of a given private overlay.
564
565 Args:
566 ref (uprev_lib.GitRef): GitRef for the private overlay.
567 package (str): Path to the package in the overlay.
568 """
569 # There might be a cleaner way to map from package -> path within the source
570 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700571 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700572 match = re.match(private_overlay_ref_pattern, ref.path)
573 if not match:
574 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
575 (private_overlay_ref_pattern, ref))
576
577 overlay = match.group(1)
578
579 return os.path.join(constants.SOURCE_ROOT,
580 'src/private-overlays/overlay-%s-private' % overlay,
581 package)
582
583
Andrew Lambea9a8a22019-12-12 14:03:43 -0700584@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
585def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700586 """Replicate a private cros_config change to the corresponding public config.
587
Alex Kleinad6b48a2020-01-08 16:57:41 -0700588 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700589 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700590 package = 'chromeos-base/chromeos-config-bsp'
591
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700592 if len(refs) != 1:
593 raise ValueError('Expected exactly one ref, actual %s' % refs)
594
595 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700596 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700597 replication_config_path = os.path.join(package_root,
598 'replication_config.jsonpb')
599
600 try:
601 replication_config = json_format.Parse(
602 osutils.ReadFile(replication_config_path),
603 replication_config_pb2.ReplicationConfig())
604 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700605 raise ValueError(
606 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700607
608 replication_lib.Replicate(replication_config)
609
610 modified_files = [
611 rule.destination_path
612 for rule in replication_config.file_replication_rules
613 ]
614
Andrew Lamb9563a152019-12-04 11:42:18 -0700615 # The generated platform C files are not easily filtered by replication rules,
616 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
617 # files cannot. Therefore, replicate and filter the JSON payloads, and then
618 # generate filtered C files from the JSON payload.
619 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700620
621 # Use the private repo's commit hash as the new version.
622 new_private_version = refs[0].revision
623
Andrew Lamb988f4da2019-12-10 10:16:43 -0700624 # modified_files should contain only relative paths at this point, but the
625 # returned UprevVersionedPackageResult must contain only absolute paths.
626 for i, modified_file in enumerate(modified_files):
627 assert not os.path.isabs(modified_file)
628 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
629
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700630 return UprevVersionedPackageResult().add_result(new_private_version,
631 modified_files)
632
633
Alex Kleinbbef2b32019-08-27 10:38:50 -0600634def get_best_visible(atom, build_target=None):
635 """Returns the best visible CPV for the given atom.
636
637 Args:
638 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600639 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600640 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700641
642 Returns:
643 portage_util.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600644 """
David Burger1e0fe232019-07-01 14:52:07 -0600645 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600646
647 board = build_target.name if build_target else None
648 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600649
650
Alex Klein149fd3b2019-12-16 16:01:05 -0700651def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600652 """Check if a prebuilt exists.
653
654 Args:
655 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600656 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600657 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700658 useflags: Any additional USE flags that should be set. May be a string
659 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700660
661 Returns:
662 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600663 """
664 assert atom
665
666 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700667 extra_env = None
668 if useflags:
669 new_flags = useflags
670 if not isinstance(useflags, six.string_types):
671 new_flags = ' '.join(useflags)
672
673 existing = os.environ.get('USE', '')
674 final_flags = '%s %s' % (existing, new_flags)
675 extra_env = {'USE': final_flags.strip()}
676 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600677
678
David Burger0f9dd4e2019-10-08 12:33:42 -0600679def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600680 """Check if |build_target| builds |atom| (has it in its depgraph)."""
681 cros_build_lib.AssertInsideChroot()
682
LaMont Jones4cbecba2020-05-12 11:54:27 -0600683 # TODO(crbug/1081828): Receive and use sysroot.
684 graph, _sdk_graph = dependency.GetBuildDependency(
685 build_target.root, build_target.name, packages)
Alex Klein36b117f2019-09-30 15:13:46 -0600686 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600687
688
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600689def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600690 """Returns the current Chrome version for the board (or in buildroot).
691
692 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600693 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700694
695 Returns:
696 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600697 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600698 # TODO(crbug/1019770): Long term we should not need the try/catch here once
699 # the builds function above only returns True for chrome when
700 # determine_chrome_version will succeed.
701 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700702 cpv = portage_util.PortageqBestVisible(
703 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600704 except cros_build_lib.RunCommandError as e:
705 # Return None because portage failed when trying to determine the chrome
706 # version.
707 logging.warning('Caught exception in determine_chrome_package: %s', e)
708 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600709 # Something like 78.0.3877.4_rc -> 78.0.3877.4
710 return cpv.version_no_rev.partition('_')[0]
711
712
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600713def determine_android_package(board):
714 """Returns the active Android container package in use by the board.
715
716 Args:
717 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700718
719 Returns:
720 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600721 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600722 try:
723 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600724 except cros_build_lib.RunCommandError as e:
725 # Return None because a command (likely portage) failed when trying to
726 # determine the package.
727 logging.warning('Caught exception in determine_android_package: %s', e)
728 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600729
Alex Kleinad6b48a2020-01-08 16:57:41 -0700730 # We assume there is only one Android package in the depgraph.
731 for package in packages:
732 if package.startswith('chromeos-base/android-container-') or \
733 package.startswith('chromeos-base/android-vm-'):
734 return package
735 return None
736
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600737
738def determine_android_version(boards=None):
739 """Determine the current Android version in buildroot now and return it.
740
741 This uses the typical portage logic to determine which version of Android
742 is active right now in the buildroot.
743
744 Args:
745 boards: List of boards to check version of.
746
747 Returns:
748 The Android build ID of the container for the boards.
749
750 Raises:
751 NoAndroidVersionError: if no unique Android version can be determined.
752 """
753 if not boards:
754 return None
755 # Verify that all boards have the same version.
756 version = None
757 for board in boards:
758 package = determine_android_package(board)
759 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600760 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600761 cpv = portage_util.SplitCPV(package)
762 if not cpv:
763 raise NoAndroidVersionError(
764 'Android version could not be determined for %s' % board)
765 if not version:
766 version = cpv.version_no_rev
767 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700768 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
769 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600770 return version
771
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700772
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600773def determine_android_branch(board):
774 """Returns the Android branch in use by the active container ebuild."""
775 try:
776 android_package = determine_android_package(board)
777 except cros_build_lib.RunCommandError:
778 raise NoAndroidBranchError(
779 'Android branch could not be determined for %s' % board)
780 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600781 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600782 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
783 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900784 # have at least one of the following targets.
Shao-Chuan Leeac919632020-05-28 13:14:37 +0900785 # TODO(crbug.com/1087167): Ensure this condition in PFQ to avoid CQ breakage.
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900786 targets = ['ARM_TARGET', 'ARM_USERDEBUG_TARGET', 'X86_USERDEBUG_TARGET',
787 'ARM64_TARGET', 'ARM64_USERDEBUG_TARGET', 'X86_64_TARGET',
788 'X86_64_USERDEBUG_TARGET']
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600789 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
790 for target in targets:
791 if target in ebuild_content:
792 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
793 if branch is not None:
794 return branch.group(1)
795 raise NoAndroidBranchError(
796 'Android branch could not be determined for %s (ebuild empty?)' % board)
797
798
799def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600800 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600801 try:
802 android_package = determine_android_package(board)
803 except cros_build_lib.RunCommandError:
804 raise NoAndroidTargetError(
805 'Android Target could not be determined for %s' % board)
806 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600807 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600808 if android_package.startswith('chromeos-base/android-vm-'):
809 return 'bertha'
810 elif android_package.startswith('chromeos-base/android-container-'):
811 return 'cheets'
812
813 raise NoAndroidTargetError(
814 'Android Target cannot be determined for the package: %s' %
815 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600816
817
818def determine_platform_version():
819 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600820 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600821 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
822 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600823
824
825def determine_milestone_version():
826 """Returns the platform version from the source root."""
827 # Milestone version is something like '79'.
828 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
829 return version.chrome_branch
830
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700831
Michael Mortensen009cb662019-10-21 11:38:43 -0600832def determine_full_version():
833 """Returns the full version from the source root."""
834 # Full version is something like 'R79-12575.0.0'.
835 milestone_version = determine_milestone_version()
836 platform_version = determine_platform_version()
837 full_version = ('R%s-%s' % (milestone_version, platform_version))
838 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600839
840
Michael Mortensende716a12020-05-15 11:27:00 -0600841def find_fingerprints(build_target):
842 """Returns a list of fingerprints for this build.
843
844 Args:
845 build_target (build_target_lib.BuildTarget): The build target.
846
847 Returns:
848 list[str] - List of fingerprint strings.
849 """
850 cros_build_lib.AssertInsideChroot()
851 fp_file = 'cheets-fingerprint.txt'
852 fp_path = os.path.join(
853 image_lib.GetLatestImageLink(build_target.name),
854 fp_file)
855 if not os.path.isfile(fp_path):
856 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600857 return []
Michael Mortensende716a12020-05-15 11:27:00 -0600858 logging.info('Reading fingerprint file: %s', fp_path)
859 fingerprints = osutils.ReadFile(fp_path).splitlines()
860 return fingerprints
861
862
Michael Mortensen59e30872020-05-18 14:12:49 -0600863def get_all_firmware_versions(build_target):
864 """Extract firmware version for all models present.
865
866 Args:
867 build_target (build_target_lib.BuildTarget): The build target.
868
869 Returns:
870 A dict of FirmwareVersions namedtuple instances by model.
871 Each element will be populated based on whether it was present in the
872 command output.
873 """
874 cros_build_lib.AssertInsideChroot()
875 result = {}
876 # Note that example output for _get_firmware_version_cmd_result is available
877 # in the packages_unittest.py for testing get_all_firmware_versions.
878 cmd_result = _get_firmware_version_cmd_result(build_target)
879
880 # There is a blank line between the version info for each model.
881 firmware_version_payloads = cmd_result.split('\n\n')
882 for firmware_version_payload in firmware_version_payloads:
883 if 'BIOS' in firmware_version_payload:
884 firmware_version = _find_firmware_versions(firmware_version_payload)
885 result[firmware_version.model] = firmware_version
886 return result
887
888
Michael Mortensen71ef5682020-05-07 14:29:24 -0600889FirmwareVersions = collections.namedtuple(
890 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
891
892
893def get_firmware_versions(build_target):
894 """Extract version information from the firmware updater, if one exists.
895
896 Args:
897 build_target (build_target_lib.BuildTarget): The build target.
898
899 Returns:
900 A FirmwareVersions namedtuple instance.
901 Each element will either be set to the string output by the firmware
902 updater shellball, or None if there is no firmware updater.
903 """
904 cros_build_lib.AssertInsideChroot()
905 cmd_result = _get_firmware_version_cmd_result(build_target)
906 if cmd_result:
907 return _find_firmware_versions(cmd_result)
908 else:
909 return FirmwareVersions(None, None, None, None, None)
910
911
912def _get_firmware_version_cmd_result(build_target):
913 """Gets the raw result output of the firmware updater version command.
914
915 Args:
916 build_target (build_target_lib.BuildTarget): The build target.
917
918 Returns:
919 Command execution result.
920 """
921 updater = os.path.join(build_target.root,
922 'usr/sbin/chromeos-firmwareupdate')
923 logging.info('Calling updater %s', updater)
924 # Call the updater using the chroot-based path.
925 return cros_build_lib.run([updater, '-V'],
926 capture_output=True, log_output=True,
927 encoding='utf-8').stdout
928
929
930def _find_firmware_versions(cmd_output):
931 """Finds firmware version output via regex matches against the cmd_output.
932
933 Args:
934 cmd_output: The raw output to search against.
935
936 Returns:
937 FirmwareVersions namedtuple with results.
938 Each element will either be set to the string output by the firmware
939 updater shellball, or None if there is no match.
940 """
941
942 # Sometimes a firmware bundle includes a special combination of RO+RW
943 # firmware. In this case, the RW firmware version is indicated with a "(RW)
944 # version" field. In other cases, the "(RW) version" field is not present.
945 # Therefore, search for the "(RW)" fields first and if they aren't present,
946 # fallback to the other format. e.g. just "BIOS version:".
947 # TODO(mmortensen): Use JSON once the firmware updater supports it.
948 main = None
949 main_rw = None
950 ec = None
951 ec_rw = None
952 model = None
953
954 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
955 if match:
956 main = match.group('version')
957
958 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
959 if match:
960 main_rw = match.group('version')
961
962 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
963 if match:
964 ec = match.group('version')
965
966 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
967 if match:
968 ec_rw = match.group('version')
969
970 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
971 if match:
972 model = match.group('model')
973
974 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -0600975
976
977MainEcFirmwareVersions = collections.namedtuple(
978 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
979
980def determine_firmware_versions(build_target):
981 """Returns a namedtuple with main and ec firmware versions.
982
983 Args:
984 build_target (build_target_lib.BuildTarget): The build target.
985
986 Returns:
987 MainEcFirmwareVersions namedtuple with results.
988 """
989 fw_versions = get_firmware_versions(build_target)
990 main_fw_version = fw_versions.main_rw or fw_versions.main
991 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
992
993 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -0600994
995def determine_kernel_version(build_target):
996 """Returns a string containing the kernel version for this build target.
997
998 Args:
999 build_target (build_target_lib.BuildTarget): The build target.
1000
1001 Returns:
1002 (str) The kernel versions, or None.
1003 """
1004 try:
1005 packages = portage_util.GetPackageDependencies(build_target.name,
1006 'virtual/linux-sources')
1007 except cros_build_lib.RunCommandError as e:
1008 logging.warning('Unable to get package list for metadata: %s', e)
1009 return None
1010 for package in packages:
1011 if package.startswith('sys-kernel/chromeos-kernel-'):
1012 kernel_version = portage_util.SplitCPV(package).version
1013 logging.info('Found active kernel version: %s', kernel_version)
1014 return kernel_version
1015 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001016
1017
1018def get_models(build_target, log_output=True):
1019 """Obtain a list of models supported by a unified board.
1020
1021 This ignored whitelabel models since GoldenEye has no specific support for
1022 these at present.
1023
1024 Args:
1025 build_target (build_target_lib.BuildTarget): The build target.
1026 log_output: Whether to log the output of the cros_config_host invocation.
1027
1028 Returns:
1029 A list of models supported by this board, if it is a unified build; None,
1030 if it is not a unified build.
1031 """
1032 return _run_cros_config_host(build_target, ['list-models'],
1033 log_output=log_output)
1034
1035
Michael Mortensen359c1f32020-05-28 19:35:42 -06001036def get_key_id(build_target, model):
1037 """Obtain the key_id for a model within the build_target.
1038
1039 Args:
1040 build_target (build_target_lib.BuildTarget): The build target.
1041 model (str): The model name
1042
1043 Returns:
1044 A key_id (str) or None.
1045 """
1046 model_arg = '--model=' + model
1047 key_id_list = _run_cros_config_host(
1048 build_target,
1049 [model_arg, 'get', '/firmware-signing', 'key-id'])
1050 key_id = None
1051 if len(key_id_list) == 1:
1052 key_id = key_id_list[0]
1053 return key_id
1054
1055
Michael Mortensen125bb012020-05-21 14:02:10 -06001056def _run_cros_config_host(build_target, args, log_output=True):
1057 """Run the cros_config_host tool.
1058
1059 Args:
1060 build_target (build_target_lib.BuildTarget): The build target.
1061 args: List of arguments to pass.
1062 log_output: Whether to log the output of the cros_config_host.
1063
1064 Returns:
1065 Output of the tool
1066 """
1067 cros_build_lib.AssertInsideChroot()
1068 tool = '/usr/bin/cros_config_host'
1069 if not os.path.isfile(tool):
1070 return None
1071
1072 config_fname = build_target.full_path(
1073 'usr/share/chromeos-config/yaml/config.yaml')
1074
1075 result = cros_build_lib.run(
1076 [tool, '-c', config_fname] + args,
1077 capture_output=True,
1078 encoding='utf-8',
1079 log_output=log_output,
1080 check=False)
1081 if result.returncode:
1082 # Show the output for debugging purposes.
1083 if 'No such file or directory' not in result.error:
1084 logging.error('cros_config_host failed: %s\n', result.error)
1085 return None
1086 return result.output.strip().splitlines()