blob: 263ef952e5e04d5cb127b19b702388f17012b601 [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
Evan Hernandezb51f1522019-08-15 11:29:40 -060011import os
Alex Klein87531182019-08-12 15:23:37 -060012
Alex Kleineb77ffa2019-05-28 14:47:44 -060013from chromite.lib import constants
Evan Hernandezb51f1522019-08-15 11:29:40 -060014from chromite.lib import cros_build_lib
Alex Klein4de25e82019-08-05 15:58:39 -060015from chromite.lib import cros_logging as logging
Alex Kleineb77ffa2019-05-28 14:47:44 -060016from chromite.lib import git
Evan Hernandezb51f1522019-08-15 11:29:40 -060017from chromite.lib import osutils
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
Alex Klein34afcbc2019-08-22 16:14:31 -060054class UprevVersionedPackageResult(object):
55 """Result data object for uprev_versioned_package."""
56
57 def __init__(self, new_version=None, modified_ebuilds=None):
58 self.new_version = new_version
59 self.modified_ebuilds = modified_ebuilds or []
60
61 @property
62 def uprevved(self):
63 return bool(self.new_version)
64
65
Alex Klein87531182019-08-12 15:23:37 -060066def uprevs_versioned_package(package):
67 """Decorator to register package uprev handlers."""
68 assert package
69
70 def register(func):
71 """Registers |func| as a handler for |package|."""
72 _UPREV_FUNCS[package] = func
73
74 @functools.wraps(func)
75 def pass_through(*args, **kwargs):
76 return func(*args, **kwargs)
77
78 return pass_through
79
80 return register
81
82
Alex Klein4de25e82019-08-05 15:58:39 -060083def uprev_android(tracking_branch, android_package, android_build_branch,
84 chroot, build_targets=None, android_version=None,
85 android_gts_build_branch=None):
86 """Returns the portage atom for the revved Android ebuild - see man emerge."""
87 command = ['cros_mark_android_as_stable',
88 '--tracking_branch=%s' % tracking_branch,
89 '--android_package=%s' % android_package,
90 '--android_build_branch=%s' % android_build_branch]
91 if build_targets:
92 command.append('--boards=%s' % ':'.join(bt.name for bt in build_targets))
93 if android_version:
94 command.append('--force_version=%s' % android_version)
95 if android_gts_build_branch:
96 command.append('--android_gts_build_branch=%s' % android_gts_build_branch)
97
98 result = cros_build_lib.RunCommand(command, redirect_stdout=True,
99 enter_chroot=True,
100 chroot_args=chroot.get_enter_args())
101
102 android_atom = _parse_android_atom(result)
103 if not android_atom:
104 logging.info('Found nothing to rev.')
105 return None
106
107 for target in build_targets or []:
108 # Sanity check: We should always be able to merge the version of
109 # Android we just unmasked.
110 command = ['emerge-%s' % target.name, '-p', '--quiet',
111 '=%s' % android_atom]
112 try:
113 cros_build_lib.RunCommand(command, enter_chroot=True,
114 chroot_args=chroot.get_enter_args())
115 except cros_build_lib.RunCommandError:
116 logging.error(
117 'Cannot emerge-%s =%s\nIs Android pinned to an older '
118 'version?', target, android_atom)
119 raise AndroidIsPinnedUprevError(android_atom)
120
121 return android_atom
122
123
124def _parse_android_atom(result):
125 """Helper to parse the atom from the cros_mark_android_as_stable output.
126
127 This function is largely just intended to make testing easier.
128
129 Args:
130 result (cros_build_lib.CommandResult): The cros_mark_android_as_stable
131 command result.
132 """
133 portage_atom_string = result.output.strip()
134
135 android_atom = None
136 if portage_atom_string:
137 android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
138
139 return android_atom
140
141
Alex Kleineb77ffa2019-05-28 14:47:44 -0600142def uprev_build_targets(build_targets, overlay_type, chroot=None,
143 output_dir=None):
144 """Uprev the set provided build targets, or all if not specified.
145
146 Args:
147 build_targets (list[build_target_util.BuildTarget]|None): The build targets
148 whose overlays should be uprevved, empty or None for all.
149 overlay_type (str): One of the valid overlay types except None (see
150 constants.VALID_OVERLAYS).
151 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
152 output_dir (str|None): The path to optionally dump result files.
153 """
154 # Need a valid overlay, but exclude None.
155 assert overlay_type and overlay_type in constants.VALID_OVERLAYS
156
157 if build_targets:
158 overlays = portage_util.FindOverlaysForBoards(
159 overlay_type, boards=[t.name for t in build_targets])
160 else:
161 overlays = portage_util.FindOverlays(overlay_type)
162
163 return uprev_overlays(overlays, build_targets=build_targets, chroot=chroot,
164 output_dir=output_dir)
165
166
167def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
168 """Uprev the given overlays.
169
170 Args:
171 overlays (list[str]): The list of overlay paths.
172 build_targets (list[build_target_util.BuildTarget]|None): The build targets
173 to clean in |chroot|, if desired. No effect unless |chroot| is provided.
174 chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
175 output_dir (str|None): The path to optionally dump result files.
176
177 Returns:
178 list[str] - The paths to all of the modified ebuild files. This includes the
179 new files that were added (i.e. the new versions) and all of the removed
180 files (i.e. the old versions).
181 """
182 assert overlays
183
184 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
185
Alex Kleind6195b62019-08-06 16:01:16 -0600186 uprev_manager = uprev_lib.UprevOverlayManager(overlays, manifest,
187 build_targets=build_targets,
188 chroot=chroot,
189 output_dir=output_dir)
Alex Kleineb77ffa2019-05-28 14:47:44 -0600190 uprev_manager.uprev()
191
192 return uprev_manager.modified_ebuilds
193
194
Alex Klein87531182019-08-12 15:23:37 -0600195def uprev_versioned_package(package, build_targets, refs, chroot):
196 """Call registered uprev handler function for the package.
197
198 Args:
199 package (portage_util.CPV): The package being uprevved.
200 build_targets (list[build_target_util.BuildTarget]): The build targets to
201 clean on a successful uprev.
202 refs (list[uprev_lib.GitRef]):
203 chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
204
205 Returns:
Alex Klein34afcbc2019-08-22 16:14:31 -0600206 UprevVersionedPackageResult: The result.
Alex Klein87531182019-08-12 15:23:37 -0600207 """
208 assert package
209
210 if package.cp not in _UPREV_FUNCS:
211 raise UnknownPackageError(
212 'Package "%s" does not have a registered handler.' % package.cp)
213
214 return _UPREV_FUNCS[package.cp](build_targets, refs, chroot)
215
216
Evan Hernandezb51f1522019-08-15 11:29:40 -0600217# TODO(evanhernandez): Remove this. Only a quick hack for testing.
218@uprevs_versioned_package('sample/sample')
219def uprev_sample(*_args, **_kwargs):
220 """Mimics an uprev by changing files in sandbox repos.
221
222 See: uprev_versioned_package.
223 """
224 paths = [
225 os.path.join(constants.SOURCE_ROOT, 'infra/dummies', repo, 'sample.txt')
226 for repo in ('general-sandbox', 'merge-sandbox')
227 ]
228
229 for path in paths:
230 osutils.WriteFile(path, cros_build_lib.GetRandomString())
231
Evan Hernandez3d311d82019-08-28 13:57:43 -0600232 return UprevVersionedPackageResult('1.2.3', paths)
Evan Hernandezb51f1522019-08-15 11:29:40 -0600233
234
Alex Klein87531182019-08-12 15:23:37 -0600235@uprevs_versioned_package(constants.CHROME_CP)
236def uprev_chrome(build_targets, refs, chroot):
237 """Uprev chrome and its related packages.
238
239 See: uprev_versioned_package.
240 """
241 # Determine the version from the refs (tags), i.e. the chrome versions are the
242 # tag names.
243 chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
244
245 uprev_manager = uprev_lib.UprevChromeManager(
246 chrome_version, build_targets=build_targets, chroot=chroot)
247 # Start with chrome itself, as we can't do anything else unless chrome
248 # uprevs successfully.
249 if not uprev_manager.uprev(constants.CHROME_CP):
250 return []
251
252 # With a successful chrome rev, also uprev related packages.
253 for package in constants.OTHER_CHROME_PACKAGES:
254 uprev_manager.uprev(package)
255
Alex Klein34afcbc2019-08-22 16:14:31 -0600256 return UprevVersionedPackageResult(chrome_version,
257 uprev_manager.modified_ebuilds)
Alex Klein87531182019-08-12 15:23:37 -0600258
259
Alex Kleinbbef2b32019-08-27 10:38:50 -0600260def get_best_visible(atom, build_target=None):
261 """Returns the best visible CPV for the given atom.
262
263 Args:
264 atom (str): The atom to look up.
265 build_target (build_target_util.BuildTarget): The build target whose
266 sysroot should be searched.
267 """
David Burger1e0fe232019-07-01 14:52:07 -0600268 assert atom
Alex Kleinbbef2b32019-08-27 10:38:50 -0600269
270 board = build_target.name if build_target else None
271 return portage_util.PortageqBestVisible(atom, board=board)