blob: 2797460af54257f32e46a4c4e63670739d1c31a5 [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
Trent Beginec16cf32020-02-24 11:26:02 -070029from chromite.lib import path_util
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 Kleineb77ffa2019-05-28 14:47:44 -060033
Alex Klein36b117f2019-09-30 15:13:46 -060034if cros_build_lib.IsInsideChroot():
35 from chromite.service import dependency
36
Alex Klein87531182019-08-12 15:23:37 -060037# Registered handlers for uprevving versioned packages.
38_UPREV_FUNCS = {}
39
Alex Kleineb77ffa2019-05-28 14:47:44 -060040
41class Error(Exception):
42 """Module's base error class."""
43
44
Alex Klein4de25e82019-08-05 15:58:39 -060045class UnknownPackageError(Error):
46 """Uprev attempted for a package without a registered handler."""
47
48
Alex Kleineb77ffa2019-05-28 14:47:44 -060049class UprevError(Error):
50 """An error occurred while uprevving packages."""
51
52
Michael Mortensenb70e8a82019-10-10 18:43:41 -060053class NoAndroidVersionError(Error):
54 """An error occurred while trying to determine the android version."""
55
56
57class NoAndroidBranchError(Error):
58 """An error occurred while trying to determine the android branch."""
59
60
61class NoAndroidTargetError(Error):
62 """An error occurred while trying to determine the android target."""
63
64
Alex Klein4de25e82019-08-05 15:58:39 -060065class AndroidIsPinnedUprevError(UprevError):
66 """Raised when we try to uprev while Android is pinned."""
67
68 def __init__(self, new_android_atom):
69 """Initialize a AndroidIsPinnedUprevError.
70
71 Args:
72 new_android_atom: The Android atom that we failed to
73 uprev to, due to Android being pinned.
74 """
75 assert new_android_atom
76 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
77 new_android_atom)
78 super(AndroidIsPinnedUprevError, self).__init__(msg)
79 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060080
81
Yaakov Shaul1eafe832019-09-10 16:50:26 -060082class EbuildManifestError(Error):
83 """Error when running ebuild manifest."""
84
85
Andrew Lamb9563a152019-12-04 11:42:18 -070086class GeneratedCrosConfigFilesError(Error):
87 """Error when cros_config_schema does not produce expected files"""
88
89 def __init__(self, expected_files, found_files):
90 msg = ('Expected to find generated C files: %s. Actually found: %s' %
91 (expected_files, found_files))
92 super(GeneratedCrosConfigFilesError, self).__init__(msg)
93
Alex Klein7a3a7dd2020-01-08 16:44:38 -070094
Yaakov Shaul730814a2019-09-10 13:58:25 -060095UprevVersionedPackageModifications = collections.namedtuple(
96 'UprevVersionedPackageModifications', ('new_version', 'files'))
Alex Klein34afcbc2019-08-22 16:14:31 -060097
Yaakov Shaul730814a2019-09-10 13:58:25 -060098
99class UprevVersionedPackageResult(object):
100 """Data object for uprev_versioned_package."""
101
102 def __init__(self):
103 self.modified = []
104
105 def add_result(self, new_version, modified_files):
106 """Adds version/ebuilds tuple to result.
107
108 Args:
109 new_version: New version number of package.
110 modified_files: List of files modified for the given version.
111 """
112 result = UprevVersionedPackageModifications(new_version, modified_files)
113 self.modified.append(result)
114 return self
Alex Klein34afcbc2019-08-22 16:14:31 -0600115
116 @property
117 def uprevved(self):
Yaakov Shaul730814a2019-09-10 13:58:25 -0600118 return bool(self.modified)
Alex Klein34afcbc2019-08-22 16:14:31 -0600119
120
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600121def patch_ebuild_vars(ebuild_path, variables):
122 """Updates variables in ebuild.
123
124 Use this function rather than portage_util.EBuild.UpdateEBuild when you
125 want to preserve the variable position and quotes within the ebuild.
126
127 Args:
128 ebuild_path: The path of the ebuild.
129 variables: Dictionary of variables to update in ebuild.
130 """
131 try:
132 for line in fileinput.input(ebuild_path, inplace=1):
133 varname, eq, _ = line.partition('=')
134 if eq == '=' and varname.strip() in variables:
135 value = variables[varname]
136 sys.stdout.write('%s="%s"\n' % (varname, value))
137 else:
138 sys.stdout.write(line)
139 finally:
140 fileinput.close()
141
142
Alex Klein87531182019-08-12 15:23:37 -0600143def uprevs_versioned_package(package):
144 """Decorator to register package uprev handlers."""
145 assert package
146
147 def register(func):
148 """Registers |func| as a handler for |package|."""
149 _UPREV_FUNCS[package] = func
150
151 @functools.wraps(func)
152 def pass_through(*args, **kwargs):
153 return func(*args, **kwargs)
154
155 return pass_through
156
157 return register
158
159
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700160def uprev_android(tracking_branch,
161 android_package,
162 android_build_branch,
163 chroot,
164 build_targets=None,
165 android_version=None,
Alex Klein4de25e82019-08-05 15:58:39 -0600166 android_gts_build_branch=None):
167 """Returns the portage atom for the revved Android ebuild - see man emerge."""
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700168 command = [
169 'cros_mark_android_as_stable',
170 '--tracking_branch=%s' % tracking_branch,
171 '--android_package=%s' % android_package,
172 '--android_build_branch=%s' % android_build_branch,
173 ]
Alex Klein4de25e82019-08-05 15:58:39 -0600174 if build_targets:
175 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
176 if android_version:
177 command.append('--force_version=%s' % android_version)
178 if android_gts_build_branch:
179 command.append('--android_gts_build_branch=%s' % android_gts_build_branch)
180
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700181 result = cros_build_lib.run(
182 command,
183 stdout=True,
184 enter_chroot=True,
Mike Frysinger88d96362020-02-14 19:05:45 -0500185 encoding='utf-8',
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700186 chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600187
Mike Frysinger88d96362020-02-14 19:05:45 -0500188 portage_atom_string = result.stdout.strip()
189 android_atom = None
190 if portage_atom_string:
191 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
Alex Klein4de25e82019-08-05 15:58:39 -0600192 if not android_atom:
193 logging.info('Found nothing to rev.')
194 return None
195
196 for target in build_targets or []:
197 # Sanity check: We should always be able to merge the version of
198 # Android we just unmasked.
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700199 command = ['emerge-%s' % target.name, '-p', '--quiet', '=%s' % android_atom]
Alex Klein4de25e82019-08-05 15:58:39 -0600200 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700201 cros_build_lib.run(
202 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
Alex Klein4de25e82019-08-05 15:58:39 -0600203 except cros_build_lib.RunCommandError:
204 logging.error(
205 'Cannot emerge-%s =%s\nIs Android pinned to an older '
206 'version?', target, android_atom)
207 raise AndroidIsPinnedUprevError(android_atom)
208
209 return android_atom
210
211
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700212def uprev_build_targets(build_targets,
213 overlay_type,
214 chroot=None,
Alex Kleineb77ffa2019-05-28 14:47:44 -0600215 output_dir=None):
216 """Uprev the set provided build targets, or all if not specified.
217
218 Args:
219 build_targets (list[build_target_util.BuildTarget]|None): The build targets
220 whose overlays should be uprevved, empty or None for all.
221 overlay_type (str): One of the valid overlay types except None (see
222 constants.VALID_OVERLAYS).
223 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
224 output_dir (str|None): The path to optionally dump result files.
225 """
226 # Need a valid overlay, but exclude None.
227 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
228
229 if build_targets:
230 overlays = portage_util.FindOverlaysForBoards(
231 overlay_type, boards=[t.name for t in build_targets])
232 else:
233 overlays = portage_util.FindOverlays(overlay_type)
234
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700235 return uprev_overlays(
236 overlays,
237 build_targets=build_targets,
238 chroot=chroot,
239 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600240
241
242def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
243 """Uprev the given overlays.
244
245 Args:
246 overlays (list[str]): The list of overlay paths.
247 build_targets (list[build_target_util.BuildTarget]|None): The build targets
248 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
249 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
250 output_dir (str|None): The path to optionally dump result files.
251
252 Returns:
253 list[str] - The paths to all of the modified ebuild files. This includes the
254 new files that were added (i.e. the new versions) and all of the removed
255 files (i.e. the old versions).
256 """
257 assert overlays
258
259 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
260
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700261 uprev_manager = uprev_lib.UprevOverlayManager(
262 overlays,
263 manifest,
264 build_targets=build_targets,
265 chroot=chroot,
266 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600267 uprev_manager.uprev()
268
269 return uprev_manager.modified_ebuilds
270
271
Alex Klein87531182019-08-12 15:23:37 -0600272def uprev_versioned_package(package, build_targets, refs, chroot):
273 """Call registered uprev handler function for the package.
274
275 Args:
276 package (portage_util.CPV): The package being uprevved.
277 build_targets (list[build_target_util.BuildTarget]): The build targets to
278 clean on a successful uprev.
279 refs (list[uprev_lib.GitRef]):
280 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
281
282 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600283 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600284 """
285 assert package
286
287 if package.cp not in _UPREV_FUNCS:
288 raise UnknownPackageError(
289 'Package "%s" does not have a registered handler.' % package.cp)
290
Andrew Lambea9a8a22019-12-12 14:03:43 -0700291 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
Alex Klein87531182019-08-12 15:23:37 -0600292
293
Evan Hernandezb51f1522019-08-15 11:29:40 -0600294# TODO(evanhernandez): Remove this. Only a quick hack for testing.
295@uprevs_versioned_package('sample/sample')
296def uprev_sample(*_args, **_kwargs):
297 """Mimics an uprev by changing files in sandbox repos.
298
299 See: uprev_versioned_package.
300 """
301 paths = [
302 os.path.join(constants.SOURCE_ROOT, 'infra/dummies', repo, 'sample.txt')
303 for repo in ('general-sandbox', 'merge-sandbox')
304 ]
305
Yaakov Shaul730814a2019-09-10 13:58:25 -0600306 return UprevVersionedPackageResult().add_result('1.2.3', paths)
Evan Hernandezb51f1522019-08-15 11:29:40 -0600307
308
Yaakov Shaul395ae832019-09-09 14:45:32 -0600309@uprevs_versioned_package('afdo/kernel-profiles')
310def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600311 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600312
313 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600314
315 Raises:
316 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600317 """
318 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
319 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
320
David Burger92485342019-09-10 17:52:45 -0600321 with open(path, 'r') as f:
322 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600323
Yaakov Shaul730814a2019-09-10 13:58:25 -0600324 result = UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600325 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600326 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
327 'sys-kernel', version)
328 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
329 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600330 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
331 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600332 afdo_profile_version = version_info['name']
Yaakov Shaulcb1cfc32019-09-16 13:51:19 -0600333 patch_ebuild_vars(ebuild_path,
334 dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600335
336 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600337 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400338 cros_build_lib.run(cmd, enter_chroot=True)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600339 except cros_build_lib.RunCommandError as e:
340 raise EbuildManifestError(
341 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600342 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600343
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600344 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600345
Yaakov Shaul730814a2019-09-10 13:58:25 -0600346 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
347
348 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600349
350
Trent Begin315d9d92019-12-03 21:55:53 -0700351@uprevs_versioned_package('chromeos-base/chromeos-dtc-vm')
Trent Begin6daa8702020-01-29 14:58:12 -0700352def uprev_sludge(build_targets, refs, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700353 """Updates sludge VM - chromeos-base/chromeos-dtc-vm.
354
355 See: uprev_versioned_package.
356 """
Trent Begin6daa8702020-01-29 14:58:12 -0700357 # Unused by uprev_sludge
358 del build_targets, refs
359
Trent Begin315d9d92019-12-03 21:55:53 -0700360 package = 'chromeos-dtc-vm'
361 path = os.path.join('src', 'private-overlays', 'project-wilco-private',
362 'chromeos-base', package)
363 package_path = os.path.join(constants.SOURCE_ROOT, path)
364 version_pin_path = os.path.join(constants.SOURCE_ROOT, path, 'VERSION-PIN')
365
Trent Begin6daa8702020-01-29 14:58:12 -0700366 return uprev_ebuild_from_pin(package_path, version_pin_path, chroot)
Trent Begin315d9d92019-12-03 21:55:53 -0700367
368
Trent Begin6daa8702020-01-29 14:58:12 -0700369def uprev_ebuild_from_pin(package_path, version_pin_path, chroot):
Trent Begin315d9d92019-12-03 21:55:53 -0700370 """Changes the package ebuild's version to match the version pin file.
371
372 Args:
373 package_path: The path of the package relative to the src root. This path
374 should contain a single ebuild with the same name as the package.
375 version_pin_path: The path of the version_pin file that contains only only
376 a version string. The ebuild's version will be directly set to this
377 number.
Trent Begin6daa8702020-01-29 14:58:12 -0700378 chroot (chroot_lib.Chroot): specify a chroot to enter.
Trent Begin315d9d92019-12-03 21:55:53 -0700379
380 Returns:
381 UprevVersionedPackageResult: The result.
382 """
383 package = os.path.basename(package_path)
384 ebuild_paths = list(portage_util.EBuild.List(package_path))
385 if not ebuild_paths:
386 raise UprevError('No ebuilds found for %s' % package)
387 elif len(ebuild_paths) > 1:
388 raise UprevError('Multiple ebuilds found for %s' % package)
389 else:
390 ebuild_path = ebuild_paths[0]
391
392 version = osutils.ReadFile(version_pin_path).strip()
393 new_ebuild_path = os.path.join(package_path,
394 '%s-%s-r1.ebuild' % (package, version))
395 os.rename(ebuild_path, new_ebuild_path)
396
Trent Begin6daa8702020-01-29 14:58:12 -0700397 try:
Trent Beginec16cf32020-02-24 11:26:02 -0700398 chroot_manifest_path = path_util.ToChrootPath(new_ebuild_path)
399 portage_util.UpdateEbuildManifest(chroot_manifest_path, chroot=chroot)
Trent Begin6daa8702020-01-29 14:58:12 -0700400 except cros_build_lib.RunCommandError as e:
401 raise UprevError(
402 'Unable to update manifest for %s: %s' % (package, e.stderr))
403
Trent Begin315d9d92019-12-03 21:55:53 -0700404 result = UprevVersionedPackageResult()
Trent Begin61ddc0e2020-01-27 15:42:16 -0700405 result.add_result(version, [new_ebuild_path, ebuild_path])
Trent Begin315d9d92019-12-03 21:55:53 -0700406 return result
407
408
Alex Klein87531182019-08-12 15:23:37 -0600409@uprevs_versioned_package(constants.CHROME_CP)
Andrew Lambea9a8a22019-12-12 14:03:43 -0700410def uprev_chrome(build_targets, refs, chroot):
Alex Klein87531182019-08-12 15:23:37 -0600411 """Uprev chrome and its related packages.
412
413 See: uprev_versioned_package.
414 """
415 # Determine the version from the refs (tags), i.e. the chrome versions are the
416 # tag names.
417 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
418
419 uprev_manager = uprev_lib.UprevChromeManager(
420 chrome_version, build_targets=build_targets, chroot=chroot)
David Burger37f48672019-09-18 17:07:56 -0600421 result = UprevVersionedPackageResult()
Alex Klein87531182019-08-12 15:23:37 -0600422 # Start with chrome itself, as we can't do anything else unless chrome
423 # uprevs successfully.
424 if not uprev_manager.uprev(constants.CHROME_CP):
David Burger37f48672019-09-18 17:07:56 -0600425 return result
Alex Klein87531182019-08-12 15:23:37 -0600426
427 # With a successful chrome rev, also uprev related packages.
428 for package in constants.OTHER_CHROME_PACKAGES:
429 uprev_manager.uprev(package)
430
David Burger37f48672019-09-18 17:07:56 -0600431 return result.add_result(chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600432
433
Andrew Lamb9563a152019-12-04 11:42:18 -0700434def _generate_platform_c_files(replication_config, chroot):
435 """Generates platform C files from a platform JSON payload.
436
437 Args:
438 replication_config (replication_config_pb2.ReplicationConfig): A
439 ReplicationConfig that has already been run. If it produced a
440 build_config.json file, that file will be used to generate platform C
441 files. Otherwise, nothing will be generated.
442 chroot (chroot_lib.Chroot): The chroot to use to generate.
443
444 Returns:
445 A list of generated files.
446 """
447 # Generate the platform C files from the build config. Note that it would be
448 # more intuitive to generate the platform C files from the platform config;
449 # however, cros_config_schema does not allow this, because the platform config
450 # payload is not always valid input. For example, if a property is both
451 # 'required' and 'build-only', it will fail schema validation. Thus, use the
452 # build config, and use '-f' to filter.
453 build_config_path = [
454 rule.destination_path
455 for rule in replication_config.file_replication_rules
456 if rule.destination_path.endswith('build_config.json')
457 ]
458
459 if not build_config_path:
460 logging.info(
Alex Kleinad6b48a2020-01-08 16:57:41 -0700461 'No build_config.json found, will not generate platform C files. '
462 'Replication config: %s', replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700463 return []
464
465 if len(build_config_path) > 1:
Alex Kleinad6b48a2020-01-08 16:57:41 -0700466 raise ValueError('Expected at most one build_config.json destination path. '
467 'Replication config: %s' % replication_config)
Andrew Lamb9563a152019-12-04 11:42:18 -0700468
469 build_config_path = build_config_path[0]
470
471 # Paths to the build_config.json and dir to output C files to, in the
472 # chroot.
473 build_config_chroot_path = os.path.join(constants.CHROOT_SOURCE_ROOT,
474 build_config_path)
475 generated_output_chroot_dir = os.path.join(constants.CHROOT_SOURCE_ROOT,
476 os.path.dirname(build_config_path))
477
478 command = [
479 'cros_config_schema', '-m', build_config_chroot_path, '-g',
480 generated_output_chroot_dir, '-f', '"TRUE"'
481 ]
482
483 cros_build_lib.run(
484 command, enter_chroot=True, chroot_args=chroot.get_enter_args())
485
486 # A relative (to the source root) path to the generated C files.
487 generated_output_dir = os.path.dirname(build_config_path)
488 generated_files = []
489 expected_c_files = ['config.c', 'ec_config.c', 'ec_config.h']
490 for f in expected_c_files:
491 if os.path.exists(
492 os.path.join(constants.SOURCE_ROOT, generated_output_dir, f)):
493 generated_files.append(os.path.join(generated_output_dir, f))
494
495 if len(expected_c_files) != len(generated_files):
496 raise GeneratedCrosConfigFilesError(expected_c_files, generated_files)
497
498 return generated_files
499
500
Andrew Lambe836f222019-12-09 12:27:38 -0700501def _get_private_overlay_package_root(ref, package):
502 """Returns the absolute path to the root of a given private overlay.
503
504 Args:
505 ref (uprev_lib.GitRef): GitRef for the private overlay.
506 package (str): Path to the package in the overlay.
507 """
508 # There might be a cleaner way to map from package -> path within the source
509 # tree. For now, just use string patterns.
Andrew Lamb4aa09912020-01-08 13:55:56 -0700510 private_overlay_ref_pattern = r'/chromeos\/overlays\/overlay-([\w-]+)-private'
Andrew Lambe836f222019-12-09 12:27:38 -0700511 match = re.match(private_overlay_ref_pattern, ref.path)
512 if not match:
513 raise ValueError('ref.path must match the pattern: %s. Actual ref: %s' %
514 (private_overlay_ref_pattern, ref))
515
516 overlay = match.group(1)
517
518 return os.path.join(constants.SOURCE_ROOT,
519 'src/private-overlays/overlay-%s-private' % overlay,
520 package)
521
522
Andrew Lambea9a8a22019-12-12 14:03:43 -0700523@uprevs_versioned_package('chromeos-base/chromeos-config-bsp')
524def replicate_private_config(_build_targets, refs, chroot):
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700525 """Replicate a private cros_config change to the corresponding public config.
526
Alex Kleinad6b48a2020-01-08 16:57:41 -0700527 See uprev_versioned_package for args
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700528 """
Andrew Lambea9a8a22019-12-12 14:03:43 -0700529 package = 'chromeos-base/chromeos-config-bsp'
530
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700531 if len(refs) != 1:
532 raise ValueError('Expected exactly one ref, actual %s' % refs)
533
534 # Expect a replication_config.jsonpb in the package root.
Andrew Lambe836f222019-12-09 12:27:38 -0700535 package_root = _get_private_overlay_package_root(refs[0], package)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700536 replication_config_path = os.path.join(package_root,
537 'replication_config.jsonpb')
538
539 try:
540 replication_config = json_format.Parse(
541 osutils.ReadFile(replication_config_path),
542 replication_config_pb2.ReplicationConfig())
543 except IOError:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700544 raise ValueError(
545 'Expected ReplicationConfig missing at %s' % replication_config_path)
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700546
547 replication_lib.Replicate(replication_config)
548
549 modified_files = [
550 rule.destination_path
551 for rule in replication_config.file_replication_rules
552 ]
553
Andrew Lamb9563a152019-12-04 11:42:18 -0700554 # The generated platform C files are not easily filtered by replication rules,
555 # i.e. JSON / proto filtering can be described by a FieldMask, arbitrary C
556 # files cannot. Therefore, replicate and filter the JSON payloads, and then
557 # generate filtered C files from the JSON payload.
558 modified_files.extend(_generate_platform_c_files(replication_config, chroot))
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700559
560 # Use the private repo's commit hash as the new version.
561 new_private_version = refs[0].revision
562
Andrew Lamb988f4da2019-12-10 10:16:43 -0700563 # modified_files should contain only relative paths at this point, but the
564 # returned UprevVersionedPackageResult must contain only absolute paths.
565 for i, modified_file in enumerate(modified_files):
566 assert not os.path.isabs(modified_file)
567 modified_files[i] = os.path.join(constants.SOURCE_ROOT, modified_file)
568
Andrew Lamb2bde9e42019-11-04 13:24:09 -0700569 return UprevVersionedPackageResult().add_result(new_private_version,
570 modified_files)
571
572
Alex Kleinbbef2b32019-08-27 10:38:50 -0600573def get_best_visible(atom, build_target=None):
574 """Returns the best visible CPV for the given atom.
575
576 Args:
577 atom (str): The atom to look up.
578 build_target (build_target_util.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600579 sysroot should be searched, or the SDK if not provided.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700580
581 Returns:
582 portage_util.CPV|None: The best visible package.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600583 """
David Burger1e0fe232019-07-01 14:52:07 -0600584 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600585
586 board = build_target.name if build_target else None
587 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600588
589
Alex Klein149fd3b2019-12-16 16:01:05 -0700590def has_prebuilt(atom, build_target=None, useflags=None):
Alex Kleinda39c6d2019-09-16 14:36:36 -0600591 """Check if a prebuilt exists.
592
593 Args:
594 atom (str): The package whose prebuilt is being queried.
595 build_target (build_target_util.BuildTarget): The build target whose
596 sysroot should be searched, or the SDK if not provided.
Alex Klein149fd3b2019-12-16 16:01:05 -0700597 useflags: Any additional USE flags that should be set. May be a string
598 of properly formatted USE flags, or an iterable of individual flags.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700599
600 Returns:
601 bool: True iff there is an available prebuilt, False otherwise.
Alex Kleinda39c6d2019-09-16 14:36:36 -0600602 """
603 assert atom
604
605 board = build_target.name if build_target else None
Alex Klein149fd3b2019-12-16 16:01:05 -0700606 extra_env = None
607 if useflags:
608 new_flags = useflags
609 if not isinstance(useflags, six.string_types):
610 new_flags = ' '.join(useflags)
611
612 existing = os.environ.get('USE', '')
613 final_flags = '%s %s' % (existing, new_flags)
614 extra_env = {'USE': final_flags.strip()}
615 return portage_util.HasPrebuilt(atom, board=board, extra_env=extra_env)
Alex Klein36b117f2019-09-30 15:13:46 -0600616
617
David Burger0f9dd4e2019-10-08 12:33:42 -0600618def builds(atom, build_target, packages=None):
Alex Klein36b117f2019-09-30 15:13:46 -0600619 """Check if |build_target| builds |atom| (has it in its depgraph)."""
620 cros_build_lib.AssertInsideChroot()
621
Chris McDonalda22b74f2019-11-22 13:55:06 -0700622 graph, _sdk_graph = dependency.GetBuildDependency(build_target.name, packages)
Alex Klein36b117f2019-09-30 15:13:46 -0600623 return any(atom in package for package in graph['package_deps'])
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600624
625
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600626def determine_chrome_version(build_target):
Michael Mortensenc2615b72019-10-15 08:12:24 -0600627 """Returns the current Chrome version for the board (or in buildroot).
628
629 Args:
Michael Mortensenb51a1f02019-10-16 13:28:20 -0600630 build_target (build_target_util.BuildTarget): The board build target.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700631
632 Returns:
633 str|None: The chrome version if available.
Michael Mortensenc2615b72019-10-15 08:12:24 -0600634 """
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600635 # TODO(crbug/1019770): Long term we should not need the try/catch here once
636 # the builds function above only returns True for chrome when
637 # determine_chrome_version will succeed.
638 try:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700639 cpv = portage_util.PortageqBestVisible(
640 constants.CHROME_CP, build_target.name, cwd=constants.SOURCE_ROOT)
Michael Mortensen9fe740c2019-10-29 14:42:48 -0600641 except cros_build_lib.RunCommandError as e:
642 # Return None because portage failed when trying to determine the chrome
643 # version.
644 logging.warning('Caught exception in determine_chrome_package: %s', e)
645 return None
Michael Mortensenc2615b72019-10-15 08:12:24 -0600646 # Something like 78.0.3877.4_rc -> 78.0.3877.4
647 return cpv.version_no_rev.partition('_')[0]
648
649
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600650def determine_android_package(board):
651 """Returns the active Android container package in use by the board.
652
653 Args:
654 board: The board name this is specific to.
Alex Kleinad6b48a2020-01-08 16:57:41 -0700655
656 Returns:
657 str|None: The android package string if there is one.
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600658 """
Michael Mortensene0f4b542019-10-24 15:30:23 -0600659 try:
660 packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
Michael Mortensene0f4b542019-10-24 15:30:23 -0600661 except cros_build_lib.RunCommandError as e:
662 # Return None because a command (likely portage) failed when trying to
663 # determine the package.
664 logging.warning('Caught exception in determine_android_package: %s', e)
665 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600666
Alex Kleinad6b48a2020-01-08 16:57:41 -0700667 # We assume there is only one Android package in the depgraph.
668 for package in packages:
669 if package.startswith('chromeos-base/android-container-') or \
670 package.startswith('chromeos-base/android-vm-'):
671 return package
672 return None
673
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600674
675def determine_android_version(boards=None):
676 """Determine the current Android version in buildroot now and return it.
677
678 This uses the typical portage logic to determine which version of Android
679 is active right now in the buildroot.
680
681 Args:
682 boards: List of boards to check version of.
683
684 Returns:
685 The Android build ID of the container for the boards.
686
687 Raises:
688 NoAndroidVersionError: if no unique Android version can be determined.
689 """
690 if not boards:
691 return None
692 # Verify that all boards have the same version.
693 version = None
694 for board in boards:
695 package = determine_android_package(board)
696 if not package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600697 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600698 cpv = portage_util.SplitCPV(package)
699 if not cpv:
700 raise NoAndroidVersionError(
701 'Android version could not be determined for %s' % board)
702 if not version:
703 version = cpv.version_no_rev
704 elif version != cpv.version_no_rev:
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700705 raise NoAndroidVersionError('Different Android versions (%s vs %s) for %s'
706 % (version, cpv.version_no_rev, boards))
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600707 return version
708
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700709
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600710def determine_android_branch(board):
711 """Returns the Android branch in use by the active container ebuild."""
712 try:
713 android_package = determine_android_package(board)
714 except cros_build_lib.RunCommandError:
715 raise NoAndroidBranchError(
716 'Android branch could not be determined for %s' % board)
717 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600718 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600719 ebuild_path = portage_util.FindEbuildForBoardPackage(android_package, board)
720 # We assume all targets pull from the same branch and that we always
721 # have an ARM_TARGET, ARM_USERDEBUG_TARGET, or an X86_USERDEBUG_TARGET.
722 targets = ['ARM_TARGET', 'ARM_USERDEBUG_TARGET', 'X86_USERDEBUG_TARGET']
723 ebuild_content = osutils.SourceEnvironment(ebuild_path, targets)
724 for target in targets:
725 if target in ebuild_content:
726 branch = re.search(r'(.*?)-linux-', ebuild_content[target])
727 if branch is not None:
728 return branch.group(1)
729 raise NoAndroidBranchError(
730 'Android branch could not be determined for %s (ebuild empty?)' % board)
731
732
733def determine_android_target(board):
Michael Mortensen14960d02019-10-18 07:53:59 -0600734 """Returns the Android target in use by the active container ebuild."""
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600735 try:
736 android_package = determine_android_package(board)
737 except cros_build_lib.RunCommandError:
738 raise NoAndroidTargetError(
739 'Android Target could not be determined for %s' % board)
740 if not android_package:
Michael Mortensenedf76532019-10-16 14:22:37 -0600741 return None
Michael Mortensenb70e8a82019-10-10 18:43:41 -0600742 if android_package.startswith('chromeos-base/android-vm-'):
743 return 'bertha'
744 elif android_package.startswith('chromeos-base/android-container-'):
745 return 'cheets'
746
747 raise NoAndroidTargetError(
748 'Android Target cannot be determined for the package: %s' %
749 android_package)
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600750
751
752def determine_platform_version():
753 """Returns the platform version from the source root."""
Michael Mortensen009cb662019-10-21 11:38:43 -0600754 # Platform version is something like '12575.0.0'.
Michael Mortensen9fdb14b2019-10-17 11:17:30 -0600755 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
756 return version.VersionString()
Michael Mortensen009cb662019-10-21 11:38:43 -0600757
758
759def determine_milestone_version():
760 """Returns the platform version from the source root."""
761 # Milestone version is something like '79'.
762 version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
763 return version.chrome_branch
764
Alex Klein7a3a7dd2020-01-08 16:44:38 -0700765
Michael Mortensen009cb662019-10-21 11:38:43 -0600766def determine_full_version():
767 """Returns the full version from the source root."""
768 # Full version is something like 'R79-12575.0.0'.
769 milestone_version = determine_milestone_version()
770 platform_version = determine_platform_version()
771 full_version = ('R%s-%s' % (milestone_version, platform_version))
772 return full_version