blob: e18e1e05c0d390b64e04a2431227577c9f60f560 [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Package utility functionality."""
7
8from __future__ import print_function
9
Yaakov Shaul730814a2019-09-10 13:58:25 -060010import collections
Ben Reiche779cf42020-12-15 03:21:31 +000011from distutils.version import LooseVersion
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060012import fileinput
Alex Klein87531182019-08-12 15:23:37 -060013import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060014import json
Evan Hernandezb51f1522019-08-15 11:29:40 -060015import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060016import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060017import sys
Alex Klein6becabc2020-09-11 14:03:05 -060018from typing import List, Optional
Alex Klein87531182019-08-12 15:23:37 -060019
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060021
Andrew Lamb2bde9e42019-11-04 13:24:09 -070022from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060023from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060025from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060026from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import git
Michael Mortensende716a12020-05-15 11:27:00 -060028from chromite.lib import image_lib
Michael Mortensenb70e8a82019-10-10 18:43:41 -060029from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060030from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070031from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060032from chromite.lib import uprev_lib
Alex Klein18a60af2020-06-11 12:08:47 -060033from chromite.lib.parser import package_info
Alex Kleineb77ffa2019-05-28 14:47:44 -060034
Alex Klein36b117f2019-09-30 15:13:46 -060035if cros_build_lib.IsInsideChroot():
Alex Klein6becabc2020-09-11 14:03:05 -060036 from chromite.lib import depgraph
Alex Klein36b117f2019-09-30 15:13:46 -060037 from chromite.service import dependency
38
Alex Klein87531182019-08-12 15:23:37 -060039# Registered handlers for uprevving versioned packages.
40_UPREV_FUNCS = {}
41
Alex Kleineb77ffa2019-05-28 14:47:44 -060042
43class Error(Exception):
44 """Module's base error class."""
45
46
Alex Klein4de25e82019-08-05 15:58:39 -060047class UnknownPackageError(Error):
48 """Uprev attempted for a package without a registered handler."""
49
50
Alex Kleineb77ffa2019-05-28 14:47:44 -060051class UprevError(Error):
52 """An error occurred while uprevving packages."""
53
54
Michael Mortensenb70e8a82019-10-10 18:43:41 -060055class NoAndroidVersionError(Error):
56 """An error occurred while trying to determine the android version."""
57
58
59class NoAndroidBranchError(Error):
60 """An error occurred while trying to determine the android branch."""
61
62
63class NoAndroidTargetError(Error):
64 """An error occurred while trying to determine the android target."""
65
66
Alex Klein4de25e82019-08-05 15:58:39 -060067class AndroidIsPinnedUprevError(UprevError):
68 """Raised when we try to uprev while Android is pinned."""
69
70 def __init__(self, new_android_atom):
71 """Initialize a AndroidIsPinnedUprevError.
72
73 Args:
74 new_android_atom: The Android atom that we failed to
75 uprev to, due to Android being pinned.
76 """
77 assert new_android_atom
78 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
79 new_android_atom)
80 super(AndroidIsPinnedUprevError, self).__init__(msg)
81 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060082
83
Andrew Lamb9563a152019-12-04 11:42:18 -070084class GeneratedCrosConfigFilesError(Error):
85 """Error when cros_config_schema does not produce expected files"""
86
87 def __init__(self, expected_files, found_files):
88 msg = ('Expected to find generated C files: %s. Actually found: %s' %
89 (expected_files, found_files))
90 super(GeneratedCrosConfigFilesError, self).__init__(msg)
91
Alex Klein7a3a7dd2020-01-08 16:44:38 -070092
Alex Klein6becabc2020-09-11 14:03:05 -060093NeedsChromeSourceResult = collections.namedtuple('NeedsChromeSourceResult', (
94 'needs_chrome_source',
95 'builds_chrome',
96 'packages',
97 'missing_chrome_prebuilt',
98 'missing_follower_prebuilt',
99))
100
101
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600102def patch_ebuild_vars(ebuild_path, variables):
103 """Updates variables in ebuild.
104
105 Use this function rather than portage_util.EBuild.UpdateEBuild when you
106 want to preserve the variable position and quotes within the ebuild.
107
108 Args:
109 ebuild_path: The path of the ebuild.
110 variables: Dictionary of variables to update in ebuild.
111 """
112 try:
113 for line in fileinput.input(ebuild_path, inplace=1):
114 varname, eq, _ = line.partition('=')
115 if eq == '=' and varname.strip() in variables:
116 value = variables[varname]
117 sys.stdout.write('%s="%s"\n' % (varname, value))
118 else:
119 sys.stdout.write(line)
120 finally:
121 fileinput.close()
122
123
Alex Klein87531182019-08-12 15:23:37 -0600124def uprevs_versioned_package(package):
125 """Decorator to register package uprev handlers."""
126 assert package
127
128 def register(func):
129 """Registers |func| as a handler for |package|."""
130 _UPREV_FUNCS[package] = func
131
132 @functools.wraps(func)
133 def pass_through(*args, **kwargs):
134 return func(*args, **kwargs)
135
136 return pass_through
137
138 return register
139
140
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700141def uprev_android(tracking_branch,
142 android_package,
143 android_build_branch,
144 chroot,
145 build_targets=None,
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +0900146 android_version=None):
Alex Klein4de25e82019-08-05 15:58:39 -0600147 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700148 command = [
149 'cros_mark_android_as_stable',
150 '--tracking_branch=%s' % tracking_branch,
151 '--android_package=%s' % android_package,
152 '--android_build_branch=%s' % android_build_branch,
153 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600154 if build_targets:
155 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
156 if android_version:
157 command.append('--force_version=%s' % android_version)
Alex Klein4de25e82019-08-05 15:58:39 -0600158
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700159 result = cros_build_lib.run(
160 command,
161 stdout=True,
162 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500163 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700164 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600165
Mike Frysinger88d96362020-02-14 19:05:45 -0500166 portage_atom_string = result.stdout.strip()
167 android_atom = None
168 if portage_atom_string:
169 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600170 if not android_atom:
171 logging.info('Found nothing to rev.')
172 return None
173
174 for target in build_targets or []:
175 # Sanity check: We should always be able to merge the version of
176 # Android we just unmasked.
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700177 command = ['emerge-%s' % target.name, '-p', '--quiet', '=%s' % android_atom]
Alex Klein4de25e82019-08-05 15:58:39 -0600178 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700179 cros_build_lib.run(
180 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600181 except cros_build_lib.RunCommandError:
182 logging.error(
183 'Cannot emerge-%s =%s\nIs Android pinned to an older '
184 'version?', target, android_atom)
185 raise AndroidIsPinnedUprevError(android_atom)
186
187 return android_atom
188
189
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700190def uprev_build_targets(build_targets,
191 overlay_type,
192 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600193 output_dir=None):
194 """Uprev the set provided build targets, or all if not specified.
195
196 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600197 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600198 whose overlays should be uprevved, empty or None for all.
199 overlay_type (str): One of the valid overlay types except None (see
200 constants.VALID_OVERLAYS).
201 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
202 output_dir (str|None): The path to optionally dump result files.
203 """
204 # Need a valid overlay, but exclude None.
205 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
206
207 if build_targets:
208 overlays = portage_util.FindOverlaysForBoards(
209 overlay_type, boards=[t.name for t in build_targets])
210 else:
211 overlays = portage_util.FindOverlays(overlay_type)
212
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700213 return uprev_overlays(
214 overlays,
215 build_targets=build_targets,
216 chroot=chroot,
217 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600218
219
220def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
221 """Uprev the given overlays.
222
223 Args:
224 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600225 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600226 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
227 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
228 output_dir (str|None): The path to optionally dump result files.
229
230 Returns:
231 list[str] - The paths to all of the modified ebuild files. This includes the
232 new files that were added (i.e. the new versions) and all of the removed
233 files (i.e. the old versions).
234 """
235 assert overlays
236
237 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
238
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700239 uprev_manager = uprev_lib.UprevOverlayManager(
240 overlays,
241 manifest,
242 build_targets=build_targets,
243 chroot=chroot,
244 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600245 uprev_manager.uprev()
246
247 return uprev_manager.modified_ebuilds
248
249
Alex Klein87531182019-08-12 15:23:37 -0600250def uprev_versioned_package(package, build_targets, refs, chroot):
251 """Call registered uprev handler function for the package.
252
253 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600254 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600255 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600256 clean on a successful uprev.
257 refs (list[uprev_lib.GitRef]):
258 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
259
260 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600261 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600262 """
263 assert package
264
265 if package.cp not in _UPREV_FUNCS:
266 raise UnknownPackageError(
267 'Package "%s" does not have a registered handler.' % package.cp)
268
Andrew Lambea9a8a22019-12-12 14:03:43 -0700269 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600270
271
Navil Perezf57ba872020-06-04 22:38:37 +0000272@uprevs_versioned_package('media-libs/virglrenderer')
273def uprev_virglrenderer(_build_targets, refs, _chroot):
274 """Updates virglrenderer ebuilds.
275
276 See: uprev_versioned_package.
277
278 Returns:
279 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
280 """
Navil Perezf57ba872020-06-04 22:38:37 +0000281 overlay = os.path.join(constants.SOURCE_ROOT,
282 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600283 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
284 'virglrenderer')
285 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000286
287 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
288 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000289 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
290 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000291 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
292
George Engelbrechte73f2782020-06-10 14:10:46 -0600293 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600294 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000295 result.add_result(refs[0].revision, updated_files)
296 return result
297
Jose Magana03b5a842020-08-19 12:52:59 +1000298@uprevs_versioned_package('chromeos-base/drivefs')
299def uprev_drivefs(_build_targets, refs, chroot):
300 """Updates drivefs ebuilds.
301
302 See: uprev_versioned_package.
303
304 Returns:
305 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
306 """
307
Ben Reiche779cf42020-12-15 03:21:31 +0000308 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000309 result = uprev_lib.UprevVersionedPackageResult()
310 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000311
Ben Reiche779cf42020-12-15 03:21:31 +0000312 drivefs_version = get_latest_drivefs_version_from_refs(refs)
313 if not drivefs_version:
314 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000315 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000316
Ben Reiche779cf42020-12-15 03:21:31 +0000317 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000318
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000319 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000320 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000321 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000322 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000323 chroot)
Jose Magana03b5a842020-08-19 12:52:59 +1000324
325 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000326 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000327 all_changed_files.extend(uprev_result.changed_files)
328
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000329 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000330 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000331 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000332 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000333 chroot)
334
335 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000336 logging.warning(
337 'drivefs package has changed files %s but drivefs-ipc does not',
338 all_changed_files)
339 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000340
341 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000342 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000343
344 return result
345
Navil Perezf57ba872020-06-04 22:38:37 +0000346
Yaakov Shaul395ae832019-09-09 14:45:32 -0600347@uprevs_versioned_package('afdo/kernel-profiles')
348def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600349 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600350
351 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600352
353 Raises:
354 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600355 """
356 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
357 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
358
David Burger92485342019-09-10 17:52:45 -0600359 with open(path, 'r') as f:
360 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600361
Chris McDonald38409112020-09-24 11:24:51 -0600362 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600363 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600364 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
365 'sys-kernel', version)
366 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
367 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600368 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
369 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600370 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600371 patch_ebuild_vars(ebuild_path,
372 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600373
374 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600375 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400376 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600377 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600378 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600379 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600380 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600381
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600382 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600383
Yaakov Shaul730814a2019-09-10 13:58:25 -0600384 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
385
386 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600387
388
Trent Begineb624182020-07-14 10:09:45 -0600389@uprevs_versioned_package('chromeos-base/termina-dlc')
390def uprev_termina_dlc(_build_targets, _refs, chroot):
391 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600392
393 See: uprev_versioned_package.
394 """
Trent Begineb624182020-07-14 10:09:45 -0600395 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600396 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
397 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000398
399 version_pin_src_path = _get_version_pin_src_path(package_path)
400 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
401
Chris McDonald38409112020-09-24 11:24:51 -0600402 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000403
404
405@uprevs_versioned_package('app-emulation/parallels-desktop')
406def uprev_parallels_desktop(_build_targets, _refs, chroot):
407 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
408
409 See: uprev_versioned_package
410
411 Returns:
412 UprevVersionedPackageResult: The result.
413 """
414 package = 'parallels-desktop'
415 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
416 'app-emulation', package)
417 version_pin_src_path = _get_version_pin_src_path(package_path)
418
419 # Expect a JSON blob like the following:
420 # {
421 # "version": "1.2.3",
422 # "test_image": { "url": "...", "size": 12345678,
423 # "sha256sum": "<32 bytes of hexadecimal>" }
424 # }
425 with open(version_pin_src_path, 'r') as f:
426 pinned = json.load(f)
427
428 if 'version' not in pinned or 'test_image' not in pinned:
429 raise UprevError('VERSION-PIN for %s missing version and/or '
430 'test_image field' % package)
431
432 version = pinned['version']
433 if not isinstance(version, str):
434 raise UprevError('version in VERSION-PIN for %s not a string' % package)
435
436 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600437 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000438
439 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100440 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
441 'local/bundles/crosint/pita/data/'
442 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000443 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
444 with open(test_image_src_path, 'w') as f:
445 json.dump(pinned['test_image'], f, indent=2)
446 result.add_result(version, [test_image_src_path])
447
448 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600449
450
Trent Begin315d9d92019-12-03 21:55:53 -0700451@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600452def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700453 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
454
455 See: uprev_versioned_package.
456 """
457 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700458 package_path = os.path.join('src', 'private-overlays',
459 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000460 version_pin_src_path = _get_version_pin_src_path(package_path)
461 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700462
Chris McDonald38409112020-09-24 11:24:51 -0600463 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700464
465
Patrick Meiring5897add2020-09-16 16:30:17 +1000466def _get_version_pin_src_path(package_path):
467 """Returns the path to the VERSION-PIN file for the given package."""
468 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
469
470
Alex Klein87531182019-08-12 15:23:37 -0600471@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700472def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600473 """Uprev chrome and its related packages.
474
475 See: uprev_versioned_package.
476 """
477 # Determine the version from the refs (tags), i.e. the chrome versions are the
478 # tag names.
479 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600480 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600481
482 uprev_manager = uprev_lib.UprevChromeManager(
483 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600484 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600485 # Start with chrome itself, as we can't do anything else unless chrome
486 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600487 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
488 # attempt. The expected behavior is documented in the following table:
489 #
490 # Outcome of Chrome uprev attempt:
491 # NEWER_VERSION_EXISTS:
492 # Do nothing.
493 # SAME_VERSION_EXISTS or REVISION_BUMP:
494 # Uprev followers
495 # Assert not VERSION_BUMP (any other outcome is fine)
496 # VERSION_BUMP or NEW_EBUILD_CREATED:
497 # Uprev followers
498 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600499 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600500 return result
Alex Klein87531182019-08-12 15:23:37 -0600501
502 # With a successful chrome rev, also uprev related packages.
503 for package in constants.OTHER_CHROME_PACKAGES:
504 uprev_manager.uprev(package)
505
David Burger37f48672019-09-18 17:07:56 -0600506 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600507
508
Ben Reiche779cf42020-12-15 03:21:31 +0000509def get_latest_drivefs_version_from_refs(refs: List[uprev_lib.GitRef]) -> str:
510 """Get the latest DriveFS version from refs
511
512 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
513 Versions are compared using |distutils.version.LooseVersion| and
514 the latest version is returned.
515
516 Args:
517 refs: The tags to parse for the latest DriveFS version.
518
519 Returns:
520 The latest DriveFS version to use.
521 """
522 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
523
524 valid_refs = []
525 for gitiles in refs:
526 if gitiles.ref.startswith(DRIVEFS_REFS_PREFIX):
527 valid_refs.append(gitiles.ref)
528
529 if not valid_refs:
530 return None
531
532 # Sort by version and take the latest version.
533 target_version_ref = sorted(valid_refs,
534 key=LooseVersion,
535 reverse=True)[0]
536 return target_version_ref.replace(DRIVEFS_REFS_PREFIX, '')
537
538
Andrew Lamb9563a152019-12-04 11:42:18 -0700539def _generate_platform_c_files(replication_config, chroot):
540 """Generates platform C files from a platform JSON payload.
541
542 Args:
543 replication_config (replication_config_pb2.ReplicationConfig): A
544 ReplicationConfig that has already been run. If it produced a
545 build_config.json file, that file will be used to generate platform C
546 files. Otherwise, nothing will be generated.
547 chroot (chroot_lib.Chroot): The chroot to use to generate.
548
549 Returns:
550 A list of generated files.
551 """
552 # Generate the platform C files from the build config. Note that it would be
553 # more intuitive to generate the platform C files from the platform config;
554 # however, cros_config_schema does not allow this, because the platform config
555 # payload is not always valid input. For example, if a property is both
556 # 'required' and 'build-only', it will fail schema validation. Thus, use the
557 # build config, and use '-f' to filter.
558 build_config_path = [
559 rule.destination_path
560 for rule in replication_config.file_replication_rules
561 if rule.destination_path.endswith('build_config.json')
562 ]
563
564 if not build_config_path:
565 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700566 'No build_config.json found, will not generate platform C files. '
567 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700568 return []
569
570 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700571 raise ValueError('Expected at most one build_config.json destination path. '
572 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700573
574 build_config_path = build_config_path[0]
575
576 # Paths to the build_config.json and dir to output C files to, in the
577 # chroot.
578 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
579 build_config_path)
580 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
581 os.path.dirname(build_config_path))
582
583 command = [
584 'cros_config_schema', '-m', build_config_chroot_path, '-g',
585 generated_output_chroot_dir, '-f', '"TRUE"'
586 ]
587
588 cros_build_lib.run(
589 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
590
591 # A relative (to the source root) path to the generated C files.
592 generated_output_dir = os.path.dirname(build_config_path)
593 generated_files = []
594 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
595 for f in expected_c_files:
596 if os.path.exists(
597 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
598 generated_files.append(os.path.join(generated_output_dir, f))
599
600 if len(expected_c_files) != len(generated_files):
601 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
602
603 return generated_files
604
605
Andrew Lambe836f222019-12-09 12:27:38 -0700606def _get_private_overlay_package_root(ref, package):
607 """Returns the absolute path to the root of a given private overlay.
608
609 Args:
610 ref (uprev_lib.GitRef): GitRef for the private overlay.
611 package (str): Path to the package in the overlay.
612 """
613 # There might be a cleaner way to map from package -> path within the source
614 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700615 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700616 match = re.match(private_overlay_ref_pattern, ref.path)
617 if not match:
618 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
619 (private_overlay_ref_pattern, ref))
620
621 overlay = match.group(1)
622
623 return os.path.join(constants.SOURCE_ROOT,
624 'src/private-overlays/overlay-%s-private' % overlay,
625 package)
626
627
Andrew Lambea9a8a22019-12-12 14:03:43 -0700628@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
629def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700630 """Replicate a private cros_config change to the corresponding public config.
631
Alex Kleinad6b48a2020-01-08 16:57:41 -0700632 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700633 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700634 package = 'chromeos-base/chromeos-config-bsp'
635
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700636 if len(refs) != 1:
637 raise ValueError('Expected exactly one ref, actual %s' % refs)
638
639 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700640 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700641 replication_config_path = os.path.join(package_root,
642 'replication_config.jsonpb')
643
644 try:
645 replication_config = json_format.Parse(
646 osutils.ReadFile(replication_config_path),
647 replication_config_pb2.ReplicationConfig())
648 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700649 raise ValueError(
650 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700651
652 replication_lib.Replicate(replication_config)
653
654 modified_files = [
655 rule.destination_path
656 for rule in replication_config.file_replication_rules
657 ]
658
Andrew Lamb9563a152019-12-04 11:42:18 -0700659 # The generated platform C files are not easily filtered by replication rules,
660 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
661 # files cannot. Therefore, replicate and filter the JSON payloads, and then
662 # generate filtered C files from the JSON payload.
663 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700664
665 # Use the private repo's commit hash as the new version.
666 new_private_version = refs[0].revision
667
Andrew Lamb988f4da2019-12-10 10:16:43 -0700668 # modified_files should contain only relative paths at this point, but the
669 # returned UprevVersionedPackageResult must contain only absolute paths.
670 for i, modified_file in enumerate(modified_files):
671 assert not os.path.isabs(modified_file)
672 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
673
Chris McDonald38409112020-09-24 11:24:51 -0600674 return uprev_lib.UprevVersionedPackageResult().add_result(
675 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700676
677
Alex Kleinbbef2b32019-08-27 10:38:50 -0600678def get_best_visible(atom, build_target=None):
679 """Returns the best visible CPV for the given atom.
680
681 Args:
682 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600683 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600684 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700685
686 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600687 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600688 """
David Burger1e0fe232019-07-01 14:52:07 -0600689 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600690
691 board = build_target.name if build_target else None
692 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600693
694
Alex Klein149fd3b2019-12-16 16:01:05 -0700695def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600696 """Check if a prebuilt exists.
697
698 Args:
699 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600700 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600701 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700702 useflags: Any additional USE flags that should be set. May be a string
703 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700704
705 Returns:
706 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600707 """
708 assert atom
709
710 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700711 extra_env = None
712 if useflags:
713 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500714 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700715 new_flags = ' '.join(useflags)
716
717 existing = os.environ.get('USE', '')
718 final_flags = '%s %s' % (existing, new_flags)
719 extra_env = {'USE': final_flags.strip()}
720 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600721
722
David Burger0f9dd4e2019-10-08 12:33:42 -0600723def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600724 """Check if |build_target| builds |atom| (has it in its depgraph)."""
725 cros_build_lib.AssertInsideChroot()
726
Alex Kleind8cd4c62020-09-14 13:37:47 -0600727 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600728 # TODO(crbug/1081828): Receive and use sysroot.
729 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600730 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600731 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600732
733
Alex Klein6becabc2020-09-11 14:03:05 -0600734def needs_chrome_source(
735 build_target: 'build_target_lib.BuildTarget',
736 compile_source=False,
737 packages: Optional[List[package_info.PackageInfo]] = None,
738 useflags=None):
739 """Check if the chrome source is needed.
740
741 The chrome source is needed if the build target builds chrome or any of its
742 follower packages, and can't use a prebuilt for them either because it's not
743 available, or because we can't use prebuilts because it must build from
744 source.
745 """
746 cros_build_lib.AssertInsideChroot()
747
748 # Check if it builds chrome and/or a follower package.
749 graph = depgraph.get_build_target_dependency_graph(build_target.root,
750 packages)
751 builds_chrome = constants.CHROME_CP in graph
752 builds_follower = {
753 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
754 }
755
756 # When we are compiling source set False since we do not use prebuilts.
757 # When not compiling from source, start with True, i.e. we have every prebuilt
758 # we've checked for up to this point.
759 has_chrome_prebuilt = not compile_source
760 has_follower_prebuilts = not compile_source
761 # Save packages that need prebuilts for reporting.
762 pkgs_needing_prebuilts = []
763 if compile_source:
764 # Need everything.
765 pkgs_needing_prebuilts.append(constants.CHROME_CP)
766 pkgs_needing_prebuilts.extend(
767 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
768 else:
769 # Check chrome itself.
770 if builds_chrome:
771 has_chrome_prebuilt = has_prebuilt(
772 constants.CHROME_CP, build_target=build_target, useflags=useflags)
773 if not has_chrome_prebuilt:
774 pkgs_needing_prebuilts.append(constants.CHROME_CP)
775 # Check follower packages.
776 for pkg, builds_pkg in builds_follower.items():
777 if not builds_pkg:
778 continue
779 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
780 has_follower_prebuilts &= prebuilt
781 if not prebuilt:
782 pkgs_needing_prebuilts.append(pkg)
783 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
784 # reflect whether we actually have the corresponding prebuilts for the build.
785
786 needs_chrome = builds_chrome and not has_chrome_prebuilt
787 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
788
789 return NeedsChromeSourceResult(
790 needs_chrome_source=needs_chrome or needs_follower,
791 builds_chrome=builds_chrome,
792 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
793 missing_chrome_prebuilt=not has_chrome_prebuilt,
794 missing_follower_prebuilt=not has_follower_prebuilts)
795
796
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600797def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600798 """Returns the current Chrome version for the board (or in buildroot).
799
800 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600801 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700802
803 Returns:
804 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600805 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600806 # TODO(crbug/1019770): Long term we should not need the try/catch here once
807 # the builds function above only returns True for chrome when
808 # determine_chrome_version will succeed.
809 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700810 cpv = portage_util.PortageqBestVisible(
811 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600812 except cros_build_lib.RunCommandError as e:
813 # Return None because portage failed when trying to determine the chrome
814 # version.
815 logging.warning('Caught exception in determine_chrome_package: %s', e)
816 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600817 # Something like 78.0.3877.4_rc -> 78.0.3877.4
818 return cpv.version_no_rev.partition('_')[0]
819
820
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600821def determine_android_package(board):
822 """Returns the active Android container package in use by the board.
823
824 Args:
825 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700826
827 Returns:
828 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600829 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600830 try:
831 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600832 except cros_build_lib.RunCommandError as e:
833 # Return None because a command (likely portage) failed when trying to
834 # determine the package.
835 logging.warning('Caught exception in determine_android_package: %s', e)
836 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600837
Alex Kleinad6b48a2020-01-08 16:57:41 -0700838 # We assume there is only one Android package in the depgraph.
839 for package in packages:
840 if package.startswith('chromeos-base/android-container-') or \
841 package.startswith('chromeos-base/android-vm-'):
842 return package
843 return None
844
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600845
846def determine_android_version(boards=None):
847 """Determine the current Android version in buildroot now and return it.
848
849 This uses the typical portage logic to determine which version of Android
850 is active right now in the buildroot.
851
852 Args:
853 boards: List of boards to check version of.
854
855 Returns:
856 The Android build ID of the container for the boards.
857
858 Raises:
859 NoAndroidVersionError: if no unique Android version can be determined.
860 """
861 if not boards:
862 return None
863 # Verify that all boards have the same version.
864 version = None
865 for board in boards:
866 package = determine_android_package(board)
867 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600868 return None
Alex Klein18a60af2020-06-11 12:08:47 -0600869 cpv = package_info.SplitCPV(package)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600870 if not cpv:
871 raise NoAndroidVersionError(
872 'Android version could not be determined for %s' % board)
873 if not version:
874 version = cpv.version_no_rev
875 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700876 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
877 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600878 return version
879
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700880
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600881def determine_android_branch(board):
882 """Returns the Android branch in use by the active container ebuild."""
883 try:
884 android_package = determine_android_package(board)
885 except cros_build_lib.RunCommandError:
886 raise NoAndroidBranchError(
887 'Android branch could not be determined for %s' % board)
888 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600889 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600890 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
891 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900892 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900893 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600894 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
895 for target in targets:
896 if target in ebuild_content:
897 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
898 if branch is not None:
899 return branch.group(1)
900 raise NoAndroidBranchError(
901 'Android branch could not be determined for %s (ebuild empty?)' % board)
902
903
904def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600905 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600906 try:
907 android_package = determine_android_package(board)
908 except cros_build_lib.RunCommandError:
909 raise NoAndroidTargetError(
910 'Android Target could not be determined for %s' % board)
911 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600912 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600913 if android_package.startswith('chromeos-base/android-vm-'):
914 return 'bertha'
915 elif android_package.startswith('chromeos-base/android-container-'):
916 return 'cheets'
917
918 raise NoAndroidTargetError(
919 'Android Target cannot be determined for the package: %s' %
920 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600921
922
923def determine_platform_version():
924 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600925 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600926 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
927 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600928
929
930def determine_milestone_version():
931 """Returns the platform version from the source root."""
932 # Milestone version is something like '79'.
933 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
934 return version.chrome_branch
935
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700936
Michael Mortensen009cb662019-10-21 11:38:43 -0600937def determine_full_version():
938 """Returns the full version from the source root."""
939 # Full version is something like 'R79-12575.0.0'.
940 milestone_version = determine_milestone_version()
941 platform_version = determine_platform_version()
942 full_version = ('R%s-%s' % (milestone_version, platform_version))
943 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600944
945
Michael Mortensende716a12020-05-15 11:27:00 -0600946def find_fingerprints(build_target):
947 """Returns a list of fingerprints for this build.
948
949 Args:
950 build_target (build_target_lib.BuildTarget): The build target.
951
952 Returns:
953 list[str] - List of fingerprint strings.
954 """
955 cros_build_lib.AssertInsideChroot()
956 fp_file = 'cheets-fingerprint.txt'
957 fp_path = os.path.join(
958 image_lib.GetLatestImageLink(build_target.name),
959 fp_file)
960 if not os.path.isfile(fp_path):
961 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600962 return []
Michael Mortensende716a12020-05-15 11:27:00 -0600963 logging.info('Reading fingerprint file: %s', fp_path)
964 fingerprints = osutils.ReadFile(fp_path).splitlines()
965 return fingerprints
966
967
Michael Mortensen59e30872020-05-18 14:12:49 -0600968def get_all_firmware_versions(build_target):
969 """Extract firmware version for all models present.
970
971 Args:
972 build_target (build_target_lib.BuildTarget): The build target.
973
974 Returns:
975 A dict of FirmwareVersions namedtuple instances by model.
976 Each element will be populated based on whether it was present in the
977 command output.
978 """
979 cros_build_lib.AssertInsideChroot()
980 result = {}
981 # Note that example output for _get_firmware_version_cmd_result is available
982 # in the packages_unittest.py for testing get_all_firmware_versions.
983 cmd_result = _get_firmware_version_cmd_result(build_target)
984
985 # There is a blank line between the version info for each model.
986 firmware_version_payloads = cmd_result.split('\n\n')
987 for firmware_version_payload in firmware_version_payloads:
988 if 'BIOS' in firmware_version_payload:
989 firmware_version = _find_firmware_versions(firmware_version_payload)
990 result[firmware_version.model] = firmware_version
991 return result
992
993
Michael Mortensen71ef5682020-05-07 14:29:24 -0600994FirmwareVersions = collections.namedtuple(
995 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
996
997
998def get_firmware_versions(build_target):
999 """Extract version information from the firmware updater, if one exists.
1000
1001 Args:
1002 build_target (build_target_lib.BuildTarget): The build target.
1003
1004 Returns:
1005 A FirmwareVersions namedtuple instance.
1006 Each element will either be set to the string output by the firmware
1007 updater shellball, or None if there is no firmware updater.
1008 """
1009 cros_build_lib.AssertInsideChroot()
1010 cmd_result = _get_firmware_version_cmd_result(build_target)
1011 if cmd_result:
1012 return _find_firmware_versions(cmd_result)
1013 else:
1014 return FirmwareVersions(None, None, None, None, None)
1015
1016
1017def _get_firmware_version_cmd_result(build_target):
1018 """Gets the raw result output of the firmware updater version command.
1019
1020 Args:
1021 build_target (build_target_lib.BuildTarget): The build target.
1022
1023 Returns:
1024 Command execution result.
1025 """
1026 updater = os.path.join(build_target.root,
1027 'usr/sbin/chromeos-firmwareupdate')
1028 logging.info('Calling updater %s', updater)
1029 # Call the updater using the chroot-based path.
1030 return cros_build_lib.run([updater, '-V'],
1031 capture_output=True, log_output=True,
1032 encoding='utf-8').stdout
1033
1034
1035def _find_firmware_versions(cmd_output):
1036 """Finds firmware version output via regex matches against the cmd_output.
1037
1038 Args:
1039 cmd_output: The raw output to search against.
1040
1041 Returns:
1042 FirmwareVersions namedtuple with results.
1043 Each element will either be set to the string output by the firmware
1044 updater shellball, or None if there is no match.
1045 """
1046
1047 # Sometimes a firmware bundle includes a special combination of RO+RW
1048 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1049 # version" field. In other cases, the "(RW) version" field is not present.
1050 # Therefore, search for the "(RW)" fields first and if they aren't present,
1051 # fallback to the other format. e.g. just "BIOS version:".
1052 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1053 main = None
1054 main_rw = None
1055 ec = None
1056 ec_rw = None
1057 model = None
1058
1059 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1060 if match:
1061 main = match.group('version')
1062
1063 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1064 if match:
1065 main_rw = match.group('version')
1066
1067 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1068 if match:
1069 ec = match.group('version')
1070
1071 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1072 if match:
1073 ec_rw = match.group('version')
1074
1075 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1076 if match:
1077 model = match.group('model')
1078
1079 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001080
1081
1082MainEcFirmwareVersions = collections.namedtuple(
1083 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1084
1085def determine_firmware_versions(build_target):
1086 """Returns a namedtuple with main and ec firmware versions.
1087
1088 Args:
1089 build_target (build_target_lib.BuildTarget): The build target.
1090
1091 Returns:
1092 MainEcFirmwareVersions namedtuple with results.
1093 """
1094 fw_versions = get_firmware_versions(build_target)
1095 main_fw_version = fw_versions.main_rw or fw_versions.main
1096 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1097
1098 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001099
1100def determine_kernel_version(build_target):
1101 """Returns a string containing the kernel version for this build target.
1102
1103 Args:
1104 build_target (build_target_lib.BuildTarget): The build target.
1105
1106 Returns:
1107 (str) The kernel versions, or None.
1108 """
1109 try:
1110 packages = portage_util.GetPackageDependencies(build_target.name,
1111 'virtual/linux-sources')
1112 except cros_build_lib.RunCommandError as e:
1113 logging.warning('Unable to get package list for metadata: %s', e)
1114 return None
1115 for package in packages:
1116 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001117 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001118 logging.info('Found active kernel version: %s', kernel_version)
1119 return kernel_version
1120 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001121
1122
1123def get_models(build_target, log_output=True):
1124 """Obtain a list of models supported by a unified board.
1125
1126 This ignored whitelabel models since GoldenEye has no specific support for
1127 these at present.
1128
1129 Args:
1130 build_target (build_target_lib.BuildTarget): The build target.
1131 log_output: Whether to log the output of the cros_config_host invocation.
1132
1133 Returns:
1134 A list of models supported by this board, if it is a unified build; None,
1135 if it is not a unified build.
1136 """
1137 return _run_cros_config_host(build_target, ['list-models'],
1138 log_output=log_output)
1139
1140
Michael Mortensen359c1f32020-05-28 19:35:42 -06001141def get_key_id(build_target, model):
1142 """Obtain the key_id for a model within the build_target.
1143
1144 Args:
1145 build_target (build_target_lib.BuildTarget): The build target.
1146 model (str): The model name
1147
1148 Returns:
1149 A key_id (str) or None.
1150 """
1151 model_arg = '--model=' + model
1152 key_id_list = _run_cros_config_host(
1153 build_target,
1154 [model_arg, 'get', '/firmware-signing', 'key-id'])
1155 key_id = None
1156 if len(key_id_list) == 1:
1157 key_id = key_id_list[0]
1158 return key_id
1159
1160
Michael Mortensen125bb012020-05-21 14:02:10 -06001161def _run_cros_config_host(build_target, args, log_output=True):
1162 """Run the cros_config_host tool.
1163
1164 Args:
1165 build_target (build_target_lib.BuildTarget): The build target.
1166 args: List of arguments to pass.
1167 log_output: Whether to log the output of the cros_config_host.
1168
1169 Returns:
1170 Output of the tool
1171 """
1172 cros_build_lib.AssertInsideChroot()
1173 tool = '/usr/bin/cros_config_host'
1174 if not os.path.isfile(tool):
1175 return None
1176
1177 config_fname = build_target.full_path(
1178 'usr/share/chromeos-config/yaml/config.yaml')
1179
1180 result = cros_build_lib.run(
1181 [tool, '-c', config_fname] + args,
1182 capture_output=True,
1183 encoding='utf-8',
1184 log_output=log_output,
1185 check=False)
1186 if result.returncode:
1187 # Show the output for debugging purposes.
1188 if 'No such file or directory' not in result.error:
1189 logging.error('cros_config_host failed: %s\n', result.error)
1190 return None
1191 return result.output.strip().splitlines()