blob: 61cb5d03e23ee5a50a0f348d4be33e7553093011 [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
Harvey Yang3eee06c2021-03-18 15:47:56 +0800303 DriveFS versions follow the tag format of refs/tags/drivefs_1.2.3.
Jose Magana03b5a842020-08-19 12:52:59 +1000304 See: uprev_versioned_package.
305
306 Returns:
307 UprevVersionedPackageResult: The result of updating drivefs ebuilds.
308 """
309
Ben Reiche779cf42020-12-15 03:21:31 +0000310 DRIVEFS_PATH_PREFIX = 'src/private-overlays/chromeos-overlay/chromeos-base'
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000311 result = uprev_lib.UprevVersionedPackageResult()
312 all_changed_files = []
Jose Magana03b5a842020-08-19 12:52:59 +1000313
Harvey Yang3eee06c2021-03-18 15:47:56 +0800314 DRIVEFS_REFS_PREFIX = 'refs/tags/drivefs_'
315 drivefs_version = _get_latest_version_from_refs(DRIVEFS_REFS_PREFIX, refs)
Ben Reiche779cf42020-12-15 03:21:31 +0000316 if not drivefs_version:
317 # No valid DriveFS version is identified.
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000318 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000319
Ben Reiche779cf42020-12-15 03:21:31 +0000320 logging.debug('DriveFS version determined from refs: %s', drivefs_version)
Jose Magana03b5a842020-08-19 12:52:59 +1000321
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000322 # Attempt to uprev drivefs package.
Ben Reiche779cf42020-12-15 03:21:31 +0000323 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs')
Jose Magana03b5a842020-08-19 12:52:59 +1000324 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000325 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800326 chroot,
327 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000328
329 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000330 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000331 all_changed_files.extend(uprev_result.changed_files)
332
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000333 # Attempt to uprev drivefs-ipc package.
Ben Reiche779cf42020-12-15 03:21:31 +0000334 pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
Jose Magana03b5a842020-08-19 12:52:59 +1000335 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
Ben Reiche779cf42020-12-15 03:21:31 +0000336 drivefs_version,
Harvey Yang3eee06c2021-03-18 15:47:56 +0800337 chroot,
338 allow_downrev=False)
Jose Magana03b5a842020-08-19 12:52:59 +1000339
340 if not uprev_result:
Ben Reich4f3fa1b2020-12-19 08:21:26 +0000341 logging.warning(
342 'drivefs package has changed files %s but drivefs-ipc does not',
343 all_changed_files)
344 return result
Jose Magana03b5a842020-08-19 12:52:59 +1000345
346 all_changed_files.extend(uprev_result.changed_files)
Ben Reiche779cf42020-12-15 03:21:31 +0000347 result.add_result(drivefs_version, all_changed_files)
Jose Magana03b5a842020-08-19 12:52:59 +1000348
349 return result
350
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800351@uprevs_versioned_package('chromeos-base/perfetto')
352def uprev_perfetto(_build_targets, refs, chroot):
353 """Updates Perfetto ebuilds.
354
Harvey Yang3eee06c2021-03-18 15:47:56 +0800355 Perfetto versions follow the tag format of refs/tags/v1.2.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800356 See: uprev_versioned_package.
357
358 Returns:
359 UprevVersionedPackageResult: The result of updating Perfetto ebuilds.
360 """
361 result = uprev_lib.UprevVersionedPackageResult()
362
Harvey Yang3eee06c2021-03-18 15:47:56 +0800363 PERFETTO_REFS_PREFIX = 'refs/tags/v'
364 perfetto_version = _get_latest_version_from_refs(PERFETTO_REFS_PREFIX, refs)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800365 if not perfetto_version:
366 # No valid Perfetto version is identified.
367 return result
368
369 logging.debug('Perfetto version determined from refs: %s', perfetto_version)
370
371 # Attempt to uprev perfetto package.
372 PERFETTO_PATH = 'src/third_party/chromiumos-overlay/chromeos-base/perfetto'
373
Harvey Yang3eee06c2021-03-18 15:47:56 +0800374 uprev_result = uprev_lib.uprev_workon_ebuild_to_version(
375 PERFETTO_PATH,
376 perfetto_version,
377 chroot,
378 allow_downrev=False,
379 ref=PERFETTO_REFS_PREFIX + perfetto_version)
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800380
381 if not uprev_result:
382 return result
383
384 result.add_result(perfetto_version, uprev_result.changed_files)
385
386 return result
Navil Perezf57ba872020-06-04 22:38:37 +0000387
Yaakov Shaul395ae832019-09-09 14:45:32 -0600388@uprevs_versioned_package('afdo/kernel-profiles')
389def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600390 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600391
392 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600393
394 Raises:
395 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600396 """
397 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
398 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
399
David Burger92485342019-09-10 17:52:45 -0600400 with open(path, 'r') as f:
401 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600402
Chris McDonald38409112020-09-24 11:24:51 -0600403 result = uprev_lib.UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600404 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600405 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
406 'sys-kernel', version)
407 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
408 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600409 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
410 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600411 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600412 patch_ebuild_vars(ebuild_path,
413 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600414
415 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600416 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400417 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600418 except cros_build_lib.RunCommandError as e:
Chris McDonald38409112020-09-24 11:24:51 -0600419 raise uprev_lib.EbuildManifestError(
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600420 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600421 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600422
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600423 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600424
Yaakov Shaul730814a2019-09-10 13:58:25 -0600425 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
426
427 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600428
429
Trent Begineb624182020-07-14 10:09:45 -0600430@uprevs_versioned_package('chromeos-base/termina-dlc')
431def uprev_termina_dlc(_build_targets, _refs, chroot):
432 """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
Trent Beginaf51f1b2020-03-09 17:35:31 -0600433
434 See: uprev_versioned_package.
435 """
Trent Begineb624182020-07-14 10:09:45 -0600436 package = 'termina-dlc'
Trent Beginaf51f1b2020-03-09 17:35:31 -0600437 package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
438 package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000439
440 version_pin_src_path = _get_version_pin_src_path(package_path)
441 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
442
Chris McDonald38409112020-09-24 11:24:51 -0600443 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000444
445
446@uprevs_versioned_package('app-emulation/parallels-desktop')
447def uprev_parallels_desktop(_build_targets, _refs, chroot):
448 """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
449
450 See: uprev_versioned_package
451
452 Returns:
453 UprevVersionedPackageResult: The result.
454 """
455 package = 'parallels-desktop'
456 package_path = os.path.join(constants.CHROMEOS_PARTNER_OVERLAY_DIR,
457 'app-emulation', package)
458 version_pin_src_path = _get_version_pin_src_path(package_path)
459
460 # Expect a JSON blob like the following:
461 # {
462 # "version": "1.2.3",
463 # "test_image": { "url": "...", "size": 12345678,
464 # "sha256sum": "<32 bytes of hexadecimal>" }
465 # }
466 with open(version_pin_src_path, 'r') as f:
467 pinned = json.load(f)
468
469 if 'version' not in pinned or 'test_image' not in pinned:
470 raise UprevError('VERSION-PIN for %s missing version and/or '
471 'test_image field' % package)
472
473 version = pinned['version']
474 if not isinstance(version, str):
475 raise UprevError('version in VERSION-PIN for %s not a string' % package)
476
477 # Update the ebuild.
Chris McDonald38409112020-09-24 11:24:51 -0600478 result = uprev_lib.uprev_ebuild_from_pin(package_path, version, chroot)
Patrick Meiring5897add2020-09-16 16:30:17 +1000479
480 # Update the VM image used for testing.
Patrick Meiring1342def2020-10-30 17:09:13 +1100481 test_image_path = ('src/platform/tast-tests-private/src/chromiumos/tast/'
482 'local/bundles/crosint/pita/data/'
483 'pluginvm_image.zip.external')
Patrick Meiring5897add2020-09-16 16:30:17 +1000484 test_image_src_path = os.path.join(constants.SOURCE_ROOT, test_image_path)
485 with open(test_image_src_path, 'w') as f:
486 json.dump(pinned['test_image'], f, indent=2)
487 result.add_result(version, [test_image_src_path])
488
489 return result
Trent Beginaf51f1b2020-03-09 17:35:31 -0600490
491
Trent Begin315d9d92019-12-03 21:55:53 -0700492@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Beginaf51f1b2020-03-09 17:35:31 -0600493def uprev_sludge(_build_targets, _refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700494 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
495
496 See: uprev_versioned_package.
497 """
498 package = 'chromeos-dtc-vm'
Trent Begind943df92020-02-25 10:30:10 -0700499 package_path = os.path.join('src', 'private-overlays',
500 'project-wilco-private', 'chromeos-base', package)
Patrick Meiring5897add2020-09-16 16:30:17 +1000501 version_pin_src_path = _get_version_pin_src_path(package_path)
502 version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
Trent Begin315d9d92019-12-03 21:55:53 -0700503
Chris McDonald38409112020-09-24 11:24:51 -0600504 return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700505
506
Patrick Meiring5897add2020-09-16 16:30:17 +1000507def _get_version_pin_src_path(package_path):
508 """Returns the path to the VERSION-PIN file for the given package."""
509 return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
510
511
Alex Klein87531182019-08-12 15:23:37 -0600512@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700513def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600514 """Uprev chrome and its related packages.
515
516 See: uprev_versioned_package.
517 """
518 # Determine the version from the refs (tags), i.e. the chrome versions are the
519 # tag names.
520 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
Chris McDonald25881af2020-05-12 03:17:53 -0600521 logging.debug('Chrome version determined from refs: %s', chrome_version)
Alex Klein87531182019-08-12 15:23:37 -0600522
523 uprev_manager = uprev_lib.UprevChromeManager(
524 chrome_version, build_targets=build_targets, chroot=chroot)
Chris McDonald38409112020-09-24 11:24:51 -0600525 result = uprev_lib.UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600526 # Start with chrome itself, as we can't do anything else unless chrome
527 # uprevs successfully.
Chris McDonald25881af2020-05-12 03:17:53 -0600528 # TODO(crbug.com/1080429): Handle all possible outcomes of a Chrome uprev
529 # attempt. The expected behavior is documented in the following table:
530 #
531 # Outcome of Chrome uprev attempt:
532 # NEWER_VERSION_EXISTS:
533 # Do nothing.
534 # SAME_VERSION_EXISTS or REVISION_BUMP:
535 # Uprev followers
536 # Assert not VERSION_BUMP (any other outcome is fine)
537 # VERSION_BUMP or NEW_EBUILD_CREATED:
538 # Uprev followers
539 # Assert that Chrome & followers are at same package version
Alex Klein87531182019-08-12 15:23:37 -0600540 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600541 return result
Alex Klein87531182019-08-12 15:23:37 -0600542
543 # With a successful chrome rev, also uprev related packages.
544 for package in constants.OTHER_CHROME_PACKAGES:
545 uprev_manager.uprev(package)
546
David Burger37f48672019-09-18 17:07:56 -0600547 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600548
549
Harvey Yang3eee06c2021-03-18 15:47:56 +0800550def _get_latest_version_from_refs(refs_prefix: str,
551 refs: List[uprev_lib.GitRef]) -> str:
552 """Get the latest version from refs
Ben Reiche779cf42020-12-15 03:21:31 +0000553
Ben Reiche779cf42020-12-15 03:21:31 +0000554 Versions are compared using |distutils.version.LooseVersion| and
555 the latest version is returned.
556
557 Args:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800558 refs_prefix: The refs prefix of the tag format.
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800559 refs: The tags to parse for the latest Perfetto version.
560
561 Returns:
562 The latest Perfetto version to use.
563 """
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800564 valid_refs = []
565 for gitiles in refs:
Harvey Yang3eee06c2021-03-18 15:47:56 +0800566 if gitiles.ref.startswith(refs_prefix):
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800567 valid_refs.append(gitiles.ref)
568
569 if not valid_refs:
570 return None
571
572 # Sort by version and take the latest version.
573 target_version_ref = sorted(valid_refs,
574 key=LooseVersion,
575 reverse=True)[0]
Harvey Yang3eee06c2021-03-18 15:47:56 +0800576 return target_version_ref.replace(refs_prefix, '')
Harvey Yang9c61e9c2021-03-02 16:32:43 +0800577
578
Andrew Lamb9563a152019-12-04 11:42:18 -0700579def _generate_platform_c_files(replication_config, chroot):
580 """Generates platform C files from a platform JSON payload.
581
582 Args:
583 replication_config (replication_config_pb2.ReplicationConfig): A
584 ReplicationConfig that has already been run. If it produced a
585 build_config.json file, that file will be used to generate platform C
586 files. Otherwise, nothing will be generated.
587 chroot (chroot_lib.Chroot): The chroot to use to generate.
588
589 Returns:
590 A list of generated files.
591 """
592 # Generate the platform C files from the build config. Note that it would be
593 # more intuitive to generate the platform C files from the platform config;
594 # however, cros_config_schema does not allow this, because the platform config
595 # payload is not always valid input. For example, if a property is both
596 # 'required' and 'build-only', it will fail schema validation. Thus, use the
597 # build config, and use '-f' to filter.
598 build_config_path = [
599 rule.destination_path
600 for rule in replication_config.file_replication_rules
601 if rule.destination_path.endswith('build_config.json')
602 ]
603
604 if not build_config_path:
605 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700606 'No build_config.json found, will not generate platform C files. '
607 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700608 return []
609
610 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700611 raise ValueError('Expected at most one build_config.json destination path. '
612 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700613
614 build_config_path = build_config_path[0]
615
616 # Paths to the build_config.json and dir to output C files to, in the
617 # chroot.
618 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
619 build_config_path)
620 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
621 os.path.dirname(build_config_path))
622
623 command = [
624 'cros_config_schema', '-m', build_config_chroot_path, '-g',
625 generated_output_chroot_dir, '-f', '"TRUE"'
626 ]
627
628 cros_build_lib.run(
629 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
630
631 # A relative (to the source root) path to the generated C files.
632 generated_output_dir = os.path.dirname(build_config_path)
633 generated_files = []
634 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
635 for f in expected_c_files:
636 if os.path.exists(
637 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
638 generated_files.append(os.path.join(generated_output_dir, f))
639
640 if len(expected_c_files) != len(generated_files):
641 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
642
643 return generated_files
644
645
Andrew Lambe836f222019-12-09 12:27:38 -0700646def _get_private_overlay_package_root(ref, package):
647 """Returns the absolute path to the root of a given private overlay.
648
649 Args:
650 ref (uprev_lib.GitRef): GitRef for the private overlay.
651 package (str): Path to the package in the overlay.
652 """
653 # There might be a cleaner way to map from package -> path within the source
654 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700655 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700656 match = re.match(private_overlay_ref_pattern, ref.path)
657 if not match:
658 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
659 (private_overlay_ref_pattern, ref))
660
661 overlay = match.group(1)
662
663 return os.path.join(constants.SOURCE_ROOT,
664 'src/private-overlays/overlay-%s-private' % overlay,
665 package)
666
667
Andrew Lambea9a8a22019-12-12 14:03:43 -0700668@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
669def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700670 """Replicate a private cros_config change to the corresponding public config.
671
Alex Kleinad6b48a2020-01-08 16:57:41 -0700672 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700673 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700674 package = 'chromeos-base/chromeos-config-bsp'
675
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700676 if len(refs) != 1:
677 raise ValueError('Expected exactly one ref, actual %s' % refs)
678
679 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700680 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700681 replication_config_path = os.path.join(package_root,
682 'replication_config.jsonpb')
683
684 try:
685 replication_config = json_format.Parse(
686 osutils.ReadFile(replication_config_path),
687 replication_config_pb2.ReplicationConfig())
688 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700689 raise ValueError(
690 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700691
692 replication_lib.Replicate(replication_config)
693
694 modified_files = [
695 rule.destination_path
696 for rule in replication_config.file_replication_rules
697 ]
698
Andrew Lamb9563a152019-12-04 11:42:18 -0700699 # The generated platform C files are not easily filtered by replication rules,
700 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
701 # files cannot. Therefore, replicate and filter the JSON payloads, and then
702 # generate filtered C files from the JSON payload.
703 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700704
705 # Use the private repo's commit hash as the new version.
706 new_private_version = refs[0].revision
707
Andrew Lamb988f4da2019-12-10 10:16:43 -0700708 # modified_files should contain only relative paths at this point, but the
709 # returned UprevVersionedPackageResult must contain only absolute paths.
710 for i, modified_file in enumerate(modified_files):
711 assert not os.path.isabs(modified_file)
712 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
713
Chris McDonald38409112020-09-24 11:24:51 -0600714 return uprev_lib.UprevVersionedPackageResult().add_result(
715 new_private_version, modified_files)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700716
717
Alex Kleinbbef2b32019-08-27 10:38:50 -0600718def get_best_visible(atom, build_target=None):
719 """Returns the best visible CPV for the given atom.
720
721 Args:
722 atom (str): The atom to look up.
Alex Klein2960c752020-03-09 13:43:38 -0600723 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600724 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700725
726 Returns:
Alex Klein75df1792020-06-11 14:42:49 -0600727 package_info.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600728 """
David Burger1e0fe232019-07-01 14:52:07 -0600729 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600730
731 board = build_target.name if build_target else None
732 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600733
734
Alex Klein149fd3b2019-12-16 16:01:05 -0700735def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600736 """Check if a prebuilt exists.
737
738 Args:
739 atom (str): The package whose prebuilt is being queried.
Alex Klein2960c752020-03-09 13:43:38 -0600740 build_target (build_target_lib.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600741 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700742 useflags: Any additional USE flags that should be set. May be a string
743 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700744
745 Returns:
746 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600747 """
748 assert atom
749
750 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700751 extra_env = None
752 if useflags:
753 new_flags = useflags
Mike Frysingercfecd6b2020-12-14 23:54:05 -0500754 if not isinstance(useflags, str):
Alex Klein149fd3b2019-12-16 16:01:05 -0700755 new_flags = ' '.join(useflags)
756
757 existing = os.environ.get('USE', '')
758 final_flags = '%s %s' % (existing, new_flags)
759 extra_env = {'USE': final_flags.strip()}
760 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600761
762
David Burger0f9dd4e2019-10-08 12:33:42 -0600763def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600764 """Check if |build_target| builds |atom| (has it in its depgraph)."""
765 cros_build_lib.AssertInsideChroot()
766
Alex Kleind8cd4c62020-09-14 13:37:47 -0600767 pkgs = tuple(packages) if packages else None
LaMont Jones4cbecba2020-05-12 11:54:27 -0600768 # TODO(crbug/1081828): Receive and use sysroot.
769 graph, _sdk_graph = dependency.GetBuildDependency(
Alex Kleind8cd4c62020-09-14 13:37:47 -0600770 build_target.root, build_target.name, pkgs)
Alex Klein36b117f2019-09-30 15:13:46 -0600771 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600772
773
Alex Klein6becabc2020-09-11 14:03:05 -0600774def needs_chrome_source(
775 build_target: 'build_target_lib.BuildTarget',
776 compile_source=False,
777 packages: Optional[List[package_info.PackageInfo]] = None,
778 useflags=None):
779 """Check if the chrome source is needed.
780
781 The chrome source is needed if the build target builds chrome or any of its
782 follower packages, and can't use a prebuilt for them either because it's not
783 available, or because we can't use prebuilts because it must build from
784 source.
785 """
786 cros_build_lib.AssertInsideChroot()
787
788 # Check if it builds chrome and/or a follower package.
Alex Kleina8052162021-02-03 14:28:22 -0700789 graph = depgraph.get_sysroot_dependency_graph(build_target.root, packages)
Alex Klein6becabc2020-09-11 14:03:05 -0600790 builds_chrome = constants.CHROME_CP in graph
791 builds_follower = {
792 pkg: pkg in graph for pkg in constants.OTHER_CHROME_PACKAGES
793 }
794
795 # When we are compiling source set False since we do not use prebuilts.
796 # When not compiling from source, start with True, i.e. we have every prebuilt
797 # we've checked for up to this point.
798 has_chrome_prebuilt = not compile_source
799 has_follower_prebuilts = not compile_source
800 # Save packages that need prebuilts for reporting.
801 pkgs_needing_prebuilts = []
802 if compile_source:
803 # Need everything.
804 pkgs_needing_prebuilts.append(constants.CHROME_CP)
805 pkgs_needing_prebuilts.extend(
806 [pkg for pkg, builds_pkg in builds_follower.items() if builds_pkg])
807 else:
808 # Check chrome itself.
809 if builds_chrome:
810 has_chrome_prebuilt = has_prebuilt(
811 constants.CHROME_CP, build_target=build_target, useflags=useflags)
812 if not has_chrome_prebuilt:
813 pkgs_needing_prebuilts.append(constants.CHROME_CP)
814 # Check follower packages.
815 for pkg, builds_pkg in builds_follower.items():
816 if not builds_pkg:
817 continue
818 prebuilt = has_prebuilt(pkg, build_target=build_target, useflags=useflags)
819 has_follower_prebuilts &= prebuilt
820 if not prebuilt:
821 pkgs_needing_prebuilts.append(pkg)
822 # Postcondition: has_chrome_prebuilt and has_follower_prebuilts now correctly
823 # reflect whether we actually have the corresponding prebuilts for the build.
824
825 needs_chrome = builds_chrome and not has_chrome_prebuilt
826 needs_follower = any(builds_follower.values()) and not has_follower_prebuilts
827
828 return NeedsChromeSourceResult(
829 needs_chrome_source=needs_chrome or needs_follower,
830 builds_chrome=builds_chrome,
831 packages=[package_info.parse(p) for p in pkgs_needing_prebuilts],
832 missing_chrome_prebuilt=not has_chrome_prebuilt,
833 missing_follower_prebuilt=not has_follower_prebuilts)
834
835
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600836def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600837 """Returns the current Chrome version for the board (or in buildroot).
838
839 Args:
Alex Klein2960c752020-03-09 13:43:38 -0600840 build_target (build_target_lib.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700841
842 Returns:
843 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600844 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600845 # TODO(crbug/1019770): Long term we should not need the try/catch here once
846 # the builds function above only returns True for chrome when
847 # determine_chrome_version will succeed.
848 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700849 cpv = portage_util.PortageqBestVisible(
850 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600851 except cros_build_lib.RunCommandError as e:
852 # Return None because portage failed when trying to determine the chrome
853 # version.
854 logging.warning('Caught exception in determine_chrome_package: %s', e)
855 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600856 # Something like 78.0.3877.4_rc -> 78.0.3877.4
857 return cpv.version_no_rev.partition('_')[0]
858
859
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600860def determine_android_package(board):
861 """Returns the active Android container package in use by the board.
862
863 Args:
864 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700865
866 Returns:
867 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600868 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600869 try:
870 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600871 except cros_build_lib.RunCommandError as e:
872 # Return None because a command (likely portage) failed when trying to
873 # determine the package.
874 logging.warning('Caught exception in determine_android_package: %s', e)
875 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600876
Alex Kleinad6b48a2020-01-08 16:57:41 -0700877 # We assume there is only one Android package in the depgraph.
878 for package in packages:
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400879 if (package.startswith('chromeos-base/android-container-') or
880 package.startswith('chromeos-base/android-vm-')):
Alex Kleinad6b48a2020-01-08 16:57:41 -0700881 return package
882 return None
883
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600884
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500885def determine_android_version(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600886 """Determine the current Android version in buildroot now and return it.
887
888 This uses the typical portage logic to determine which version of Android
889 is active right now in the buildroot.
890
891 Args:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500892 board: The board name this is specific to.
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500893 package: The Android package, if already computed.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600894
895 Returns:
Mike Frysingerb53f1822021-03-05 00:44:50 -0500896 The Android build ID of the container for the board.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600897
898 Raises:
899 NoAndroidVersionError: if no unique Android version can be determined.
900 """
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500901 if not package:
902 package = determine_android_package(board)
Mike Frysingerb53f1822021-03-05 00:44:50 -0500903 if not package:
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600904 return None
Mike Frysingerb53f1822021-03-05 00:44:50 -0500905 cpv = package_info.SplitCPV(package)
906 if not cpv:
907 raise NoAndroidVersionError(
908 'Android version could not be determined for %s' % board)
909 return cpv.version_no_rev
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600910
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700911
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500912def determine_android_branch(board, package=None):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600913 """Returns the Android branch in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500914 if not package:
915 package = determine_android_package(board)
916 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600917 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500918 ebuild_path = portage_util.FindEbuildForBoardPackage(package, board)
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600919 # We assume all targets pull from the same branch and that we always
Federico 'Morg' Pareschicd9165a2020-05-29 09:45:55 +0900920 # have at least one of the following targets.
Shao-Chuan Lee73bba612020-06-17 11:47:04 +0900921 targets = constants.ANDROID_ALL_BUILD_TARGETS
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600922 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
923 for target in targets:
924 if target in ebuild_content:
925 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
926 if branch is not None:
927 return branch.group(1)
928 raise NoAndroidBranchError(
929 'Android branch could not be determined for %s (ebuild empty?)' % board)
930
931
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500932def determine_android_target(board, package=None):
Michael Mortensen14960d02019-10-18 07:53:59 -0600933 """Returns the Android target in use by the active container ebuild."""
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500934 if not package:
935 package = determine_android_package(board)
936 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600937 return None
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500938 if package.startswith('chromeos-base/android-vm-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600939 return 'bertha'
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500940 elif package.startswith('chromeos-base/android-container-'):
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600941 return 'cheets'
942
943 raise NoAndroidTargetError(
944 'Android Target cannot be determined for the package: %s' %
Mike Frysinger8e1c99a2021-03-05 00:58:11 -0500945 package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600946
947
948def determine_platform_version():
949 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600950 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600951 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
952 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600953
954
955def determine_milestone_version():
956 """Returns the platform version from the source root."""
957 # Milestone version is something like '79'.
958 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
959 return version.chrome_branch
960
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700961
Michael Mortensen009cb662019-10-21 11:38:43 -0600962def determine_full_version():
963 """Returns the full version from the source root."""
964 # Full version is something like 'R79-12575.0.0'.
965 milestone_version = determine_milestone_version()
966 platform_version = determine_platform_version()
967 full_version = ('R%s-%s' % (milestone_version, platform_version))
968 return full_version
Michael Mortensen71ef5682020-05-07 14:29:24 -0600969
970
Michael Mortensende716a12020-05-15 11:27:00 -0600971def find_fingerprints(build_target):
972 """Returns a list of fingerprints for this build.
973
974 Args:
975 build_target (build_target_lib.BuildTarget): The build target.
976
977 Returns:
978 list[str] - List of fingerprint strings.
979 """
980 cros_build_lib.AssertInsideChroot()
981 fp_file = 'cheets-fingerprint.txt'
982 fp_path = os.path.join(
983 image_lib.GetLatestImageLink(build_target.name),
984 fp_file)
985 if not os.path.isfile(fp_path):
986 logging.info('Fingerprint file not found: %s', fp_path)
Michael Mortensend81d81e2020-06-09 14:20:59 -0600987 return []
Michael Mortensende716a12020-05-15 11:27:00 -0600988 logging.info('Reading fingerprint file: %s', fp_path)
989 fingerprints = osutils.ReadFile(fp_path).splitlines()
990 return fingerprints
991
992
Michael Mortensen59e30872020-05-18 14:12:49 -0600993def get_all_firmware_versions(build_target):
994 """Extract firmware version for all models present.
995
996 Args:
997 build_target (build_target_lib.BuildTarget): The build target.
998
999 Returns:
1000 A dict of FirmwareVersions namedtuple instances by model.
1001 Each element will be populated based on whether it was present in the
1002 command output.
1003 """
1004 cros_build_lib.AssertInsideChroot()
1005 result = {}
1006 # Note that example output for _get_firmware_version_cmd_result is available
1007 # in the packages_unittest.py for testing get_all_firmware_versions.
1008 cmd_result = _get_firmware_version_cmd_result(build_target)
1009
1010 # There is a blank line between the version info for each model.
1011 firmware_version_payloads = cmd_result.split('\n\n')
1012 for firmware_version_payload in firmware_version_payloads:
1013 if 'BIOS' in firmware_version_payload:
1014 firmware_version = _find_firmware_versions(firmware_version_payload)
1015 result[firmware_version.model] = firmware_version
1016 return result
1017
1018
Michael Mortensen71ef5682020-05-07 14:29:24 -06001019FirmwareVersions = collections.namedtuple(
1020 'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
1021
1022
1023def get_firmware_versions(build_target):
1024 """Extract version information from the firmware updater, if one exists.
1025
1026 Args:
1027 build_target (build_target_lib.BuildTarget): The build target.
1028
1029 Returns:
1030 A FirmwareVersions namedtuple instance.
1031 Each element will either be set to the string output by the firmware
1032 updater shellball, or None if there is no firmware updater.
1033 """
1034 cros_build_lib.AssertInsideChroot()
1035 cmd_result = _get_firmware_version_cmd_result(build_target)
1036 if cmd_result:
1037 return _find_firmware_versions(cmd_result)
1038 else:
1039 return FirmwareVersions(None, None, None, None, None)
1040
1041
1042def _get_firmware_version_cmd_result(build_target):
1043 """Gets the raw result output of the firmware updater version command.
1044
1045 Args:
1046 build_target (build_target_lib.BuildTarget): The build target.
1047
1048 Returns:
1049 Command execution result.
1050 """
1051 updater = os.path.join(build_target.root,
1052 'usr/sbin/chromeos-firmwareupdate')
1053 logging.info('Calling updater %s', updater)
1054 # Call the updater using the chroot-based path.
1055 return cros_build_lib.run([updater, '-V'],
1056 capture_output=True, log_output=True,
1057 encoding='utf-8').stdout
1058
1059
1060def _find_firmware_versions(cmd_output):
1061 """Finds firmware version output via regex matches against the cmd_output.
1062
1063 Args:
1064 cmd_output: The raw output to search against.
1065
1066 Returns:
1067 FirmwareVersions namedtuple with results.
1068 Each element will either be set to the string output by the firmware
1069 updater shellball, or None if there is no match.
1070 """
1071
1072 # Sometimes a firmware bundle includes a special combination of RO+RW
1073 # firmware. In this case, the RW firmware version is indicated with a "(RW)
1074 # version" field. In other cases, the "(RW) version" field is not present.
1075 # Therefore, search for the "(RW)" fields first and if they aren't present,
1076 # fallback to the other format. e.g. just "BIOS version:".
1077 # TODO(mmortensen): Use JSON once the firmware updater supports it.
1078 main = None
1079 main_rw = None
1080 ec = None
1081 ec_rw = None
1082 model = None
1083
1084 match = re.search(r'BIOS version:\s*(?P<version>.*)', cmd_output)
1085 if match:
1086 main = match.group('version')
1087
1088 match = re.search(r'BIOS \(RW\) version:\s*(?P<version>.*)', cmd_output)
1089 if match:
1090 main_rw = match.group('version')
1091
1092 match = re.search(r'EC version:\s*(?P<version>.*)', cmd_output)
1093 if match:
1094 ec = match.group('version')
1095
1096 match = re.search(r'EC \(RW\) version:\s*(?P<version>.*)', cmd_output)
1097 if match:
1098 ec_rw = match.group('version')
1099
1100 match = re.search(r'Model:\s*(?P<model>.*)', cmd_output)
1101 if match:
1102 model = match.group('model')
1103
1104 return FirmwareVersions(model, main, main_rw, ec, ec_rw)
Michael Mortensena4af79e2020-05-06 16:18:48 -06001105
1106
1107MainEcFirmwareVersions = collections.namedtuple(
1108 'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
1109
1110def determine_firmware_versions(build_target):
1111 """Returns a namedtuple with main and ec firmware versions.
1112
1113 Args:
1114 build_target (build_target_lib.BuildTarget): The build target.
1115
1116 Returns:
1117 MainEcFirmwareVersions namedtuple with results.
1118 """
1119 fw_versions = get_firmware_versions(build_target)
1120 main_fw_version = fw_versions.main_rw or fw_versions.main
1121 ec_fw_version = fw_versions.ec_rw or fw_versions.ec
1122
1123 return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001124
1125def determine_kernel_version(build_target):
1126 """Returns a string containing the kernel version for this build target.
1127
1128 Args:
1129 build_target (build_target_lib.BuildTarget): The build target.
1130
1131 Returns:
1132 (str) The kernel versions, or None.
1133 """
1134 try:
1135 packages = portage_util.GetPackageDependencies(build_target.name,
1136 'virtual/linux-sources')
1137 except cros_build_lib.RunCommandError as e:
1138 logging.warning('Unable to get package list for metadata: %s', e)
1139 return None
1140 for package in packages:
1141 if package.startswith('sys-kernel/chromeos-kernel-'):
Alex Klein18a60af2020-06-11 12:08:47 -06001142 kernel_version = package_info.SplitCPV(package).version
Michael Mortensenfbf2b2d2020-05-14 16:33:06 -06001143 logging.info('Found active kernel version: %s', kernel_version)
1144 return kernel_version
1145 return None
Michael Mortensen125bb012020-05-21 14:02:10 -06001146
1147
1148def get_models(build_target, log_output=True):
1149 """Obtain a list of models supported by a unified board.
1150
1151 This ignored whitelabel models since GoldenEye has no specific support for
1152 these at present.
1153
1154 Args:
1155 build_target (build_target_lib.BuildTarget): The build target.
1156 log_output: Whether to log the output of the cros_config_host invocation.
1157
1158 Returns:
1159 A list of models supported by this board, if it is a unified build; None,
1160 if it is not a unified build.
1161 """
1162 return _run_cros_config_host(build_target, ['list-models'],
1163 log_output=log_output)
1164
1165
Michael Mortensen359c1f32020-05-28 19:35:42 -06001166def get_key_id(build_target, model):
1167 """Obtain the key_id for a model within the build_target.
1168
1169 Args:
1170 build_target (build_target_lib.BuildTarget): The build target.
1171 model (str): The model name
1172
1173 Returns:
1174 A key_id (str) or None.
1175 """
1176 model_arg = '--model=' + model
1177 key_id_list = _run_cros_config_host(
1178 build_target,
1179 [model_arg, 'get', '/firmware-signing', 'key-id'])
1180 key_id = None
1181 if len(key_id_list) == 1:
1182 key_id = key_id_list[0]
1183 return key_id
1184
1185
Michael Mortensen125bb012020-05-21 14:02:10 -06001186def _run_cros_config_host(build_target, args, log_output=True):
1187 """Run the cros_config_host tool.
1188
1189 Args:
1190 build_target (build_target_lib.BuildTarget): The build target.
1191 args: List of arguments to pass.
1192 log_output: Whether to log the output of the cros_config_host.
1193
1194 Returns:
1195 Output of the tool
1196 """
1197 cros_build_lib.AssertInsideChroot()
1198 tool = '/usr/bin/cros_config_host'
1199 if not os.path.isfile(tool):
1200 return None
1201
1202 config_fname = build_target.full_path(
1203 'usr/share/chromeos-config/yaml/config.yaml')
1204
1205 result = cros_build_lib.run(
1206 [tool, '-c', config_fname] + args,
1207 capture_output=True,
1208 encoding='utf-8',
1209 log_output=log_output,
1210 check=False)
1211 if result.returncode:
1212 # Show the output for debugging purposes.
1213 if 'No such file or directory' not in result.error:
1214 logging.error('cros_config_host failed: %s\n', result.error)
1215 return None
1216 return result.output.strip().splitlines()