blob: c7de3eea5376d9b54003621c398e88eecabf4a2d [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
Alex Klein34afcbc2019-08-22 16:14:31 -060055class UprevVersionedPackageResult(object):
56 """Result data object for uprev_versioned_package."""
57
58 def __init__(self, new_version=None, modified_ebuilds=None):
59 self.new_version = new_version
60 self.modified_ebuilds = modified_ebuilds or []
61
62 @property
63 def uprevved(self):
64 return bool(self.new_version)
65
66
Alex Klein87531182019-08-12 15:23:37 -060067def uprevs_versioned_package(package):
68 """Decorator to register package uprev handlers."""
69 assert package
70
71 def register(func):
72 """Registers |func| as a handler for |package|."""
73 _UPREV_FUNCS[package] = func
74
75 @functools.wraps(func)
76 def pass_through(*args, **kwargs):
77 return func(*args, **kwargs)
78
79 return pass_through
80
81 return register
82
83
Alex Klein4de25e82019-08-05 15:58:39 -060084def uprev_android(tracking_branch, android_package, android_build_branch,
85 chroot, build_targets=None, android_version=None,
86 android_gts_build_branch=None):
87 """Returns the portage atom for the revved Android ebuild - see man emerge."""
88 command = ['cros_mark_android_as_stable',
89 '--tracking_branch=%s' % tracking_branch,
90 '--android_package=%s' % android_package,
91 '--android_build_branch=%s' % android_build_branch]
92 if build_targets:
93 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
94 if android_version:
95 command.append('--force_version=%s' % android_version)
96 if android_gts_build_branch:
97 command.append('--android_gts_build_branch=%s' % android_gts_build_branch)
98
99 result = cros_build_lib.RunCommand(command, redirect_stdout=True,
100 enter_chroot=True,
101 chroot_args=chroot.get_enter_args())
102
103 android_atom = _parse_android_atom(result)
104 if not android_atom:
105 logging.info('Found nothing to rev.')
106 return None
107
108 for target in build_targets or []:
109 # Sanity check: We should always be able to merge the version of
110 # Android we just unmasked.
111 command = ['emerge-%s' % target.name, '-p', '--quiet',
112 '=%s' % android_atom]
113 try:
114 cros_build_lib.RunCommand(command, enter_chroot=True,
115 chroot_args=chroot.get_enter_args())
116 except cros_build_lib.RunCommandError:
117 logging.error(
118 'Cannot emerge-%s =%s\nIs Android pinned to an older '
119 'version?', target, android_atom)
120 raise AndroidIsPinnedUprevError(android_atom)
121
122 return android_atom
123
124
125def _parse_android_atom(result):
126 """Helper to parse the atom from the cros_mark_android_as_stable output.
127
128 This function is largely just intended to make testing easier.
129
130 Args:
131 result (cros_build_lib.CommandResult): The cros_mark_android_as_stable
132 command result.
133 """
134 portage_atom_string = result.output.strip()
135
136 android_atom = None
137 if portage_atom_string:
138 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
139
140 return android_atom
141
142
Alex Kleineb77ffa2019-05-28 14:47:44 -0600143def uprev_build_targets(build_targets, overlay_type, chroot=None,
144 output_dir=None):
145 """Uprev the set provided build targets, or all if not specified.
146
147 Args:
148 build_targets (list[build_target_util.BuildTarget]|None): The build targets
149 whose overlays should be uprevved, empty or None for all.
150 overlay_type (str): One of the valid overlay types except None (see
151 constants.VALID_OVERLAYS).
152 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
153 output_dir (str|None): The path to optionally dump result files.
154 """
155 # Need a valid overlay, but exclude None.
156 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
157
158 if build_targets:
159 overlays = portage_util.FindOverlaysForBoards(
160 overlay_type, boards=[t.name for t in build_targets])
161 else:
162 overlays = portage_util.FindOverlays(overlay_type)
163
164 return uprev_overlays(overlays, build_targets=build_targets, chroot=chroot,
165 output_dir=output_dir)
166
167
168def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
169 """Uprev the given overlays.
170
171 Args:
172 overlays (list[str]): The list of overlay paths.
173 build_targets (list[build_target_util.BuildTarget]|None): The build targets
174 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
175 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
176 output_dir (str|None): The path to optionally dump result files.
177
178 Returns:
179 list[str] - The paths to all of the modified ebuild files. This includes the
180 new files that were added (i.e. the new versions) and all of the removed
181 files (i.e. the old versions).
182 """
183 assert overlays
184
185 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
186
Alex Kleind6195b62019-08-06 16:01:16 -0600187 uprev_manager = uprev_lib.UprevOverlayManager(overlays, manifest,
188 build_targets=build_targets,
189 chroot=chroot,
190 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600191 uprev_manager.uprev()
192
193 return uprev_manager.modified_ebuilds
194
195
Alex Klein87531182019-08-12 15:23:37 -0600196def uprev_versioned_package(package, build_targets, refs, chroot):
197 """Call registered uprev handler function for the package.
198
199 Args:
200 package (portage_util.CPV): The package being uprevved.
201 build_targets (list[build_target_util.BuildTarget]): The build targets to
202 clean on a successful uprev.
203 refs (list[uprev_lib.GitRef]):
204 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
205
206 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600207 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600208 """
209 assert package
210
211 if package.cp not in _UPREV_FUNCS:
212 raise UnknownPackageError(
213 'Package "%s" does not have a registered handler.' % package.cp)
214
215 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
216
217
Evan Hernandezb51f1522019-08-15 11:29:40 -0600218# TODO(evanhernandez): Remove this. Only a quick hack for testing.
219@uprevs_versioned_package('sample/sample')
220def uprev_sample(*_args, **_kwargs):
221 """Mimics an uprev by changing files in sandbox repos.
222
223 See: uprev_versioned_package.
224 """
225 paths = [
226 os.path.join(constants.SOURCE_ROOT, 'infra/dummies', repo, 'sample.txt')
227 for repo in ('general-sandbox', 'merge-sandbox')
228 ]
229
Evan Hernandez3d311d82019-08-28 13:57:43 -0600230 return UprevVersionedPackageResult('1.2.3', paths)
Evan Hernandezb51f1522019-08-15 11:29:40 -0600231
232
Yaakov Shaul395ae832019-09-09 14:45:32 -0600233@uprevs_versioned_package('afdo/kernel-profiles')
234def uprev_kernel_afdo(*_args, **_kwargs):
235 """Updates the kernel ebuild with version from kernel_afdo.json.
236
237 See: uprev_versioned_package.
238 """
239 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
240 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
241
242 with open(path, 'r') as file:
243 versions = json.load(file)
244
245 paths = []
246 for version, version_info in versions.items():
247 ebuild_path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
248 'chromiumos-overlay', 'sys-kernel', version,
249 '%s-9999.ebuild' % version)
250 portage_util.EBuild.UpdateEBuild(
Yaakov Shaul09e88272019-09-10 12:01:04 -0600251 ebuild_path,
252 dict(AFDO_PROFILE_VERSION=version_info['name']),
253 make_stable=False)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600254 paths.append(ebuild_path)
255
256 return UprevVersionedPackageResult("test version", paths)
257
258
Alex Klein87531182019-08-12 15:23:37 -0600259@uprevs_versioned_package(constants.CHROME_CP)
260def uprev_chrome(build_targets, refs, chroot):
261 """Uprev chrome and its related packages.
262
263 See: uprev_versioned_package.
264 """
265 # Determine the version from the refs (tags), i.e. the chrome versions are the
266 # tag names.
267 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
268
269 uprev_manager = uprev_lib.UprevChromeManager(
270 chrome_version, build_targets=build_targets, chroot=chroot)
271 # Start with chrome itself, as we can't do anything else unless chrome
272 # uprevs successfully.
273 if not uprev_manager.uprev(constants.CHROME_CP):
274 return []
275
276 # With a successful chrome rev, also uprev related packages.
277 for package in constants.OTHER_CHROME_PACKAGES:
278 uprev_manager.uprev(package)
279
Alex Klein34afcbc2019-08-22 16:14:31 -0600280 return UprevVersionedPackageResult(chrome_version,
281 uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600282
283
Alex Kleinbbef2b32019-08-27 10:38:50 -0600284def get_best_visible(atom, build_target=None):
285 """Returns the best visible CPV for the given atom.
286
287 Args:
288 atom (str): The atom to look up.
289 build_target (build_target_util.BuildTarget): The build target whose
290 sysroot should be searched.
291 """
David Burger1e0fe232019-07-01 14:52:07 -0600292 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600293
294 board = build_target.name if build_target else None
295 return portage_util.PortageqBestVisible(atom, board=board)