blob: 50ddf61e8d3f37e0962af60ac10a3688136ca560 [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')
Trent Begin6daa8702020-01-29 14:58:12 -0700365def uprev_sludge(build_targets, refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700366 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
367
368 See: uprev_versioned_package.
369 """
Trent Begin6daa8702020-01-29 14:58:12 -0700370 # Unused by uprev_sludge
371 del build_targets, refs
372
Trent Begin315d9d92019-12-03 21:55:53 -0700373 package = 'chromeos-dtc-vm'
374 path = os.path.join('src', 'private-overlays', 'project-wilco-private',
375 'chromeos-base', package)
376 package_path = os.path.join(constants.SOURCE_ROOT, path)
377 version_pin_path = os.path.join(constants.SOURCE_ROOT, path, 'VERSION-PIN')
378
Trent Begin6daa8702020-01-29 14:58:12 -0700379 return uprev_ebuild_from_pin(package_path, version_pin_path, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700380
381
Trent Begin6daa8702020-01-29 14:58:12 -0700382def uprev_ebuild_from_pin(package_path, version_pin_path, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700383 """Changes the package ebuild's version to match the version pin file.
384
385 Args:
386 package_path: The path of the package relative to the src root. This path
387 should contain a single ebuild with the same name as the package.
388 version_pin_path: The path of the version_pin file that contains only only
389 a version string. The ebuild's version will be directly set to this
390 number.
Trent Begin6daa8702020-01-29 14:58:12 -0700391 chroot (chroot_lib.Chroot): specify a chroot to enter.
Trent Begin315d9d92019-12-03 21:55:53 -0700392
393 Returns:
394 UprevVersionedPackageResult: The result.
395 """
396 package = os.path.basename(package_path)
397 ebuild_paths = list(portage_util.EBuild.List(package_path))
398 if not ebuild_paths:
399 raise UprevError('No ebuilds found for %s' % package)
400 elif len(ebuild_paths) > 1:
401 raise UprevError('Multiple ebuilds found for %s' % package)
402 else:
403 ebuild_path = ebuild_paths[0]
404
405 version = osutils.ReadFile(version_pin_path).strip()
406 new_ebuild_path = os.path.join(package_path,
407 '%s-%s-r1.ebuild' % (package, version))
408 os.rename(ebuild_path, new_ebuild_path)
409
Trent Begin6daa8702020-01-29 14:58:12 -0700410 try:
411 portage_util.UpdateEbuildManifest(new_ebuild_path, chroot=chroot)
412 except cros_build_lib.RunCommandError as e:
413 raise UprevError(
414 'Unable to update manifest for %s: %s' % (package, e.stderr))
415
Trent Begin315d9d92019-12-03 21:55:53 -0700416 result = UprevVersionedPackageResult()
Trent Begin61ddc0e2020-01-27 15:42:16 -0700417 result.add_result(version, [new_ebuild_path, ebuild_path])
Trent Begin315d9d92019-12-03 21:55:53 -0700418 return result
419
420
Alex Klein87531182019-08-12 15:23:37 -0600421@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700422def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600423 """Uprev chrome and its related packages.
424
425 See: uprev_versioned_package.
426 """
427 # Determine the version from the refs (tags), i.e. the chrome versions are the
428 # tag names.
429 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
430
431 uprev_manager = uprev_lib.UprevChromeManager(
432 chrome_version, build_targets=build_targets, chroot=chroot)
David Burger37f48672019-09-18 17:07:56 -0600433 result = UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600434 # Start with chrome itself, as we can't do anything else unless chrome
435 # uprevs successfully.
436 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600437 return result
Alex Klein87531182019-08-12 15:23:37 -0600438
439 # With a successful chrome rev, also uprev related packages.
440 for package in constants.OTHER_CHROME_PACKAGES:
441 uprev_manager.uprev(package)
442
David Burger37f48672019-09-18 17:07:56 -0600443 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600444
445
Andrew Lamb9563a152019-12-04 11:42:18 -0700446def _generate_platform_c_files(replication_config, chroot):
447 """Generates platform C files from a platform JSON payload.
448
449 Args:
450 replication_config (replication_config_pb2.ReplicationConfig): A
451 ReplicationConfig that has already been run. If it produced a
452 build_config.json file, that file will be used to generate platform C
453 files. Otherwise, nothing will be generated.
454 chroot (chroot_lib.Chroot): The chroot to use to generate.
455
456 Returns:
457 A list of generated files.
458 """
459 # Generate the platform C files from the build config. Note that it would be
460 # more intuitive to generate the platform C files from the platform config;
461 # however, cros_config_schema does not allow this, because the platform config
462 # payload is not always valid input. For example, if a property is both
463 # 'required' and 'build-only', it will fail schema validation. Thus, use the
464 # build config, and use '-f' to filter.
465 build_config_path = [
466 rule.destination_path
467 for rule in replication_config.file_replication_rules
468 if rule.destination_path.endswith('build_config.json')
469 ]
470
471 if not build_config_path:
472 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700473 'No build_config.json found, will not generate platform C files. '
474 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700475 return []
476
477 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700478 raise ValueError('Expected at most one build_config.json destination path. '
479 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700480
481 build_config_path = build_config_path[0]
482
483 # Paths to the build_config.json and dir to output C files to, in the
484 # chroot.
485 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
486 build_config_path)
487 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
488 os.path.dirname(build_config_path))
489
490 command = [
491 'cros_config_schema', '-m', build_config_chroot_path, '-g',
492 generated_output_chroot_dir, '-f', '"TRUE"'
493 ]
494
495 cros_build_lib.run(
496 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
497
498 # A relative (to the source root) path to the generated C files.
499 generated_output_dir = os.path.dirname(build_config_path)
500 generated_files = []
501 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
502 for f in expected_c_files:
503 if os.path.exists(
504 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
505 generated_files.append(os.path.join(generated_output_dir, f))
506
507 if len(expected_c_files) != len(generated_files):
508 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
509
510 return generated_files
511
512
Andrew Lambe836f222019-12-09 12:27:38 -0700513def _get_private_overlay_package_root(ref, package):
514 """Returns the absolute path to the root of a given private overlay.
515
516 Args:
517 ref (uprev_lib.GitRef): GitRef for the private overlay.
518 package (str): Path to the package in the overlay.
519 """
520 # There might be a cleaner way to map from package -> path within the source
521 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700522 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700523 match = re.match(private_overlay_ref_pattern, ref.path)
524 if not match:
525 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
526 (private_overlay_ref_pattern, ref))
527
528 overlay = match.group(1)
529
530 return os.path.join(constants.SOURCE_ROOT,
531 'src/private-overlays/overlay-%s-private' % overlay,
532 package)
533
534
Andrew Lambea9a8a22019-12-12 14:03:43 -0700535@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
536def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700537 """Replicate a private cros_config change to the corresponding public config.
538
Alex Kleinad6b48a2020-01-08 16:57:41 -0700539 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700540 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700541 package = 'chromeos-base/chromeos-config-bsp'
542
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700543 if len(refs) != 1:
544 raise ValueError('Expected exactly one ref, actual %s' % refs)
545
546 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700547 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700548 replication_config_path = os.path.join(package_root,
549 'replication_config.jsonpb')
550
551 try:
552 replication_config = json_format.Parse(
553 osutils.ReadFile(replication_config_path),
554 replication_config_pb2.ReplicationConfig())
555 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700556 raise ValueError(
557 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700558
559 replication_lib.Replicate(replication_config)
560
561 modified_files = [
562 rule.destination_path
563 for rule in replication_config.file_replication_rules
564 ]
565
Andrew Lamb9563a152019-12-04 11:42:18 -0700566 # The generated platform C files are not easily filtered by replication rules,
567 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
568 # files cannot. Therefore, replicate and filter the JSON payloads, and then
569 # generate filtered C files from the JSON payload.
570 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700571
572 # Use the private repo's commit hash as the new version.
573 new_private_version = refs[0].revision
574
Andrew Lamb988f4da2019-12-10 10:16:43 -0700575 # modified_files should contain only relative paths at this point, but the
576 # returned UprevVersionedPackageResult must contain only absolute paths.
577 for i, modified_file in enumerate(modified_files):
578 assert not os.path.isabs(modified_file)
579 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
580
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700581 return UprevVersionedPackageResult().add_result(new_private_version,
582 modified_files)
583
584
Alex Kleinbbef2b32019-08-27 10:38:50 -0600585def get_best_visible(atom, build_target=None):
586 """Returns the best visible CPV for the given atom.
587
588 Args:
589 atom (str): The atom to look up.
590 build_target (build_target_util.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600591 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700592
593 Returns:
594 portage_util.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600595 """
David Burger1e0fe232019-07-01 14:52:07 -0600596 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600597
598 board = build_target.name if build_target else None
599 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600600
601
Alex Klein149fd3b2019-12-16 16:01:05 -0700602def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600603 """Check if a prebuilt exists.
604
605 Args:
606 atom (str): The package whose prebuilt is being queried.
607 build_target (build_target_util.BuildTarget): The build target whose
608 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700609 useflags: Any additional USE flags that should be set. May be a string
610 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700611
612 Returns:
613 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600614 """
615 assert atom
616
617 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700618 extra_env = None
619 if useflags:
620 new_flags = useflags
621 if not isinstance(useflags, six.string_types):
622 new_flags = ' '.join(useflags)
623
624 existing = os.environ.get('USE', '')
625 final_flags = '%s %s' % (existing, new_flags)
626 extra_env = {'USE': final_flags.strip()}
627 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600628
629
David Burger0f9dd4e2019-10-08 12:33:42 -0600630def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600631 """Check if |build_target| builds |atom| (has it in its depgraph)."""
632 cros_build_lib.AssertInsideChroot()
633
Chris McDonalda22b74f2019-11-22 13:55:06 -0700634 graph, _sdk_graph = dependency.GetBuildDependency(build_target.name, packages)
Alex Klein36b117f2019-09-30 15:13:46 -0600635 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600636
637
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600638def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600639 """Returns the current Chrome version for the board (or in buildroot).
640
641 Args:
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600642 build_target (build_target_util.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700643
644 Returns:
645 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600646 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600647 # TODO(crbug/1019770): Long term we should not need the try/catch here once
648 # the builds function above only returns True for chrome when
649 # determine_chrome_version will succeed.
650 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700651 cpv = portage_util.PortageqBestVisible(
652 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600653 except cros_build_lib.RunCommandError as e:
654 # Return None because portage failed when trying to determine the chrome
655 # version.
656 logging.warning('Caught exception in determine_chrome_package: %s', e)
657 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600658 # Something like 78.0.3877.4_rc -> 78.0.3877.4
659 return cpv.version_no_rev.partition('_')[0]
660
661
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600662def determine_android_package(board):
663 """Returns the active Android container package in use by the board.
664
665 Args:
666 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700667
668 Returns:
669 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600670 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600671 try:
672 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600673 except cros_build_lib.RunCommandError as e:
674 # Return None because a command (likely portage) failed when trying to
675 # determine the package.
676 logging.warning('Caught exception in determine_android_package: %s', e)
677 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600678
Alex Kleinad6b48a2020-01-08 16:57:41 -0700679 # We assume there is only one Android package in the depgraph.
680 for package in packages:
681 if package.startswith('chromeos-base/android-container-') or \
682 package.startswith('chromeos-base/android-vm-'):
683 return package
684 return None
685
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600686
687def determine_android_version(boards=None):
688 """Determine the current Android version in buildroot now and return it.
689
690 This uses the typical portage logic to determine which version of Android
691 is active right now in the buildroot.
692
693 Args:
694 boards: List of boards to check version of.
695
696 Returns:
697 The Android build ID of the container for the boards.
698
699 Raises:
700 NoAndroidVersionError: if no unique Android version can be determined.
701 """
702 if not boards:
703 return None
704 # Verify that all boards have the same version.
705 version = None
706 for board in boards:
707 package = determine_android_package(board)
708 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600709 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600710 cpv = portage_util.SplitCPV(package)
711 if not cpv:
712 raise NoAndroidVersionError(
713 'Android version could not be determined for %s' % board)
714 if not version:
715 version = cpv.version_no_rev
716 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700717 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
718 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600719 return version
720
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700721
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600722def determine_android_branch(board):
723 """Returns the Android branch in use by the active container ebuild."""
724 try:
725 android_package = determine_android_package(board)
726 except cros_build_lib.RunCommandError:
727 raise NoAndroidBranchError(
728 'Android branch could not be determined for %s' % board)
729 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600730 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600731 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
732 # We assume all targets pull from the same branch and that we always
733 # have an ARM_TARGET, ARM_USERDEBUG_TARGET, or an X86_USERDEBUG_TARGET.
734 targets = ['ARM_TARGET', 'ARM_USERDEBUG_TARGET', 'X86_USERDEBUG_TARGET']
735 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
736 for target in targets:
737 if target in ebuild_content:
738 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
739 if branch is not None:
740 return branch.group(1)
741 raise NoAndroidBranchError(
742 'Android branch could not be determined for %s (ebuild empty?)' % board)
743
744
745def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600746 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600747 try:
748 android_package = determine_android_package(board)
749 except cros_build_lib.RunCommandError:
750 raise NoAndroidTargetError(
751 'Android Target could not be determined for %s' % board)
752 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600753 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600754 if android_package.startswith('chromeos-base/android-vm-'):
755 return 'bertha'
756 elif android_package.startswith('chromeos-base/android-container-'):
757 return 'cheets'
758
759 raise NoAndroidTargetError(
760 'Android Target cannot be determined for the package: %s' %
761 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600762
763
764def determine_platform_version():
765 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600766 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600767 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
768 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600769
770
771def determine_milestone_version():
772 """Returns the platform version from the source root."""
773 # Milestone version is something like '79'.
774 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
775 return version.chrome_branch
776
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700777
Michael Mortensen009cb662019-10-21 11:38:43 -0600778def determine_full_version():
779 """Returns the full version from the source root."""
780 # Full version is something like 'R79-12575.0.0'.
781 milestone_version = determine_milestone_version()
782 platform_version = determine_platform_version()
783 full_version = ('R%s-%s' % (milestone_version, platform_version))
784 return full_version