blob: ba9833480fe1e92411629b124127eb60c7d04804 [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
Alex Klein87531182019-08-12 15:23:37 -060010import functools
Yaakov Shaul395ae832019-09-09 14:45:32 -060011import json
Evan Hernandezb51f1522019-08-15 11:29:40 -060012import os
Alex Klein87531182019-08-12 15:23:37 -060013
Alex Kleineb77ffa2019-05-28 14:47:44 -060014from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060015from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060016from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060017from chromite.lib import git
Evan Hernandezb51f1522019-08-15 11:29:40 -060018from chromite.lib import osutils
Alex Kleineb77ffa2019-05-28 14:47:44 -060019from chromite.lib import portage_util
Alex Kleind6195b62019-08-06 16:01:16 -060020from chromite.lib import uprev_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060021
Alex Klein87531182019-08-12 15:23:37 -060022# Registered handlers for uprevving versioned packages.
23_UPREV_FUNCS = {}
24
Alex Kleineb77ffa2019-05-28 14:47:44 -060025
26class Error(Exception):
27 """Module's base error class."""
28
29
Alex Klein4de25e82019-08-05 15:58:39 -060030class UnknownPackageError(Error):
31 """Uprev attempted for a package without a registered handler."""
32
33
Alex Kleineb77ffa2019-05-28 14:47:44 -060034class UprevError(Error):
35 """An error occurred while uprevving packages."""
36
37
Alex Klein4de25e82019-08-05 15:58:39 -060038class AndroidIsPinnedUprevError(UprevError):
39 """Raised when we try to uprev while Android is pinned."""
40
41 def __init__(self, new_android_atom):
42 """Initialize a AndroidIsPinnedUprevError.
43
44 Args:
45 new_android_atom: The Android atom that we failed to
46 uprev to, due to Android being pinned.
47 """
48 assert new_android_atom
49 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
50 new_android_atom)
51 super(AndroidIsPinnedUprevError, self).__init__(msg)
52 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060053
54
Yaakov Shaul1eafe832019-09-10 16:50:26 -060055class EbuildManifestError(Error):
56 """Error when running ebuild manifest."""
57
58
Alex Klein34afcbc2019-08-22 16:14:31 -060059class UprevVersionedPackageResult(object):
60 """Result data object for uprev_versioned_package."""
61
62 def __init__(self, new_version=None, modified_ebuilds=None):
63 self.new_version = new_version
64 self.modified_ebuilds = modified_ebuilds or []
65
66 @property
67 def uprevved(self):
68 return bool(self.new_version)
69
70
Alex Klein87531182019-08-12 15:23:37 -060071def uprevs_versioned_package(package):
72 """Decorator to register package uprev handlers."""
73 assert package
74
75 def register(func):
76 """Registers |func| as a handler for |package|."""
77 _UPREV_FUNCS[package] = func
78
79 @functools.wraps(func)
80 def pass_through(*args, **kwargs):
81 return func(*args, **kwargs)
82
83 return pass_through
84
85 return register
86
87
Alex Klein4de25e82019-08-05 15:58:39 -060088def uprev_android(tracking_branch, android_package, android_build_branch,
89 chroot, build_targets=None, android_version=None,
90 android_gts_build_branch=None):
91 """Returns the portage atom for the revved Android ebuild - see man emerge."""
92 command = ['cros_mark_android_as_stable',
93 '--tracking_branch=%s' % tracking_branch,
94 '--android_package=%s' % android_package,
95 '--android_build_branch=%s' % android_build_branch]
96 if build_targets:
97 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
98 if android_version:
99 command.append('--force_version=%s' % android_version)
100 if android_gts_build_branch:
101 command.append('--android_gts_build_branch=%s' % android_gts_build_branch)
102
103 result = cros_build_lib.RunCommand(command, redirect_stdout=True,
104 enter_chroot=True,
105 chroot_args=chroot.get_enter_args())
106
107 android_atom = _parse_android_atom(result)
108 if not android_atom:
109 logging.info('Found nothing to rev.')
110 return None
111
112 for target in build_targets or []:
113 # Sanity check: We should always be able to merge the version of
114 # Android we just unmasked.
115 command = ['emerge-%s' % target.name, '-p', '--quiet',
116 '=%s' % android_atom]
117 try:
118 cros_build_lib.RunCommand(command, enter_chroot=True,
119 chroot_args=chroot.get_enter_args())
120 except cros_build_lib.RunCommandError:
121 logging.error(
122 'Cannot emerge-%s =%s\nIs Android pinned to an older '
123 'version?', target, android_atom)
124 raise AndroidIsPinnedUprevError(android_atom)
125
126 return android_atom
127
128
129def _parse_android_atom(result):
130 """Helper to parse the atom from the cros_mark_android_as_stable output.
131
132 This function is largely just intended to make testing easier.
133
134 Args:
135 result (cros_build_lib.CommandResult): The cros_mark_android_as_stable
136 command result.
137 """
138 portage_atom_string = result.output.strip()
139
140 android_atom = None
141 if portage_atom_string:
142 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
143
144 return android_atom
145
146
Alex Kleineb77ffa2019-05-28 14:47:44 -0600147def uprev_build_targets(build_targets, overlay_type, chroot=None,
148 output_dir=None):
149 """Uprev the set provided build targets, or all if not specified.
150
151 Args:
152 build_targets (list[build_target_util.BuildTarget]|None): The build targets
153 whose overlays should be uprevved, empty or None for all.
154 overlay_type (str): One of the valid overlay types except None (see
155 constants.VALID_OVERLAYS).
156 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
157 output_dir (str|None): The path to optionally dump result files.
158 """
159 # Need a valid overlay, but exclude None.
160 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
161
162 if build_targets:
163 overlays = portage_util.FindOverlaysForBoards(
164 overlay_type, boards=[t.name for t in build_targets])
165 else:
166 overlays = portage_util.FindOverlays(overlay_type)
167
168 return uprev_overlays(overlays, build_targets=build_targets, chroot=chroot,
169 output_dir=output_dir)
170
171
172def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
173 """Uprev the given overlays.
174
175 Args:
176 overlays (list[str]): The list of overlay paths.
177 build_targets (list[build_target_util.BuildTarget]|None): The build targets
178 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
179 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
180 output_dir (str|None): The path to optionally dump result files.
181
182 Returns:
183 list[str] - The paths to all of the modified ebuild files. This includes the
184 new files that were added (i.e. the new versions) and all of the removed
185 files (i.e. the old versions).
186 """
187 assert overlays
188
189 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
190
Alex Kleind6195b62019-08-06 16:01:16 -0600191 uprev_manager = uprev_lib.UprevOverlayManager(overlays, manifest,
192 build_targets=build_targets,
193 chroot=chroot,
194 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600195 uprev_manager.uprev()
196
197 return uprev_manager.modified_ebuilds
198
199
Alex Klein87531182019-08-12 15:23:37 -0600200def uprev_versioned_package(package, build_targets, refs, chroot):
201 """Call registered uprev handler function for the package.
202
203 Args:
204 package (portage_util.CPV): The package being uprevved.
205 build_targets (list[build_target_util.BuildTarget]): The build targets to
206 clean on a successful uprev.
207 refs (list[uprev_lib.GitRef]):
208 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
209
210 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600211 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600212 """
213 assert package
214
215 if package.cp not in _UPREV_FUNCS:
216 raise UnknownPackageError(
217 'Package "%s" does not have a registered handler.' % package.cp)
218
219 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
220
221
Evan Hernandezb51f1522019-08-15 11:29:40 -0600222# TODO(evanhernandez): Remove this. Only a quick hack for testing.
223@uprevs_versioned_package('sample/sample')
224def uprev_sample(*_args, **_kwargs):
225 """Mimics an uprev by changing files in sandbox repos.
226
227 See: uprev_versioned_package.
228 """
229 paths = [
230 os.path.join(constants.SOURCE_ROOT, 'infra/dummies', repo, 'sample.txt')
231 for repo in ('general-sandbox', 'merge-sandbox')
232 ]
233
Evan Hernandez3d311d82019-08-28 13:57:43 -0600234 return UprevVersionedPackageResult('1.2.3', paths)
Evan Hernandezb51f1522019-08-15 11:29:40 -0600235
236
Yaakov Shaul395ae832019-09-09 14:45:32 -0600237@uprevs_versioned_package('afdo/kernel-profiles')
238def uprev_kernel_afdo(*_args, **_kwargs):
239 """Updates the kernel ebuild with version from kernel_afdo.json.
240
241 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600242
243 Raises:
244 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600245 """
246 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
247 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
248
249 with open(path, 'r') as file:
250 versions = json.load(file)
251
252 paths = []
253 for version, version_info in versions.items():
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600254 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
255 'chromiumos-overlay', 'sys-kernel', version)
256 ebuild_path = os.path.join(path, '%s-9999.ebuild' % version)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600257 portage_util.EBuild.UpdateEBuild(
Yaakov Shaul09e88272019-09-10 12:01:04 -0600258 ebuild_path,
259 dict(AFDO_PROFILE_VERSION=version_info['name']),
260 make_stable=False)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600261 paths.append(ebuild_path)
262
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600263 cmd = ['ebuild', ebuild_path, 'manifest', '--force']
264
265 try:
266 cros_build_lib.RunCommand(cmd, enter_chroot=True)
267 except cros_build_lib.RunCommandError as e:
268 raise EbuildManifestError(
269 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
270 % (ebuild_path, e), e)
271
272 manifest_path = os.path.join(path, 'Manifest')
273 paths.append(manifest_path)
274
Yaakov Shaul395ae832019-09-09 14:45:32 -0600275 return UprevVersionedPackageResult("test version", paths)
276
277
Alex Klein87531182019-08-12 15:23:37 -0600278@uprevs_versioned_package(constants.CHROME_CP)
279def uprev_chrome(build_targets, refs, chroot):
280 """Uprev chrome and its related packages.
281
282 See: uprev_versioned_package.
283 """
284 # Determine the version from the refs (tags), i.e. the chrome versions are the
285 # tag names.
286 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
287
288 uprev_manager = uprev_lib.UprevChromeManager(
289 chrome_version, build_targets=build_targets, chroot=chroot)
290 # Start with chrome itself, as we can't do anything else unless chrome
291 # uprevs successfully.
292 if not uprev_manager.uprev(constants.CHROME_CP):
293 return []
294
295 # With a successful chrome rev, also uprev related packages.
296 for package in constants.OTHER_CHROME_PACKAGES:
297 uprev_manager.uprev(package)
298
Alex Klein34afcbc2019-08-22 16:14:31 -0600299 return UprevVersionedPackageResult(chrome_version,
300 uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600301
302
Alex Kleinbbef2b32019-08-27 10:38:50 -0600303def get_best_visible(atom, build_target=None):
304 """Returns the best visible CPV for the given atom.
305
306 Args:
307 atom (str): The atom to look up.
308 build_target (build_target_util.BuildTarget): The build target whose
309 sysroot should be searched.
310 """
David Burger1e0fe232019-07-01 14:52:07 -0600311 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600312
313 board = build_target.name if build_target else None
314 return portage_util.PortageqBestVisible(atom, board=board)