blob: 7d7cb6ca3f87d587019e0836a0b888401a8f7f1c [file] [log] [blame]
Alex Kleineb77ffa2019-05-28 14:47:44 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Package utility functionality."""
7
8from __future__ import print_function
9
Yaakov Shaul730814a2019-09-10 13:58:25 -060010import collections
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060011import fileinput
Alex Klein87531182019-08-12 15:23:37 -060012import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060013import json
Evan Hernandezb51f1522019-08-15 11:29:40 -060014import os
Michael Mortensenb70e8a82019-10-10 18:43:41 -060015import re
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -060016import sys
Alex Klein87531182019-08-12 15:23:37 -060017
Alex Klein149fd3b2019-12-16 16:01:05 -070018import six
19
Andrew Lamb2bde9e42019-11-04 13:24:09 -070020from google.protobuf import json_format
Yaakov Shaul730814a2019-09-10 13:58:25 -060021
Andrew Lamb2bde9e42019-11-04 13:24:09 -070022from chromite.api.gen.config import replication_config_pb2
Michael Mortensen9fdb14b2019-10-17 11:17:30 -060023from chromite.cbuildbot import manifest_version
Alex Kleineb77ffa2019-05-28 14:47:44 -060024from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060025from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060026from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060027from chromite.lib import git
Michael Mortensenb70e8a82019-10-10 18:43:41 -060028from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060029from chromite.lib import portage_util
Andrew Lamb2bde9e42019-11-04 13:24:09 -070030from chromite.lib import replication_lib
Alex Kleind6195b62019-08-06 16:01:16 -060031from chromite.lib import uprev_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060032
Alex Klein36b117f2019-09-30 15:13:46 -060033if cros_build_lib.IsInsideChroot():
34 from chromite.service import dependency
35
Alex Klein87531182019-08-12 15:23:37 -060036# Registered handlers for uprevving versioned packages.
37_UPREV_FUNCS = {}
38
Alex Kleineb77ffa2019-05-28 14:47:44 -060039
40class Error(Exception):
41 """Module's base error class."""
42
43
Alex Klein4de25e82019-08-05 15:58:39 -060044class UnknownPackageError(Error):
45 """Uprev attempted for a package without a registered handler."""
46
47
Alex Kleineb77ffa2019-05-28 14:47:44 -060048class UprevError(Error):
49 """An error occurred while uprevving packages."""
50
51
Michael Mortensenb70e8a82019-10-10 18:43:41 -060052class NoAndroidVersionError(Error):
53 """An error occurred while trying to determine the android version."""
54
55
56class NoAndroidBranchError(Error):
57 """An error occurred while trying to determine the android branch."""
58
59
60class NoAndroidTargetError(Error):
61 """An error occurred while trying to determine the android target."""
62
63
Alex Klein4de25e82019-08-05 15:58:39 -060064class AndroidIsPinnedUprevError(UprevError):
65 """Raised when we try to uprev while Android is pinned."""
66
67 def __init__(self, new_android_atom):
68 """Initialize a AndroidIsPinnedUprevError.
69
70 Args:
71 new_android_atom: The Android atom that we failed to
72 uprev to, due to Android being pinned.
73 """
74 assert new_android_atom
75 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
76 new_android_atom)
77 super(AndroidIsPinnedUprevError, self).__init__(msg)
78 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060079
80
Yaakov Shaul1eafe832019-09-10 16:50:26 -060081class EbuildManifestError(Error):
82 """Error when running ebuild manifest."""
83
84
Andrew Lamb9563a152019-12-04 11:42:18 -070085class GeneratedCrosConfigFilesError(Error):
86 """Error when cros_config_schema does not produce expected files"""
87
88 def __init__(self, expected_files, found_files):
89 msg = ('Expected to find generated C files: %s. Actually found: %s' %
90 (expected_files, found_files))
91 super(GeneratedCrosConfigFilesError, self).__init__(msg)
92
Alex Klein7a3a7dd2020-01-08 16:44:38 -070093
Yaakov Shaul730814a2019-09-10 13:58:25 -060094UprevVersionedPackageModifications = collections.namedtuple(
95 'UprevVersionedPackageModifications', ('new_version', 'files'))
Alex Klein34afcbc2019-08-22 16:14:31 -060096
Yaakov Shaul730814a2019-09-10 13:58:25 -060097
98class UprevVersionedPackageResult(object):
99 """Data object for uprev_versioned_package."""
100
101 def __init__(self):
102 self.modified = []
103
104 def add_result(self, new_version, modified_files):
105 """Adds version/ebuilds tuple to result.
106
107 Args:
108 new_version: New version number of package.
109 modified_files: List of files modified for the given version.
110 """
111 result = UprevVersionedPackageModifications(new_version, modified_files)
112 self.modified.append(result)
113 return self
Alex Klein34afcbc2019-08-22 16:14:31 -0600114
115 @property
116 def uprevved(self):
Yaakov Shaul730814a2019-09-10 13:58:25 -0600117 return bool(self.modified)
Alex Klein34afcbc2019-08-22 16:14:31 -0600118
119
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600120def patch_ebuild_vars(ebuild_path, variables):
121 """Updates variables in ebuild.
122
123 Use this function rather than portage_util.EBuild.UpdateEBuild when you
124 want to preserve the variable position and quotes within the ebuild.
125
126 Args:
127 ebuild_path: The path of the ebuild.
128 variables: Dictionary of variables to update in ebuild.
129 """
130 try:
131 for line in fileinput.input(ebuild_path, inplace=1):
132 varname, eq, _ = line.partition('=')
133 if eq == '=' and varname.strip() in variables:
134 value = variables[varname]
135 sys.stdout.write('%s="%s"\n' % (varname, value))
136 else:
137 sys.stdout.write(line)
138 finally:
139 fileinput.close()
140
141
Alex Klein87531182019-08-12 15:23:37 -0600142def uprevs_versioned_package(package):
143 """Decorator to register package uprev handlers."""
144 assert package
145
146 def register(func):
147 """Registers |func| as a handler for |package|."""
148 _UPREV_FUNCS[package] = func
149
150 @functools.wraps(func)
151 def pass_through(*args, **kwargs):
152 return func(*args, **kwargs)
153
154 return pass_through
155
156 return register
157
158
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700159def uprev_android(tracking_branch,
160 android_package,
161 android_build_branch,
162 chroot,
163 build_targets=None,
164 android_version=None,
Alex Klein4de25e82019-08-05 15:58:39 -0600165 android_gts_build_branch=None):
166 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700167 command = [
168 'cros_mark_android_as_stable',
169 '--tracking_branch=%s' % tracking_branch,
170 '--android_package=%s' % android_package,
171 '--android_build_branch=%s' % android_build_branch,
172 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600173 if build_targets:
174 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
175 if android_version:
176 command.append('--force_version=%s' % android_version)
177 if android_gts_build_branch:
178 command.append('--android_gts_build_branch=%s' % android_gts_build_branch)
179
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700180 result = cros_build_lib.run(
181 command,
182 stdout=True,
183 enter_chroot=True,
184 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600185
186 android_atom = _parse_android_atom(result)
187 if not android_atom:
188 logging.info('Found nothing to rev.')
189 return None
190
191 for target in build_targets or []:
192 # Sanity check: We should always be able to merge the version of
193 # Android we just unmasked.
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700194 command = ['emerge-%s' % target.name, '-p', '--quiet', '=%s' % android_atom]
Alex Klein4de25e82019-08-05 15:58:39 -0600195 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700196 cros_build_lib.run(
197 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600198 except cros_build_lib.RunCommandError:
199 logging.error(
200 'Cannot emerge-%s =%s\nIs Android pinned to an older '
201 'version?', target, android_atom)
202 raise AndroidIsPinnedUprevError(android_atom)
203
204 return android_atom
205
206
207def _parse_android_atom(result):
208 """Helper to parse the atom from the cros_mark_android_as_stable output.
209
210 This function is largely just intended to make testing easier.
211
212 Args:
213 result (cros_build_lib.CommandResult): The cros_mark_android_as_stable
214 command result.
215 """
216 portage_atom_string = result.output.strip()
217
218 android_atom = None
219 if portage_atom_string:
220 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
221
222 return android_atom
223
224
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700225def uprev_build_targets(build_targets,
226 overlay_type,
227 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600228 output_dir=None):
229 """Uprev the set provided build targets, or all if not specified.
230
231 Args:
232 build_targets (list[build_target_util.BuildTarget]|None): The build targets
233 whose overlays should be uprevved, empty or None for all.
234 overlay_type (str): One of the valid overlay types except None (see
235 constants.VALID_OVERLAYS).
236 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
237 output_dir (str|None): The path to optionally dump result files.
238 """
239 # Need a valid overlay, but exclude None.
240 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
241
242 if build_targets:
243 overlays = portage_util.FindOverlaysForBoards(
244 overlay_type, boards=[t.name for t in build_targets])
245 else:
246 overlays = portage_util.FindOverlays(overlay_type)
247
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700248 return uprev_overlays(
249 overlays,
250 build_targets=build_targets,
251 chroot=chroot,
252 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600253
254
255def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
256 """Uprev the given overlays.
257
258 Args:
259 overlays (list[str]): The list of overlay paths.
260 build_targets (list[build_target_util.BuildTarget]|None): The build targets
261 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
262 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
263 output_dir (str|None): The path to optionally dump result files.
264
265 Returns:
266 list[str] - The paths to all of the modified ebuild files. This includes the
267 new files that were added (i.e. the new versions) and all of the removed
268 files (i.e. the old versions).
269 """
270 assert overlays
271
272 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
273
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700274 uprev_manager = uprev_lib.UprevOverlayManager(
275 overlays,
276 manifest,
277 build_targets=build_targets,
278 chroot=chroot,
279 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600280 uprev_manager.uprev()
281
282 return uprev_manager.modified_ebuilds
283
284
Alex Klein87531182019-08-12 15:23:37 -0600285def uprev_versioned_package(package, build_targets, refs, chroot):
286 """Call registered uprev handler function for the package.
287
288 Args:
289 package (portage_util.CPV): The package being uprevved.
290 build_targets (list[build_target_util.BuildTarget]): The build targets to
291 clean on a successful uprev.
292 refs (list[uprev_lib.GitRef]):
293 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
294
295 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600296 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600297 """
298 assert package
299
300 if package.cp not in _UPREV_FUNCS:
301 raise UnknownPackageError(
302 'Package "%s" does not have a registered handler.' % package.cp)
303
Andrew Lambea9a8a22019-12-12 14:03:43 -0700304 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600305
306
Evan Hernandezb51f1522019-08-15 11:29:40 -0600307# TODO(evanhernandez): Remove this. Only a quick hack for testing.
308@uprevs_versioned_package('sample/sample')
309def uprev_sample(*_args, **_kwargs):
310 """Mimics an uprev by changing files in sandbox repos.
311
312 See: uprev_versioned_package.
313 """
314 paths = [
315 os.path.join(constants.SOURCE_ROOT, 'infra/dummies', repo, 'sample.txt')
316 for repo in ('general-sandbox', 'merge-sandbox')
317 ]
318
Yaakov Shaul730814a2019-09-10 13:58:25 -0600319 return UprevVersionedPackageResult().add_result('1.2.3', paths)
Evan Hernandezb51f1522019-08-15 11:29:40 -0600320
321
Yaakov Shaul395ae832019-09-09 14:45:32 -0600322@uprevs_versioned_package('afdo/kernel-profiles')
323def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600324 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600325
326 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600327
328 Raises:
329 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600330 """
331 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
332 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
333
David Burger92485342019-09-10 17:52:45 -0600334 with open(path, 'r') as f:
335 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600336
Yaakov Shaul730814a2019-09-10 13:58:25 -0600337 result = UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600338 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600339 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
340 'sys-kernel', version)
341 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
342 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600343 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
344 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600345 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600346 patch_ebuild_vars(ebuild_path,
347 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600348
349 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600350 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400351 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600352 except cros_build_lib.RunCommandError as e:
353 raise EbuildManifestError(
354 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600355 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600356
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600357 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600358
Yaakov Shaul730814a2019-09-10 13:58:25 -0600359 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
360
361 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600362
363
Trent Begin315d9d92019-12-03 21:55:53 -0700364@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
365def uprev_sludge(*_args, **_kwargs):
366 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
367
368 See: uprev_versioned_package.
369 """
370 package = 'chromeos-dtc-vm'
371 path = os.path.join('src', 'private-overlays', 'project-wilco-private',
372 'chromeos-base', package)
373 package_path = os.path.join(constants.SOURCE_ROOT, path)
374 version_pin_path = os.path.join(constants.SOURCE_ROOT, path, 'VERSION-PIN')
375
376 return uprev_ebuild_from_pin(package_path, version_pin_path)
377
378
379def uprev_ebuild_from_pin(package_path, version_pin_path):
380 """Changes the package ebuild's version to match the version pin file.
381
382 Args:
383 package_path: The path of the package relative to the src root. This path
384 should contain a single ebuild with the same name as the package.
385 version_pin_path: The path of the version_pin file that contains only only
386 a version string. The ebuild's version will be directly set to this
387 number.
388
389 Returns:
390 UprevVersionedPackageResult: The result.
391 """
392 package = os.path.basename(package_path)
393 ebuild_paths = list(portage_util.EBuild.List(package_path))
394 if not ebuild_paths:
395 raise UprevError('No ebuilds found for %s' % package)
396 elif len(ebuild_paths) > 1:
397 raise UprevError('Multiple ebuilds found for %s' % package)
398 else:
399 ebuild_path = ebuild_paths[0]
400
401 version = osutils.ReadFile(version_pin_path).strip()
402 new_ebuild_path = os.path.join(package_path,
403 '%s-%s-r1.ebuild' % (package, version))
404 os.rename(ebuild_path, new_ebuild_path)
405
406 result = UprevVersionedPackageResult()
407 result.add_result(version, [new_ebuild_path])
408 return result
409
410
Alex Klein87531182019-08-12 15:23:37 -0600411@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700412def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600413 """Uprev chrome and its related packages.
414
415 See: uprev_versioned_package.
416 """
417 # Determine the version from the refs (tags), i.e. the chrome versions are the
418 # tag names.
419 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
420
421 uprev_manager = uprev_lib.UprevChromeManager(
422 chrome_version, build_targets=build_targets, chroot=chroot)
David Burger37f48672019-09-18 17:07:56 -0600423 result = UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600424 # Start with chrome itself, as we can't do anything else unless chrome
425 # uprevs successfully.
426 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600427 return result
Alex Klein87531182019-08-12 15:23:37 -0600428
429 # With a successful chrome rev, also uprev related packages.
430 for package in constants.OTHER_CHROME_PACKAGES:
431 uprev_manager.uprev(package)
432
David Burger37f48672019-09-18 17:07:56 -0600433 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600434
435
Andrew Lamb9563a152019-12-04 11:42:18 -0700436def _generate_platform_c_files(replication_config, chroot):
437 """Generates platform C files from a platform JSON payload.
438
439 Args:
440 replication_config (replication_config_pb2.ReplicationConfig): A
441 ReplicationConfig that has already been run. If it produced a
442 build_config.json file, that file will be used to generate platform C
443 files. Otherwise, nothing will be generated.
444 chroot (chroot_lib.Chroot): The chroot to use to generate.
445
446 Returns:
447 A list of generated files.
448 """
449 # Generate the platform C files from the build config. Note that it would be
450 # more intuitive to generate the platform C files from the platform config;
451 # however, cros_config_schema does not allow this, because the platform config
452 # payload is not always valid input. For example, if a property is both
453 # 'required' and 'build-only', it will fail schema validation. Thus, use the
454 # build config, and use '-f' to filter.
455 build_config_path = [
456 rule.destination_path
457 for rule in replication_config.file_replication_rules
458 if rule.destination_path.endswith('build_config.json')
459 ]
460
461 if not build_config_path:
462 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700463 'No build_config.json found, will not generate platform C files. '
464 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700465 return []
466
467 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700468 raise ValueError('Expected at most one build_config.json destination path. '
469 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700470
471 build_config_path = build_config_path[0]
472
473 # Paths to the build_config.json and dir to output C files to, in the
474 # chroot.
475 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
476 build_config_path)
477 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
478 os.path.dirname(build_config_path))
479
480 command = [
481 'cros_config_schema', '-m', build_config_chroot_path, '-g',
482 generated_output_chroot_dir, '-f', '"TRUE"'
483 ]
484
485 cros_build_lib.run(
486 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
487
488 # A relative (to the source root) path to the generated C files.
489 generated_output_dir = os.path.dirname(build_config_path)
490 generated_files = []
491 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
492 for f in expected_c_files:
493 if os.path.exists(
494 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
495 generated_files.append(os.path.join(generated_output_dir, f))
496
497 if len(expected_c_files) != len(generated_files):
498 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
499
500 return generated_files
501
502
Andrew Lambe836f222019-12-09 12:27:38 -0700503def _get_private_overlay_package_root(ref, package):
504 """Returns the absolute path to the root of a given private overlay.
505
506 Args:
507 ref (uprev_lib.GitRef): GitRef for the private overlay.
508 package (str): Path to the package in the overlay.
509 """
510 # There might be a cleaner way to map from package -> path within the source
511 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700512 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700513 match = re.match(private_overlay_ref_pattern, ref.path)
514 if not match:
515 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
516 (private_overlay_ref_pattern, ref))
517
518 overlay = match.group(1)
519
520 return os.path.join(constants.SOURCE_ROOT,
521 'src/private-overlays/overlay-%s-private' % overlay,
522 package)
523
524
Andrew Lambea9a8a22019-12-12 14:03:43 -0700525@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
526def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700527 """Replicate a private cros_config change to the corresponding public config.
528
Alex Kleinad6b48a2020-01-08 16:57:41 -0700529 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700530 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700531 package = 'chromeos-base/chromeos-config-bsp'
532
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700533 if len(refs) != 1:
534 raise ValueError('Expected exactly one ref, actual %s' % refs)
535
536 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700537 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700538 replication_config_path = os.path.join(package_root,
539 'replication_config.jsonpb')
540
541 try:
542 replication_config = json_format.Parse(
543 osutils.ReadFile(replication_config_path),
544 replication_config_pb2.ReplicationConfig())
545 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700546 raise ValueError(
547 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700548
549 replication_lib.Replicate(replication_config)
550
551 modified_files = [
552 rule.destination_path
553 for rule in replication_config.file_replication_rules
554 ]
555
Andrew Lamb9563a152019-12-04 11:42:18 -0700556 # The generated platform C files are not easily filtered by replication rules,
557 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
558 # files cannot. Therefore, replicate and filter the JSON payloads, and then
559 # generate filtered C files from the JSON payload.
560 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700561
562 # Use the private repo's commit hash as the new version.
563 new_private_version = refs[0].revision
564
Andrew Lamb988f4da2019-12-10 10:16:43 -0700565 # modified_files should contain only relative paths at this point, but the
566 # returned UprevVersionedPackageResult must contain only absolute paths.
567 for i, modified_file in enumerate(modified_files):
568 assert not os.path.isabs(modified_file)
569 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
570
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700571 return UprevVersionedPackageResult().add_result(new_private_version,
572 modified_files)
573
574
Alex Kleinbbef2b32019-08-27 10:38:50 -0600575def get_best_visible(atom, build_target=None):
576 """Returns the best visible CPV for the given atom.
577
578 Args:
579 atom (str): The atom to look up.
580 build_target (build_target_util.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600581 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700582
583 Returns:
584 portage_util.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600585 """
David Burger1e0fe232019-07-01 14:52:07 -0600586 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600587
588 board = build_target.name if build_target else None
589 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600590
591
Alex Klein149fd3b2019-12-16 16:01:05 -0700592def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600593 """Check if a prebuilt exists.
594
595 Args:
596 atom (str): The package whose prebuilt is being queried.
597 build_target (build_target_util.BuildTarget): The build target whose
598 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700599 useflags: Any additional USE flags that should be set. May be a string
600 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700601
602 Returns:
603 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600604 """
605 assert atom
606
607 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700608 extra_env = None
609 if useflags:
610 new_flags = useflags
611 if not isinstance(useflags, six.string_types):
612 new_flags = ' '.join(useflags)
613
614 existing = os.environ.get('USE', '')
615 final_flags = '%s %s' % (existing, new_flags)
616 extra_env = {'USE': final_flags.strip()}
617 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600618
619
David Burger0f9dd4e2019-10-08 12:33:42 -0600620def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600621 """Check if |build_target| builds |atom| (has it in its depgraph)."""
622 cros_build_lib.AssertInsideChroot()
623
Chris McDonalda22b74f2019-11-22 13:55:06 -0700624 graph, _sdk_graph = dependency.GetBuildDependency(build_target.name, packages)
Alex Klein36b117f2019-09-30 15:13:46 -0600625 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600626
627
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600628def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600629 """Returns the current Chrome version for the board (or in buildroot).
630
631 Args:
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600632 build_target (build_target_util.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700633
634 Returns:
635 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600636 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600637 # TODO(crbug/1019770): Long term we should not need the try/catch here once
638 # the builds function above only returns True for chrome when
639 # determine_chrome_version will succeed.
640 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700641 cpv = portage_util.PortageqBestVisible(
642 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600643 except cros_build_lib.RunCommandError as e:
644 # Return None because portage failed when trying to determine the chrome
645 # version.
646 logging.warning('Caught exception in determine_chrome_package: %s', e)
647 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600648 # Something like 78.0.3877.4_rc -> 78.0.3877.4
649 return cpv.version_no_rev.partition('_')[0]
650
651
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600652def determine_android_package(board):
653 """Returns the active Android container package in use by the board.
654
655 Args:
656 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700657
658 Returns:
659 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600660 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600661 try:
662 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600663 except cros_build_lib.RunCommandError as e:
664 # Return None because a command (likely portage) failed when trying to
665 # determine the package.
666 logging.warning('Caught exception in determine_android_package: %s', e)
667 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600668
Alex Kleinad6b48a2020-01-08 16:57:41 -0700669 # We assume there is only one Android package in the depgraph.
670 for package in packages:
671 if package.startswith('chromeos-base/android-container-') or \
672 package.startswith('chromeos-base/android-vm-'):
673 return package
674 return None
675
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600676
677def determine_android_version(boards=None):
678 """Determine the current Android version in buildroot now and return it.
679
680 This uses the typical portage logic to determine which version of Android
681 is active right now in the buildroot.
682
683 Args:
684 boards: List of boards to check version of.
685
686 Returns:
687 The Android build ID of the container for the boards.
688
689 Raises:
690 NoAndroidVersionError: if no unique Android version can be determined.
691 """
692 if not boards:
693 return None
694 # Verify that all boards have the same version.
695 version = None
696 for board in boards:
697 package = determine_android_package(board)
698 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600699 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600700 cpv = portage_util.SplitCPV(package)
701 if not cpv:
702 raise NoAndroidVersionError(
703 'Android version could not be determined for %s' % board)
704 if not version:
705 version = cpv.version_no_rev
706 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700707 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
708 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600709 return version
710
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700711
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600712def determine_android_branch(board):
713 """Returns the Android branch in use by the active container ebuild."""
714 try:
715 android_package = determine_android_package(board)
716 except cros_build_lib.RunCommandError:
717 raise NoAndroidBranchError(
718 'Android branch could not be determined for %s' % board)
719 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600720 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600721 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
722 # We assume all targets pull from the same branch and that we always
723 # have an ARM_TARGET, ARM_USERDEBUG_TARGET, or an X86_USERDEBUG_TARGET.
724 targets = ['ARM_TARGET', 'ARM_USERDEBUG_TARGET', 'X86_USERDEBUG_TARGET']
725 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
726 for target in targets:
727 if target in ebuild_content:
728 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
729 if branch is not None:
730 return branch.group(1)
731 raise NoAndroidBranchError(
732 'Android branch could not be determined for %s (ebuild empty?)' % board)
733
734
735def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600736 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600737 try:
738 android_package = determine_android_package(board)
739 except cros_build_lib.RunCommandError:
740 raise NoAndroidTargetError(
741 'Android Target could not be determined for %s' % board)
742 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600743 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600744 if android_package.startswith('chromeos-base/android-vm-'):
745 return 'bertha'
746 elif android_package.startswith('chromeos-base/android-container-'):
747 return 'cheets'
748
749 raise NoAndroidTargetError(
750 'Android Target cannot be determined for the package: %s' %
751 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600752
753
754def determine_platform_version():
755 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600756 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600757 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
758 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600759
760
761def determine_milestone_version():
762 """Returns the platform version from the source root."""
763 # Milestone version is something like '79'.
764 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
765 return version.chrome_branch
766
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700767
Michael Mortensen009cb662019-10-21 11:38:43 -0600768def determine_full_version():
769 """Returns the full version from the source root."""
770 # Full version is something like 'R79-12575.0.0'.
771 milestone_version = determine_milestone_version()
772 platform_version = determine_platform_version()
773 full_version = ('R%s-%s' % (milestone_version, platform_version))
774 return full_version