blob: a689856c9b08f7355e579214146b23efe0b6d725 [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
Alex Klein87531182019-08-12 15:23:37 -060011import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060012import json
Evan Hernandezb51f1522019-08-15 11:29:40 -060013import os
Alex Klein87531182019-08-12 15:23:37 -060014
Yaakov Shaul730814a2019-09-10 13:58:25 -060015
Alex Kleineb77ffa2019-05-28 14:47:44 -060016from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060017from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060018from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060019from chromite.lib import git
Alex Kleineb77ffa2019-05-28 14:47:44 -060020from chromite.lib import portage_util
Alex Kleind6195b62019-08-06 16:01:16 -060021from chromite.lib import uprev_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060022
Alex Klein87531182019-08-12 15:23:37 -060023# Registered handlers for uprevving versioned packages.
24_UPREV_FUNCS = {}
25
Alex Kleineb77ffa2019-05-28 14:47:44 -060026
27class Error(Exception):
28 """Module's base error class."""
29
30
Alex Klein4de25e82019-08-05 15:58:39 -060031class UnknownPackageError(Error):
32 """Uprev attempted for a package without a registered handler."""
33
34
Alex Kleineb77ffa2019-05-28 14:47:44 -060035class UprevError(Error):
36 """An error occurred while uprevving packages."""
37
38
Alex Klein4de25e82019-08-05 15:58:39 -060039class AndroidIsPinnedUprevError(UprevError):
40 """Raised when we try to uprev while Android is pinned."""
41
42 def __init__(self, new_android_atom):
43 """Initialize a AndroidIsPinnedUprevError.
44
45 Args:
46 new_android_atom: The Android atom that we failed to
47 uprev to, due to Android being pinned.
48 """
49 assert new_android_atom
50 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
51 new_android_atom)
52 super(AndroidIsPinnedUprevError, self).__init__(msg)
53 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060054
55
Yaakov Shaul1eafe832019-09-10 16:50:26 -060056class EbuildManifestError(Error):
57 """Error when running ebuild manifest."""
58
59
Yaakov Shaul730814a2019-09-10 13:58:25 -060060UprevVersionedPackageModifications = collections.namedtuple(
61 'UprevVersionedPackageModifications', ('new_version', 'files'))
Alex Klein34afcbc2019-08-22 16:14:31 -060062
Yaakov Shaul730814a2019-09-10 13:58:25 -060063
64class UprevVersionedPackageResult(object):
65 """Data object for uprev_versioned_package."""
66
67 def __init__(self):
68 self.modified = []
69
70 def add_result(self, new_version, modified_files):
71 """Adds version/ebuilds tuple to result.
72
73 Args:
74 new_version: New version number of package.
75 modified_files: List of files modified for the given version.
76 """
77 result = UprevVersionedPackageModifications(new_version, modified_files)
78 self.modified.append(result)
79 return self
Alex Klein34afcbc2019-08-22 16:14:31 -060080
81 @property
82 def uprevved(self):
Yaakov Shaul730814a2019-09-10 13:58:25 -060083 return bool(self.modified)
Alex Klein34afcbc2019-08-22 16:14:31 -060084
85
Alex Klein87531182019-08-12 15:23:37 -060086def uprevs_versioned_package(package):
87 """Decorator to register package uprev handlers."""
88 assert package
89
90 def register(func):
91 """Registers |func| as a handler for |package|."""
92 _UPREV_FUNCS[package] = func
93
94 @functools.wraps(func)
95 def pass_through(*args, **kwargs):
96 return func(*args, **kwargs)
97
98 return pass_through
99
100 return register
101
102
Alex Klein4de25e82019-08-05 15:58:39 -0600103def uprev_android(tracking_branch, android_package, android_build_branch,
104 chroot, build_targets=None, android_version=None,
105 android_gts_build_branch=None):
106 """Returns the portage atom for the revved Android ebuild - see man emerge."""
107 command = ['cros_mark_android_as_stable',
108 '--tracking_branch=%s' % tracking_branch,
109 '--android_package=%s' % android_package,
110 '--android_build_branch=%s' % android_build_branch]
111 if build_targets:
112 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
113 if android_version:
114 command.append('--force_version=%s' % android_version)
115 if android_gts_build_branch:
116 command.append('--android_gts_build_branch=%s' % android_gts_build_branch)
117
118 result = cros_build_lib.RunCommand(command, redirect_stdout=True,
119 enter_chroot=True,
120 chroot_args=chroot.get_enter_args())
121
122 android_atom = _parse_android_atom(result)
123 if not android_atom:
124 logging.info('Found nothing to rev.')
125 return None
126
127 for target in build_targets or []:
128 # Sanity check: We should always be able to merge the version of
129 # Android we just unmasked.
130 command = ['emerge-%s' % target.name, '-p', '--quiet',
131 '=%s' % android_atom]
132 try:
133 cros_build_lib.RunCommand(command, enter_chroot=True,
134 chroot_args=chroot.get_enter_args())
135 except cros_build_lib.RunCommandError:
136 logging.error(
137 'Cannot emerge-%s =%s\nIs Android pinned to an older '
138 'version?', target, android_atom)
139 raise AndroidIsPinnedUprevError(android_atom)
140
141 return android_atom
142
143
144def _parse_android_atom(result):
145 """Helper to parse the atom from the cros_mark_android_as_stable output.
146
147 This function is largely just intended to make testing easier.
148
149 Args:
150 result (cros_build_lib.CommandResult): The cros_mark_android_as_stable
151 command result.
152 """
153 portage_atom_string = result.output.strip()
154
155 android_atom = None
156 if portage_atom_string:
157 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
158
159 return android_atom
160
161
Alex Kleineb77ffa2019-05-28 14:47:44 -0600162def uprev_build_targets(build_targets, overlay_type, chroot=None,
163 output_dir=None):
164 """Uprev the set provided build targets, or all if not specified.
165
166 Args:
167 build_targets (list[build_target_util.BuildTarget]|None): The build targets
168 whose overlays should be uprevved, empty or None for all.
169 overlay_type (str): One of the valid overlay types except None (see
170 constants.VALID_OVERLAYS).
171 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
172 output_dir (str|None): The path to optionally dump result files.
173 """
174 # Need a valid overlay, but exclude None.
175 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
176
177 if build_targets:
178 overlays = portage_util.FindOverlaysForBoards(
179 overlay_type, boards=[t.name for t in build_targets])
180 else:
181 overlays = portage_util.FindOverlays(overlay_type)
182
183 return uprev_overlays(overlays, build_targets=build_targets, chroot=chroot,
184 output_dir=output_dir)
185
186
187def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
188 """Uprev the given overlays.
189
190 Args:
191 overlays (list[str]): The list of overlay paths.
192 build_targets (list[build_target_util.BuildTarget]|None): The build targets
193 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
194 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
195 output_dir (str|None): The path to optionally dump result files.
196
197 Returns:
198 list[str] - The paths to all of the modified ebuild files. This includes the
199 new files that were added (i.e. the new versions) and all of the removed
200 files (i.e. the old versions).
201 """
202 assert overlays
203
204 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
205
Alex Kleind6195b62019-08-06 16:01:16 -0600206 uprev_manager = uprev_lib.UprevOverlayManager(overlays, manifest,
207 build_targets=build_targets,
208 chroot=chroot,
209 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600210 uprev_manager.uprev()
211
212 return uprev_manager.modified_ebuilds
213
214
Alex Klein87531182019-08-12 15:23:37 -0600215def uprev_versioned_package(package, build_targets, refs, chroot):
216 """Call registered uprev handler function for the package.
217
218 Args:
219 package (portage_util.CPV): The package being uprevved.
220 build_targets (list[build_target_util.BuildTarget]): The build targets to
221 clean on a successful uprev.
222 refs (list[uprev_lib.GitRef]):
223 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
224
225 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600226 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600227 """
228 assert package
229
230 if package.cp not in _UPREV_FUNCS:
231 raise UnknownPackageError(
232 'Package "%s" does not have a registered handler.' % package.cp)
233
234 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
235
236
Evan Hernandezb51f1522019-08-15 11:29:40 -0600237# TODO(evanhernandez): Remove this. Only a quick hack for testing.
238@uprevs_versioned_package('sample/sample')
239def uprev_sample(*_args, **_kwargs):
240 """Mimics an uprev by changing files in sandbox repos.
241
242 See: uprev_versioned_package.
243 """
244 paths = [
245 os.path.join(constants.SOURCE_ROOT, 'infra/dummies', repo, 'sample.txt')
246 for repo in ('general-sandbox', 'merge-sandbox')
247 ]
248
Yaakov Shaul730814a2019-09-10 13:58:25 -0600249 return UprevVersionedPackageResult().add_result('1.2.3', paths)
Evan Hernandezb51f1522019-08-15 11:29:40 -0600250
251
Yaakov Shaul395ae832019-09-09 14:45:32 -0600252@uprevs_versioned_package('afdo/kernel-profiles')
253def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600254 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600255
256 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600257
258 Raises:
259 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600260 """
261 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
262 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
263
David Burger92485342019-09-10 17:52:45 -0600264 with open(path, 'r') as f:
265 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600266
Yaakov Shaul730814a2019-09-10 13:58:25 -0600267 result = UprevVersionedPackageResult()
Yaakov Shaul395ae832019-09-09 14:45:32 -0600268 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600269 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
270 'sys-kernel', version)
271 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
272 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600273 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
274 '%s-9999.ebuild' % version)
Yaakov Shaul730814a2019-09-10 13:58:25 -0600275 afdo_profile_version = version_info['name']
Yaakov Shaul395ae832019-09-09 14:45:32 -0600276 portage_util.EBuild.UpdateEBuild(
Yaakov Shaul730814a2019-09-10 13:58:25 -0600277 ebuild_path, dict(AFDO_PROFILE_VERSION=afdo_profile_version))
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600278
279 try:
Yaakov Shaul730814a2019-09-10 13:58:25 -0600280 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600281 cros_build_lib.RunCommand(cmd, enter_chroot=True)
282 except cros_build_lib.RunCommandError as e:
283 raise EbuildManifestError(
284 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600285 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600286
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600287 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600288
Yaakov Shaul730814a2019-09-10 13:58:25 -0600289 result.add_result(afdo_profile_version, [ebuild_path, manifest_path])
290
291 return result
Yaakov Shaul395ae832019-09-09 14:45:32 -0600292
293
Alex Klein87531182019-08-12 15:23:37 -0600294@uprevs_versioned_package(constants.CHROME_CP)
295def uprev_chrome(build_targets, refs, chroot):
296 """Uprev chrome and its related packages.
297
298 See: uprev_versioned_package.
299 """
300 # Determine the version from the refs (tags), i.e. the chrome versions are the
301 # tag names.
302 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
303
304 uprev_manager = uprev_lib.UprevChromeManager(
305 chrome_version, build_targets=build_targets, chroot=chroot)
306 # Start with chrome itself, as we can't do anything else unless chrome
307 # uprevs successfully.
308 if not uprev_manager.uprev(constants.CHROME_CP):
309 return []
310
311 # With a successful chrome rev, also uprev related packages.
312 for package in constants.OTHER_CHROME_PACKAGES:
313 uprev_manager.uprev(package)
314
Yaakov Shaul730814a2019-09-10 13:58:25 -0600315 return UprevVersionedPackageResult().add_result(
316 chrome_version, uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600317
318
Alex Kleinbbef2b32019-08-27 10:38:50 -0600319def get_best_visible(atom, build_target=None):
320 """Returns the best visible CPV for the given atom.
321
322 Args:
323 atom (str): The atom to look up.
324 build_target (build_target_util.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600325 sysroot should be searched, or the SDK if not provided.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600326 """
David Burger1e0fe232019-07-01 14:52:07 -0600327 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600328
329 board = build_target.name if build_target else None
330 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600331
332
333def has_prebuilt(atom, build_target=None):
334 """Check if a prebuilt exists.
335
336 Args:
337 atom (str): The package whose prebuilt is being queried.
338 build_target (build_target_util.BuildTarget): The build target whose
339 sysroot should be searched, or the SDK if not provided.
340 """
341 assert atom
342
343 board = build_target.name if build_target else None
344 return portage_util.HasPrebuilt(atom, board=board)