blob: 0776c2f2c47405b8f32a3669a45f8911b95e45b0 [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
Shao-Chuan Leeb6a2cb62021-02-19 14:18:59 +0900141def uprev_android(android_package,
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700142 android_build_branch,
143 chroot,
144 build_targets=None,
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900145 android_version=None,
146 skip_commit=False):
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',
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900150 f'--android_package={android_package}',
151 f'--android_build_branch={android_build_branch}',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700152 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600153 if build_targets:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900154 command.append(f'--boards={":".join(bt.name for bt in build_targets)}')
Alex Klein4de25e82019-08-05 15:58:39 -0600155 if android_version:
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900156 command.append(f'--force_version={android_version}')
157 if skip_commit:
158 command.append('--skip_commit')
Alex Klein4de25e82019-08-05 15:58:39 -0600159
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700160 result = cros_build_lib.run(
161 command,
162 stdout=True,
163 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500164 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700165 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600166
Mike Frysinger88d96362020-02-14 19:05:45 -0500167 portage_atom_string = result.stdout.strip()
168 android_atom = None
169 if portage_atom_string:
170 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600171 if not android_atom:
172 logging.info('Found nothing to rev.')
173 return None
174
175 for target in build_targets or []:
176 # Sanity check: We should always be able to merge the version of
177 # Android we just unmasked.
Shao-Chuan Lee85ba7ce2021-02-09 13:50:11 +0900178 command = [f'emerge-{target.name}', '-p', '--quiet', f'={android_atom}']
Alex Klein4de25e82019-08-05 15:58:39 -0600179 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700180 cros_build_lib.run(
181 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600182 except cros_build_lib.RunCommandError:
183 logging.error(
184 'Cannot emerge-%s =%s\nIs Android pinned to an older '
185 'version?', target, android_atom)
186 raise AndroidIsPinnedUprevError(android_atom)
187
188 return android_atom
189
190
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700191def uprev_build_targets(build_targets,
192 overlay_type,
193 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600194 output_dir=None):
195 """Uprev the set provided build targets, or all if not specified.
196
197 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600198 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600199 whose overlays should be uprevved, empty or None for all.
200 overlay_type (str): One of the valid overlay types except None (see
201 constants.VALID_OVERLAYS).
202 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
203 output_dir (str|None): The path to optionally dump result files.
204 """
205 # Need a valid overlay, but exclude None.
206 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
207
208 if build_targets:
209 overlays = portage_util.FindOverlaysForBoards(
210 overlay_type, boards=[t.name for t in build_targets])
211 else:
212 overlays = portage_util.FindOverlays(overlay_type)
213
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700214 return uprev_overlays(
215 overlays,
216 build_targets=build_targets,
217 chroot=chroot,
218 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600219
220
221def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
222 """Uprev the given overlays.
223
224 Args:
225 overlays (list[str]): The list of overlay paths.
Alex Klein2960c752020-03-09 13:43:38 -0600226 build_targets (list[build_target_lib.BuildTarget]|None): The build targets
Alex Kleineb77ffa2019-05-28 14:47:44 -0600227 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
228 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
229 output_dir (str|None): The path to optionally dump result files.
230
231 Returns:
232 list[str] - The paths to all of the modified ebuild files. This includes the
233 new files that were added (i.e. the new versions) and all of the removed
234 files (i.e. the old versions).
235 """
236 assert overlays
237
238 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
239
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700240 uprev_manager = uprev_lib.UprevOverlayManager(
241 overlays,
242 manifest,
243 build_targets=build_targets,
244 chroot=chroot,
245 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600246 uprev_manager.uprev()
247
248 return uprev_manager.modified_ebuilds
249
250
Alex Klein87531182019-08-12 15:23:37 -0600251def uprev_versioned_package(package, build_targets, refs, chroot):
252 """Call registered uprev handler function for the package.
253
254 Args:
Alex Klein75df1792020-06-11 14:42:49 -0600255 package (package_info.CPV): The package being uprevved.
Alex Klein2960c752020-03-09 13:43:38 -0600256 build_targets (list[build_target_lib.BuildTarget]): The build targets to
Alex Klein87531182019-08-12 15:23:37 -0600257 clean on a successful uprev.
258 refs (list[uprev_lib.GitRef]):
259 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
260
261 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600262 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600263 """
264 assert package
265
266 if package.cp not in _UPREV_FUNCS:
267 raise UnknownPackageError(
268 'Package "%s" does not have a registered handler.' % package.cp)
269
Andrew Lambea9a8a22019-12-12 14:03:43 -0700270 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600271
272
Navil Perezf57ba872020-06-04 22:38:37 +0000273@uprevs_versioned_package('media-libs/virglrenderer')
274def uprev_virglrenderer(_build_targets, refs, _chroot):
275 """Updates virglrenderer ebuilds.
276
277 See: uprev_versioned_package.
278
279 Returns:
280 UprevVersionedPackageResult: The result of updating virglrenderer ebuilds.
281 """
Navil Perezf57ba872020-06-04 22:38:37 +0000282 overlay = os.path.join(constants.SOURCE_ROOT,
283 constants.CHROMIUMOS_OVERLAY_DIR)
George Engelbrechte73f2782020-06-10 14:10:46 -0600284 repo_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
285 'virglrenderer')
286 manifest = git.ManifestCheckout.Cached(repo_path)
Navil Perezf57ba872020-06-04 22:38:37 +0000287
288 uprev_manager = uprev_lib.UprevOverlayManager([overlay], manifest)
289 # TODO(crbug.com/1066242): Ebuilds for virglrenderer are currently
Jose Magana03b5a842020-08-19 12:52:59 +1000290 # denylisted. Do not force uprevs after builder is stable and ebuilds are no
291 # longer denylisted.
Navil Perezf57ba872020-06-04 22:38:37 +0000292 uprev_manager.uprev(package_list=['media-libs/virglrenderer'], force=True)
293
George Engelbrechte73f2782020-06-10 14:10:46 -0600294 updated_files = uprev_manager.modified_ebuilds
Chris McDonald38409112020-09-24 11:24:51 -0600295 result = uprev_lib.UprevVersionedPackageResult()
Navil Perezf57ba872020-06-04 22:38:37 +0000296 result.add_result(refs[0].revision, updated_files)
297 return result
298
Jose Magana03b5a842020-08-19 12:52:59 +1000299@uprevs_versioned_package('chromeos-base/drivefs')
300def uprev_drivefs(_build_targets, refs, chroot):
301 """Updates drivefs ebuilds.
302
303 See: uprev_versioned_package.
304
305 Returns:
306 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
307 """
308
Ben Reiche779cf42020-12-15 03:21:31 +0000309 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000310 result = uprev_lib.UprevVersionedPackageResult()
311 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000312
Ben Reiche779cf42020-12-15 03:21:31 +0000313 drivefs_version = get_latest_drivefs_version_from_refs(refs)
314 if not drivefs_version:
315 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000316 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000317
Ben Reiche779cf42020-12-15 03:21:31 +0000318 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000319
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000320 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000321 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000322 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000323 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000324 chroot)
Jose Magana03b5a842020-08-19 12:52:59 +1000325
326 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000327 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000328 all_changed_files.extend(uprev_result.changed_files)
329
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000330 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000331 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000332 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000333 drivefs_version,
Jose Magana03b5a842020-08-19 12:52:59 +1000334 chroot)
335
336 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000337 logging.warning(
338 'drivefs package has changed files %s but drivefs-ipc does not',
339 all_changed_files)
340 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000341
342 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000343 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000344
345 return result
346
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800347@uprevs_versioned_package('chromeos-base/perfetto')
348def uprev_perfetto(_build_targets, refs, chroot):
349 """Updates Perfetto ebuilds.
350
351 See: uprev_versioned_package.
352
353 Returns:
354 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
355 """
356 result = uprev_lib.UprevVersionedPackageResult()
357
358 perfetto_version = get_latest_perfetto_version_from_refs(refs)
359 if not perfetto_version:
360 # No valid Perfetto version is identified.
361 return result
362
363 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
364
365 # Attempt to uprev perfetto package.
366 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
367
368 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(PERFETTO_PATH,
369 perfetto_version,
370 chroot)
371
372 if not uprev_result:
373 return result
374
375 result.add_result(perfetto_version, uprev_result.changed_files)
376
377 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000378
Yaakov Shaul395ae832019-09-09 14:45:32 -0600379@uprevs_versioned_package('afdo/kernel-profiles')
380def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600381 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600382
383 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600384
385 Raises:
386 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600387 """
388 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
389 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
390
David Burger92485342019-09-10 17:52:45 -0600391 with open(path, 'r') as f:
392 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600393
Chris McDonald38409112020-09-24 11:24:51 -0600394 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600395 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600396 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
397 'sys-kernel', version)
398 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
399 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600400 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
401 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600402 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600403 patch_ebuild_vars(ebuild_path,
404 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600405
406 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600407 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400408 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600409 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600410 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600411 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600412 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600413
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600414 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600415
Yaakov Shaul730814a2019-09-10 13:58:25 -0600416 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
417
418 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600419
420
Trent Begineb624182020-07-14 10:09:45 -0600421@uprevs_versioned_package('chromeos-base/termina-dlc')
422def uprev_termina_dlc(_build_targets, _refs, chroot):
423 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600424
425 See: uprev_versioned_package.
426 """
Trent Begineb624182020-07-14 10:09:45 -0600427 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600428 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
429 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000430
431 version_pin_src_path = _get_version_pin_src_path(package_path)
432 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
433
Chris McDonald38409112020-09-24 11:24:51 -0600434 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000435
436
437@uprevs_versioned_package('app-emulation/parallels-desktop')
438def uprev_parallels_desktop(_build_targets, _refs, chroot):
439 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
440
441 See: uprev_versioned_package
442
443 Returns:
444 UprevVersionedPackageResult: The result.
445 """
446 package = 'parallels-desktop'
447 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
448 'app-emulation', package)
449 version_pin_src_path = _get_version_pin_src_path(package_path)
450
451 # Expect a JSON blob like the following:
452 # {
453 # "version": "1.2.3",
454 # "test_image": { "url": "...", "size": 12345678,
455 # "sha256sum": "<32 bytes of hexadecimal>" }
456 # }
457 with open(version_pin_src_path, 'r') as f:
458 pinned = json.load(f)
459
460 if 'version' not in pinned or 'test_image' not in pinned:
461 raise UprevError('VERSION-PIN for %s missing version and/or '
462 'test_image field' % package)
463
464 version = pinned['version']
465 if not isinstance(version, str):
466 raise UprevError('version in VERSION-PIN for %s not a string' % package)
467
468 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600469 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000470
471 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100472 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
473 'local/bundles/crosint/pita/data/'
474 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000475 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
476 with open(test_image_src_path, 'w') as f:
477 json.dump(pinned['test_image'], f, indent=2)
478 result.add_result(version, [test_image_src_path])
479
480 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600481
482
Trent Begin315d9d92019-12-03 21:55:53 -0700483@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600484def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700485 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
486
487 See: uprev_versioned_package.
488 """
489 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700490 package_path = os.path.join('src', 'private-overlays',
491 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000492 version_pin_src_path = _get_version_pin_src_path(package_path)
493 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700494
Chris McDonald38409112020-09-24 11:24:51 -0600495 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700496
497
Patrick Meiring5897add2020-09-16 16:30:17 +1000498def _get_version_pin_src_path(package_path):
499 """Returns the path to the VERSION-PIN file for the given package."""
500 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
501
502
Alex Klein87531182019-08-12 15:23:37 -0600503@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700504def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600505 """Uprev chrome and its related packages.
506
507 See: uprev_versioned_package.
508 """
509 # Determine the version from the refs (tags), i.e. the chrome versions are the
510 # tag names.
511 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600512 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600513
514 uprev_manager = uprev_lib.UprevChromeManager(
515 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600516 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600517 # Start with chrome itself, as we can't do anything else unless chrome
518 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600519 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
520 # attempt. The expected behavior is documented in the following table:
521 #
522 # Outcome of Chrome uprev attempt:
523 # NEWER_VERSION_EXISTS:
524 # Do nothing.
525 # SAME_VERSION_EXISTS or REVISION_BUMP:
526 # Uprev followers
527 # Assert not VERSION_BUMP (any other outcome is fine)
528 # VERSION_BUMP or NEW_EBUILD_CREATED:
529 # Uprev followers
530 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600531 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600532 return result
Alex Klein87531182019-08-12 15:23:37 -0600533
534 # With a successful chrome rev, also uprev related packages.
535 for package in constants.OTHER_CHROME_PACKAGES:
536 uprev_manager.uprev(package)
537
David Burger37f48672019-09-18 17:07:56 -0600538 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600539
540
Ben Reiche779cf42020-12-15 03:21:31 +0000541def get_latest_drivefs_version_from_refs(refs: List[uprev_lib.GitRef]) -> str:
542 """Get the latest DriveFS version from refs
543
544 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
545 Versions are compared using |distutils.version.LooseVersion| and
546 the latest version is returned.
547
548 Args:
549 refs: The tags to parse for the latest DriveFS version.
550
551 Returns:
552 The latest DriveFS version to use.
553 """
554 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
555
556 valid_refs = []
557 for gitiles in refs:
558 if gitiles.ref.startswith(DRIVEFS_REFS_PREFIX):
559 valid_refs.append(gitiles.ref)
560
561 if not valid_refs:
562 return None
563
564 # Sort by version and take the latest version.
565 target_version_ref = sorted(valid_refs,
566 key=LooseVersion,
567 reverse=True)[0]
568 return target_version_ref.replace(DRIVEFS_REFS_PREFIX, '')
569
570
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800571def get_latest_perfetto_version_from_refs(refs: List[uprev_lib.GitRef]) -> str:
572 """Get the latest Perfetto version from refs
573
574 Perfetto versions follow the tag format of refs/tags/v1.2.
575 Versions are compared using |distutils.version.LooseVersion| and
576 the latest version is returned.
577
578 Args:
579 refs: The tags to parse for the latest Perfetto version.
580
581 Returns:
582 The latest Perfetto version to use.
583 """
584 PERFETTO_REFS_PREFIX = 'refs/tags/v'
585
586 valid_refs = []
587 for gitiles in refs:
588 if gitiles.ref.startswith(PERFETTO_REFS_PREFIX):
589 valid_refs.append(gitiles.ref)
590
591 if not valid_refs:
592 return None
593
594 # Sort by version and take the latest version.
595 target_version_ref = sorted(valid_refs,
596 key=LooseVersion,
597 reverse=True)[0]
598 return target_version_ref.replace(PERFETTO_REFS_PREFIX, '')
599
600
Andrew Lamb9563a152019-12-04 11:42:18 -0700601def _generate_platform_c_files(replication_config, chroot):
602 """Generates platform C files from a platform JSON payload.
603
604 Args:
605 replication_config (replication_config_pb2.ReplicationConfig): A
606 ReplicationConfig that has already been run. If it produced a
607 build_config.json file, that file will be used to generate platform C
608 files. Otherwise, nothing will be generated.
609 chroot (chroot_lib.Chroot): The chroot to use to generate.
610
611 Returns:
612 A list of generated files.
613 """
614 # Generate the platform C files from the build config. Note that it would be
615 # more intuitive to generate the platform C files from the platform config;
616 # however, cros_config_schema does not allow this, because the platform config
617 # payload is not always valid input. For example, if a property is both
618 # 'required' and 'build-only', it will fail schema validation. Thus, use the
619 # build config, and use '-f' to filter.
620 build_config_path = [
621 rule.destination_path
622 for rule in replication_config.file_replication_rules
623 if rule.destination_path.endswith('build_config.json')
624 ]
625
626 if not build_config_path:
627 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700628 'No build_config.json found, will not generate platform C files. '
629 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700630 return []
631
632 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700633 raise ValueError('Expected at most one build_config.json destination path. '
634 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700635
636 build_config_path = build_config_path[0]
637
638 # Paths to the build_config.json and dir to output C files to, in the
639 # chroot.
640 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
641 build_config_path)
642 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
643 os.path.dirname(build_config_path))
644
645 command = [
646 'cros_config_schema', '-m', build_config_chroot_path, '-g',
647 generated_output_chroot_dir, '-f', '"TRUE"'
648 ]
649
650 cros_build_lib.run(
651 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
652
653 # A relative (to the source root) path to the generated C files.
654 generated_output_dir = os.path.dirname(build_config_path)
655 generated_files = []
656 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
657 for f in expected_c_files:
658 if os.path.exists(
659 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
660 generated_files.append(os.path.join(generated_output_dir, f))
661
662 if len(expected_c_files) != len(generated_files):
663 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
664
665 return generated_files
666
667
Andrew Lambe836f222019-12-09 12:27:38 -0700668def _get_private_overlay_package_root(ref, package):
669 """Returns the absolute path to the root of a given private overlay.
670
671 Args:
672 ref (uprev_lib.GitRef): GitRef for the private overlay.
673 package (str): Path to the package in the overlay.
674 """
675 # There might be a cleaner way to map from package -> path within the source
676 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700677 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700678 match = re.match(private_overlay_ref_pattern, ref.path)
679 if not match:
680 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
681 (private_overlay_ref_pattern, ref))
682
683 overlay = match.group(1)
684
685 return os.path.join(constants.SOURCE_ROOT,
686 'src/private-overlays/overlay-%s-private' % overlay,
687 package)
688
689
Andrew Lambea9a8a22019-12-12 14:03:43 -0700690@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
691def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700692 """Replicate a private cros_config change to the corresponding public config.
693
Alex Kleinad6b48a2020-01-08 16:57:41 -0700694 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700695 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700696 package = 'chromeos-base/chromeos-config-bsp'
697
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700698 if len(refs) != 1:
699 raise ValueError('Expected exactly one ref, actual %s' % refs)
700
701 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700702 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700703 replication_config_path = os.path.join(package_root,
704 'replication_config.jsonpb')
705
706 try:
707 replication_config = json_format.Parse(
708 osutils.ReadFile(replication_config_path),
709 replication_config_pb2.ReplicationConfig())
710 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700711 raise ValueError(
712 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700713
714 replication_lib.Replicate(replication_config)
715
716 modified_files = [
717 rule.destination_path
718 for rule in replication_config.file_replication_rules
719 ]
720
Andrew Lamb9563a152019-12-04 11:42:18 -0700721 # The generated platform C files are not easily filtered by replication rules,
722 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
723 # files cannot. Therefore, replicate and filter the JSON payloads, and then
724 # generate filtered C files from the JSON payload.
725 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700726
727 # Use the private repo's commit hash as the new version.
728 new_private_version = refs[0].revision
729
Andrew Lamb988f4da2019-12-10 10:16:43 -0700730 # modified_files should contain only relative paths at this point, but the
731 # returned UprevVersionedPackageResult must contain only absolute paths.
732 for i, modified_file in enumerate(modified_files):
733 assert not os.path.isabs(modified_file)
734 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
735
Chris McDonald38409112020-09-24 11:24:51 -0600736 return uprev_lib.UprevVersionedPackageResult().add_result(
737 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700738
739
Alex Kleinbbef2b32019-08-27 10:38:50 -0600740def get_best_visible(atom, build_target=None):
741 """Returns the best visible CPV for the given atom.
742
743 Args:
744 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600745 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600746 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700747
748 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600749 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600750 """
David Burger1e0fe232019-07-01 14:52:07 -0600751 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600752
753 board = build_target.name if build_target else None
754 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600755
756
Alex Klein149fd3b2019-12-16 16:01:05 -0700757def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600758 """Check if a prebuilt exists.
759
760 Args:
761 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600762 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600763 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700764 useflags: Any additional USE flags that should be set. May be a string
765 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700766
767 Returns:
768 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600769 """
770 assert atom
771
772 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700773 extra_env = None
774 if useflags:
775 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500776 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700777 new_flags = ' '.join(useflags)
778
779 existing = os.environ.get('USE', '')
780 final_flags = '%s %s' % (existing, new_flags)
781 extra_env = {'USE': final_flags.strip()}
782 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600783
784
David Burger0f9dd4e2019-10-08 12:33:42 -0600785def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600786 """Check if |build_target| builds |atom| (has it in its depgraph)."""
787 cros_build_lib.AssertInsideChroot()
788
Alex Kleind8cd4c62020-09-14 13:37:47 -0600789 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600790 # TODO(crbug/1081828): Receive and use sysroot.
791 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600792 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600793 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600794
795
Alex Klein6becabc2020-09-11 14:03:05 -0600796def needs_chrome_source(
797 build_target: 'build_target_lib.BuildTarget',
798 compile_source=False,
799 packages: Optional[List[package_info.PackageInfo]] = None,
800 useflags=None):
801 """Check if the chrome source is needed.
802
803 The chrome source is needed if the build target builds chrome or any of its
804 follower packages, and can't use a prebuilt for them either because it's not
805 available, or because we can't use prebuilts because it must build from
806 source.
807 """
808 cros_build_lib.AssertInsideChroot()
809
810 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700811 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600812 builds_chrome = constants.CHROME_CP in graph
813 builds_follower = {
814 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
815 }
816
817 # When we are compiling source set False since we do not use prebuilts.
818 # When not compiling from source, start with True, i.e. we have every prebuilt
819 # we've checked for up to this point.
820 has_chrome_prebuilt = not compile_source
821 has_follower_prebuilts = not compile_source
822 # Save packages that need prebuilts for reporting.
823 pkgs_needing_prebuilts = []
824 if compile_source:
825 # Need everything.
826 pkgs_needing_prebuilts.append(constants.CHROME_CP)
827 pkgs_needing_prebuilts.extend(
828 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
829 else:
830 # Check chrome itself.
831 if builds_chrome:
832 has_chrome_prebuilt = has_prebuilt(
833 constants.CHROME_CP, build_target=build_target, useflags=useflags)
834 if not has_chrome_prebuilt:
835 pkgs_needing_prebuilts.append(constants.CHROME_CP)
836 # Check follower packages.
837 for pkg, builds_pkg in builds_follower.items():
838 if not builds_pkg:
839 continue
840 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
841 has_follower_prebuilts &= prebuilt
842 if not prebuilt:
843 pkgs_needing_prebuilts.append(pkg)
844 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
845 # reflect whether we actually have the corresponding prebuilts for the build.
846
847 needs_chrome = builds_chrome and not has_chrome_prebuilt
848 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
849
850 return NeedsChromeSourceResult(
851 needs_chrome_source=needs_chrome or needs_follower,
852 builds_chrome=builds_chrome,
853 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
854 missing_chrome_prebuilt=not has_chrome_prebuilt,
855 missing_follower_prebuilt=not has_follower_prebuilts)
856
857
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600858def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600859 """Returns the current Chrome version for the board (or in buildroot).
860
861 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600862 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700863
864 Returns:
865 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600866 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600867 # TODO(crbug/1019770): Long term we should not need the try/catch here once
868 # the builds function above only returns True for chrome when
869 # determine_chrome_version will succeed.
870 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700871 cpv = portage_util.PortageqBestVisible(
872 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600873 except cros_build_lib.RunCommandError as e:
874 # Return None because portage failed when trying to determine the chrome
875 # version.
876 logging.warning('Caught exception in determine_chrome_package: %s', e)
877 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600878 # Something like 78.0.3877.4_rc -> 78.0.3877.4
879 return cpv.version_no_rev.partition('_')[0]
880
881
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600882def determine_android_package(board):
883 """Returns the active Android container package in use by the board.
884
885 Args:
886 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700887
888 Returns:
889 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600890 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600891 try:
892 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600893 except cros_build_lib.RunCommandError as e:
894 # Return None because a command (likely portage) failed when trying to
895 # determine the package.
896 logging.warning('Caught exception in determine_android_package: %s', e)
897 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600898
Alex Kleinad6b48a2020-01-08 16:57:41 -0700899 # We assume there is only one Android package in the depgraph.
900 for package in packages:
901 if package.startswith('chromeos-base/android-container-') or \
902 package.startswith('chromeos-base/android-vm-'):
903 return package
904 return None
905
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600906
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500907def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600908 """Determine the current Android version in buildroot now and return it.
909
910 This uses the typical portage logic to determine which version of Android
911 is active right now in the buildroot.
912
913 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500914 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500915 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600916
917 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500918 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600919
920 Raises:
921 NoAndroidVersionError: if no unique Android version can be determined.
922 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500923 if not package:
924 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500925 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600926 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500927 cpv = package_info.SplitCPV(package)
928 if not cpv:
929 raise NoAndroidVersionError(
930 'Android version could not be determined for %s' % board)
931 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600932
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700933
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500934def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600935 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500936 if not package:
937 package = determine_android_package(board)
938 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600939 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500940 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600941 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900942 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900943 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600944 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
945 for target in targets:
946 if target in ebuild_content:
947 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
948 if branch is not None:
949 return branch.group(1)
950 raise NoAndroidBranchError(
951 'Android branch could not be determined for %s (ebuild empty?)' % board)
952
953
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500954def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600955 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500956 if not package:
957 package = determine_android_package(board)
958 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600959 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500960 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600961 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500962 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600963 return 'cheets'
964
965 raise NoAndroidTargetError(
966 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500967 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600968
969
970def determine_platform_version():
971 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600972 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600973 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
974 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600975
976
977def determine_milestone_version():
978 """Returns the platform version from the source root."""
979 # Milestone version is something like '79'.
980 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
981 return version.chrome_branch
982
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700983
Michael Mortensen009cb662019-10-21 11:38:43 -0600984def determine_full_version():
985 """Returns the full version from the source root."""
986 # Full version is something like 'R79-12575.0.0'.
987 milestone_version = determine_milestone_version()
988 platform_version = determine_platform_version()
989 full_version = ('R%s-%s' % (milestone_version, platform_version))
990 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600991
992
Michael Mortensende716a12020-05-15 11:27:00 -0600993def find_fingerprints(build_target):
994 """Returns a list of fingerprints for this build.
995
996 Args:
997 build_target (build_target_lib.BuildTarget): The build target.
998
999 Returns:
1000 list[str] - List of fingerprint strings.
1001 """
1002 cros_build_lib.AssertInsideChroot()
1003 fp_file = 'cheets-fingerprint.txt'
1004 fp_path = os.path.join(
1005 image_lib.GetLatestImageLink(build_target.name),
1006 fp_file)
1007 if not os.path.isfile(fp_path):
1008 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -06001009 return []
Michael Mortensende716a12020-05-15 11:27:00 -06001010 logging.info('Reading fingerprint file: %s', fp_path)
1011 fingerprints = osutils.ReadFile(fp_path).splitlines()
1012 return fingerprints
1013
1014
Michael Mortensen59e30872020-05-18 14:12:49 -06001015def get_all_firmware_versions(build_target):
1016 """Extract firmware version for all models present.
1017
1018 Args:
1019 build_target (build_target_lib.BuildTarget): The build target.
1020
1021 Returns:
1022 A dict of FirmwareVersions namedtuple instances by model.
1023 Each element will be populated based on whether it was present in the
1024 command output.
1025 """
1026 cros_build_lib.AssertInsideChroot()
1027 result = {}
1028 # Note that example output for _get_firmware_version_cmd_result is available
1029 # in the packages_unittest.py for testing get_all_firmware_versions.
1030 cmd_result = _get_firmware_version_cmd_result(build_target)
1031
1032 # There is a blank line between the version info for each model.
1033 firmware_version_payloads = cmd_result.split('\n\n')
1034 for firmware_version_payload in firmware_version_payloads:
1035 if 'BIOS' in firmware_version_payload:
1036 firmware_version = _find_firmware_versions(firmware_version_payload)
1037 result[firmware_version.model] = firmware_version
1038 return result
1039
1040
Michael Mortensen71ef5682020-05-07 14:29:24 -06001041FirmwareVersions = collections.namedtuple(
1042 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1043
1044
1045def get_firmware_versions(build_target):
1046 """Extract version information from the firmware updater, if one exists.
1047
1048 Args:
1049 build_target (build_target_lib.BuildTarget): The build target.
1050
1051 Returns:
1052 A FirmwareVersions namedtuple instance.
1053 Each element will either be set to the string output by the firmware
1054 updater shellball, or None if there is no firmware updater.
1055 """
1056 cros_build_lib.AssertInsideChroot()
1057 cmd_result = _get_firmware_version_cmd_result(build_target)
1058 if cmd_result:
1059 return _find_firmware_versions(cmd_result)
1060 else:
1061 return FirmwareVersions(None, None, None, None, None)
1062
1063
1064def _get_firmware_version_cmd_result(build_target):
1065 """Gets the raw result output of the firmware updater version command.
1066
1067 Args:
1068 build_target (build_target_lib.BuildTarget): The build target.
1069
1070 Returns:
1071 Command execution result.
1072 """
1073 updater = os.path.join(build_target.root,
1074 'usr/sbin/chromeos-firmwareupdate')
1075 logging.info('Calling updater %s', updater)
1076 # Call the updater using the chroot-based path.
1077 return cros_build_lib.run([updater, '-V'],
1078 capture_output=True, log_output=True,
1079 encoding='utf-8').stdout
1080
1081
1082def _find_firmware_versions(cmd_output):
1083 """Finds firmware version output via regex matches against the cmd_output.
1084
1085 Args:
1086 cmd_output: The raw output to search against.
1087
1088 Returns:
1089 FirmwareVersions namedtuple with results.
1090 Each element will either be set to the string output by the firmware
1091 updater shellball, or None if there is no match.
1092 """
1093
1094 # Sometimes a firmware bundle includes a special combination of RO+RW
1095 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1096 # version" field. In other cases, the "(RW) version" field is not present.
1097 # Therefore, search for the "(RW)" fields first and if they aren't present,
1098 # fallback to the other format. e.g. just "BIOS version:".
1099 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1100 main = None
1101 main_rw = None
1102 ec = None
1103 ec_rw = None
1104 model = None
1105
1106 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1107 if match:
1108 main = match.group('version')
1109
1110 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1111 if match:
1112 main_rw = match.group('version')
1113
1114 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1115 if match:
1116 ec = match.group('version')
1117
1118 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1119 if match:
1120 ec_rw = match.group('version')
1121
1122 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1123 if match:
1124 model = match.group('model')
1125
1126 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001127
1128
1129MainEcFirmwareVersions = collections.namedtuple(
1130 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1131
1132def determine_firmware_versions(build_target):
1133 """Returns a namedtuple with main and ec firmware versions.
1134
1135 Args:
1136 build_target (build_target_lib.BuildTarget): The build target.
1137
1138 Returns:
1139 MainEcFirmwareVersions namedtuple with results.
1140 """
1141 fw_versions = get_firmware_versions(build_target)
1142 main_fw_version = fw_versions.main_rw or fw_versions.main
1143 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1144
1145 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001146
1147def determine_kernel_version(build_target):
1148 """Returns a string containing the kernel version for this build target.
1149
1150 Args:
1151 build_target (build_target_lib.BuildTarget): The build target.
1152
1153 Returns:
1154 (str) The kernel versions, or None.
1155 """
1156 try:
1157 packages = portage_util.GetPackageDependencies(build_target.name,
1158 'virtual/linux-sources')
1159 except cros_build_lib.RunCommandError as e:
1160 logging.warning('Unable to get package list for metadata: %s', e)
1161 return None
1162 for package in packages:
1163 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001164 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001165 logging.info('Found active kernel version: %s', kernel_version)
1166 return kernel_version
1167 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001168
1169
1170def get_models(build_target, log_output=True):
1171 """Obtain a list of models supported by a unified board.
1172
1173 This ignored whitelabel models since GoldenEye has no specific support for
1174 these at present.
1175
1176 Args:
1177 build_target (build_target_lib.BuildTarget): The build target.
1178 log_output: Whether to log the output of the cros_config_host invocation.
1179
1180 Returns:
1181 A list of models supported by this board, if it is a unified build; None,
1182 if it is not a unified build.
1183 """
1184 return _run_cros_config_host(build_target, ['list-models'],
1185 log_output=log_output)
1186
1187
Michael Mortensen359c1f32020-05-28 19:35:42 -06001188def get_key_id(build_target, model):
1189 """Obtain the key_id for a model within the build_target.
1190
1191 Args:
1192 build_target (build_target_lib.BuildTarget): The build target.
1193 model (str): The model name
1194
1195 Returns:
1196 A key_id (str) or None.
1197 """
1198 model_arg = '--model=' + model
1199 key_id_list = _run_cros_config_host(
1200 build_target,
1201 [model_arg, 'get', '/firmware-signing', 'key-id'])
1202 key_id = None
1203 if len(key_id_list) == 1:
1204 key_id = key_id_list[0]
1205 return key_id
1206
1207
Michael Mortensen125bb012020-05-21 14:02:10 -06001208def _run_cros_config_host(build_target, args, log_output=True):
1209 """Run the cros_config_host tool.
1210
1211 Args:
1212 build_target (build_target_lib.BuildTarget): The build target.
1213 args: List of arguments to pass.
1214 log_output: Whether to log the output of the cros_config_host.
1215
1216 Returns:
1217 Output of the tool
1218 """
1219 cros_build_lib.AssertInsideChroot()
1220 tool = '/usr/bin/cros_config_host'
1221 if not os.path.isfile(tool):
1222 return None
1223
1224 config_fname = build_target.full_path(
1225 'usr/share/chromeos-config/yaml/config.yaml')
1226
1227 result = cros_build_lib.run(
1228 [tool, '-c', config_fname] + args,
1229 capture_output=True,
1230 encoding='utf-8',
1231 log_output=log_output,
1232 check=False)
1233 if result.returncode:
1234 # Show the output for debugging purposes.
1235 if 'No such file or directory' not in result.error:
1236 logging.error('cros_config_host failed: %s\n', result.error)
1237 return None
1238 return result.output.strip().splitlines()