blob: b9eedcb2086a889a02771472d823a5f7960f73bc [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
Alex Kleineb77ffa2019-05-28 14:47:44 -060018from chromite.lib import portage_util
Alex Kleind6195b62019-08-06 16:01:16 -060019from chromite.lib import uprev_lib
Alex Kleineb77ffa2019-05-28 14:47:44 -060020
Alex Klein87531182019-08-12 15:23:37 -060021# Registered handlers for uprevving versioned packages.
22_UPREV_FUNCS = {}
23
Alex Kleineb77ffa2019-05-28 14:47:44 -060024
25class Error(Exception):
26 """Module's base error class."""
27
28
Alex Klein4de25e82019-08-05 15:58:39 -060029class UnknownPackageError(Error):
30 """Uprev attempted for a package without a registered handler."""
31
32
Alex Kleineb77ffa2019-05-28 14:47:44 -060033class UprevError(Error):
34 """An error occurred while uprevving packages."""
35
36
Alex Klein4de25e82019-08-05 15:58:39 -060037class AndroidIsPinnedUprevError(UprevError):
38 """Raised when we try to uprev while Android is pinned."""
39
40 def __init__(self, new_android_atom):
41 """Initialize a AndroidIsPinnedUprevError.
42
43 Args:
44 new_android_atom: The Android atom that we failed to
45 uprev to, due to Android being pinned.
46 """
47 assert new_android_atom
48 msg = ('Failed up uprev to Android version %s as Android was pinned.' %
49 new_android_atom)
50 super(AndroidIsPinnedUprevError, self).__init__(msg)
51 self.new_android_atom = new_android_atom
Alex Klein87531182019-08-12 15:23:37 -060052
53
Yaakov Shaul1eafe832019-09-10 16:50:26 -060054class EbuildManifestError(Error):
55 """Error when running ebuild manifest."""
56
57
Alex Klein34afcbc2019-08-22 16:14:31 -060058class UprevVersionedPackageResult(object):
59 """Result data object for uprev_versioned_package."""
60
61 def __init__(self, new_version=None, modified_ebuilds=None):
62 self.new_version = new_version
63 self.modified_ebuilds = modified_ebuilds or []
64
65 @property
66 def uprevved(self):
67 return bool(self.new_version)
68
69
Alex Klein87531182019-08-12 15:23:37 -060070def uprevs_versioned_package(package):
71 """Decorator to register package uprev handlers."""
72 assert package
73
74 def register(func):
75 """Registers |func| as a handler for |package|."""
76 _UPREV_FUNCS[package] = func
77
78 @functools.wraps(func)
79 def pass_through(*args, **kwargs):
80 return func(*args, **kwargs)
81
82 return pass_through
83
84 return register
85
86
Alex Klein4de25e82019-08-05 15:58:39 -060087def uprev_android(tracking_branch, android_package, android_build_branch,
88 chroot, build_targets=None, android_version=None,
89 android_gts_build_branch=None):
90 """Returns the portage atom for the revved Android ebuild - see man emerge."""
91 command = ['cros_mark_android_as_stable',
92 '--tracking_branch=%s' % tracking_branch,
93 '--android_package=%s' % android_package,
94 '--android_build_branch=%s' % android_build_branch]
95 if build_targets:
96 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
97 if android_version:
98 command.append('--force_version=%s' % android_version)
99 if android_gts_build_branch:
100 command.append('--android_gts_build_branch=%s' % android_gts_build_branch)
101
102 result = cros_build_lib.RunCommand(command, redirect_stdout=True,
103 enter_chroot=True,
104 chroot_args=chroot.get_enter_args())
105
106 android_atom = _parse_android_atom(result)
107 if not android_atom:
108 logging.info('Found nothing to rev.')
109 return None
110
111 for target in build_targets or []:
112 # Sanity check: We should always be able to merge the version of
113 # Android we just unmasked.
114 command = ['emerge-%s' % target.name, '-p', '--quiet',
115 '=%s' % android_atom]
116 try:
117 cros_build_lib.RunCommand(command, enter_chroot=True,
118 chroot_args=chroot.get_enter_args())
119 except cros_build_lib.RunCommandError:
120 logging.error(
121 'Cannot emerge-%s =%s\nIs Android pinned to an older '
122 'version?', target, android_atom)
123 raise AndroidIsPinnedUprevError(android_atom)
124
125 return android_atom
126
127
128def _parse_android_atom(result):
129 """Helper to parse the atom from the cros_mark_android_as_stable output.
130
131 This function is largely just intended to make testing easier.
132
133 Args:
134 result (cros_build_lib.CommandResult): The cros_mark_android_as_stable
135 command result.
136 """
137 portage_atom_string = result.output.strip()
138
139 android_atom = None
140 if portage_atom_string:
141 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
142
143 return android_atom
144
145
Alex Kleineb77ffa2019-05-28 14:47:44 -0600146def uprev_build_targets(build_targets, overlay_type, chroot=None,
147 output_dir=None):
148 """Uprev the set provided build targets, or all if not specified.
149
150 Args:
151 build_targets (list[build_target_util.BuildTarget]|None): The build targets
152 whose overlays should be uprevved, empty or None for all.
153 overlay_type (str): One of the valid overlay types except None (see
154 constants.VALID_OVERLAYS).
155 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
156 output_dir (str|None): The path to optionally dump result files.
157 """
158 # Need a valid overlay, but exclude None.
159 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
160
161 if build_targets:
162 overlays = portage_util.FindOverlaysForBoards(
163 overlay_type, boards=[t.name for t in build_targets])
164 else:
165 overlays = portage_util.FindOverlays(overlay_type)
166
167 return uprev_overlays(overlays, build_targets=build_targets, chroot=chroot,
168 output_dir=output_dir)
169
170
171def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
172 """Uprev the given overlays.
173
174 Args:
175 overlays (list[str]): The list of overlay paths.
176 build_targets (list[build_target_util.BuildTarget]|None): The build targets
177 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
178 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
179 output_dir (str|None): The path to optionally dump result files.
180
181 Returns:
182 list[str] - The paths to all of the modified ebuild files. This includes the
183 new files that were added (i.e. the new versions) and all of the removed
184 files (i.e. the old versions).
185 """
186 assert overlays
187
188 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
189
Alex Kleind6195b62019-08-06 16:01:16 -0600190 uprev_manager = uprev_lib.UprevOverlayManager(overlays, manifest,
191 build_targets=build_targets,
192 chroot=chroot,
193 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600194 uprev_manager.uprev()
195
196 return uprev_manager.modified_ebuilds
197
198
Alex Klein87531182019-08-12 15:23:37 -0600199def uprev_versioned_package(package, build_targets, refs, chroot):
200 """Call registered uprev handler function for the package.
201
202 Args:
203 package (portage_util.CPV): The package being uprevved.
204 build_targets (list[build_target_util.BuildTarget]): The build targets to
205 clean on a successful uprev.
206 refs (list[uprev_lib.GitRef]):
207 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
208
209 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600210 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600211 """
212 assert package
213
214 if package.cp not in _UPREV_FUNCS:
215 raise UnknownPackageError(
216 'Package "%s" does not have a registered handler.' % package.cp)
217
218 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
219
220
Evan Hernandezb51f1522019-08-15 11:29:40 -0600221# TODO(evanhernandez): Remove this. Only a quick hack for testing.
222@uprevs_versioned_package('sample/sample')
223def uprev_sample(*_args, **_kwargs):
224 """Mimics an uprev by changing files in sandbox repos.
225
226 See: uprev_versioned_package.
227 """
228 paths = [
229 os.path.join(constants.SOURCE_ROOT, 'infra/dummies', repo, 'sample.txt')
230 for repo in ('general-sandbox', 'merge-sandbox')
231 ]
232
Evan Hernandez3d311d82019-08-28 13:57:43 -0600233 return UprevVersionedPackageResult('1.2.3', paths)
Evan Hernandezb51f1522019-08-15 11:29:40 -0600234
235
Yaakov Shaul395ae832019-09-09 14:45:32 -0600236@uprevs_versioned_package('afdo/kernel-profiles')
237def uprev_kernel_afdo(*_args, **_kwargs):
David Burger92485342019-09-10 17:52:45 -0600238 """Updates kernel ebuilds with versions from kernel_afdo.json.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600239
240 See: uprev_versioned_package.
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600241
242 Raises:
243 EbuildManifestError: When ebuild manifest does not complete successfuly.
Yaakov Shaul395ae832019-09-09 14:45:32 -0600244 """
245 path = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
246 'toolchain-utils', 'afdo_metadata', 'kernel_afdo.json')
247
David Burger92485342019-09-10 17:52:45 -0600248 with open(path, 'r') as f:
249 versions = json.load(f)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600250
251 paths = []
252 for version, version_info in versions.items():
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600253 path = os.path.join('src', 'third_party', 'chromiumos-overlay',
254 'sys-kernel', version)
255 ebuild_path = os.path.join(constants.SOURCE_ROOT, path,
256 '%s-9999.ebuild' % version)
Yaakov Shaula187b152019-09-11 12:41:32 -0600257 chroot_ebuild_path = os.path.join(constants.CHROOT_SOURCE_ROOT, path,
258 '%s-9999.ebuild' % version)
259
Yaakov Shaul395ae832019-09-09 14:45:32 -0600260 portage_util.EBuild.UpdateEBuild(
Yaakov Shaul09e88272019-09-10 12:01:04 -0600261 ebuild_path,
262 dict(AFDO_PROFILE_VERSION=version_info['name']),
263 make_stable=False)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600264 paths.append(ebuild_path)
265
Yaakov Shaula187b152019-09-11 12:41:32 -0600266 cmd = ['ebuild', chroot_ebuild_path, 'manifest', '--force']
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600267
268 try:
269 cros_build_lib.RunCommand(cmd, enter_chroot=True)
270 except cros_build_lib.RunCommandError as e:
271 raise EbuildManifestError(
272 'Error encountered when regenerating the manifest for ebuild: %s\n%s'
Yaakov Shaula187b152019-09-11 12:41:32 -0600273 % (chroot_ebuild_path, e), e)
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600274
Yaakov Shauldd8b4112019-09-11 11:44:03 -0600275 manifest_path = os.path.join(constants.SOURCE_ROOT, path, 'Manifest')
Yaakov Shaul1eafe832019-09-10 16:50:26 -0600276 paths.append(manifest_path)
277
David Burger92485342019-09-10 17:52:45 -0600278 return UprevVersionedPackageResult('test version', paths)
Yaakov Shaul395ae832019-09-09 14:45:32 -0600279
280
Alex Klein87531182019-08-12 15:23:37 -0600281@uprevs_versioned_package(constants.CHROME_CP)
282def uprev_chrome(build_targets, refs, chroot):
283 """Uprev chrome and its related packages.
284
285 See: uprev_versioned_package.
286 """
287 # Determine the version from the refs (tags), i.e. the chrome versions are the
288 # tag names.
289 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
290
291 uprev_manager = uprev_lib.UprevChromeManager(
292 chrome_version, build_targets=build_targets, chroot=chroot)
293 # Start with chrome itself, as we can't do anything else unless chrome
294 # uprevs successfully.
295 if not uprev_manager.uprev(constants.CHROME_CP):
296 return []
297
298 # With a successful chrome rev, also uprev related packages.
299 for package in constants.OTHER_CHROME_PACKAGES:
300 uprev_manager.uprev(package)
301
Alex Klein34afcbc2019-08-22 16:14:31 -0600302 return UprevVersionedPackageResult(chrome_version,
303 uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600304
305
Alex Kleinbbef2b32019-08-27 10:38:50 -0600306def get_best_visible(atom, build_target=None):
307 """Returns the best visible CPV for the given atom.
308
309 Args:
310 atom (str): The atom to look up.
311 build_target (build_target_util.BuildTarget): The build target whose
Alex Kleinda39c6d2019-09-16 14:36:36 -0600312 sysroot should be searched, or the SDK if not provided.
Alex Kleinbbef2b32019-08-27 10:38:50 -0600313 """
David Burger1e0fe232019-07-01 14:52:07 -0600314 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600315
316 board = build_target.name if build_target else None
317 return portage_util.PortageqBestVisible(atom, board=board)
Alex Kleinda39c6d2019-09-16 14:36:36 -0600318
319
320def has_prebuilt(atom, build_target=None):
321 """Check if a prebuilt exists.
322
323 Args:
324 atom (str): The package whose prebuilt is being queried.
325 build_target (build_target_util.BuildTarget): The build target whose
326 sysroot should be searched, or the SDK if not provided.
327 """
328 assert atom
329
330 board = build_target.name if build_target else None
331 return portage_util.HasPrebuilt(atom, board=board)