blob: 5a67a2865d576949a7453955363249b834571a35 [file] [log] [blame]
Alex Kleinf4047132019-05-30 11:25:38 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Simplified cros_mark_as_stable script."""
6
Chris McDonald59650c32021-07-20 15:29:28 -06007import logging
Alex Kleinf4047132019-05-30 11:25:38 -06008import os
Christian Flachfb8c9b32022-02-28 15:16:18 +01009from typing import Dict, List, Optional
Alex Kleinf4047132019-05-30 11:25:38 -060010
Ram Chandrasekar60f69f32022-06-03 22:49:30 +000011from chromite.lib import chromeos_version
Alex Kleinf4047132019-05-30 11:25:38 -060012from chromite.lib import commandline
Chris McDonald59650c32021-07-20 15:29:28 -060013from chromite.lib import constants
Alex Kleinf4047132019-05-30 11:25:38 -060014from chromite.lib import cros_build_lib
Alex Kleinf4047132019-05-30 11:25:38 -060015from chromite.lib import git
16from chromite.lib import osutils
17from chromite.lib import parallel
18from chromite.lib import portage_util
19
Mike Frysinger2688ef62020-02-16 00:00:46 -050020
Alex Kleinf4047132019-05-30 11:25:38 -060021# Commit message subject for uprevving Portage packages.
22GIT_COMMIT_SUBJECT = 'Marking set of ebuilds as stable'
23
24# Commit message for uprevving Portage packages.
25_GIT_COMMIT_MESSAGE = 'Marking 9999 ebuild for %s as stable.'
26
27
Christian Flachfb8c9b32022-02-28 15:16:18 +010028def GetParser() -> commandline.ArgumentParser:
Alex Kleinf4047132019-05-30 11:25:38 -060029 """Build the argument parser."""
30 parser = commandline.ArgumentParser(description=__doc__)
31
32 parser.add_argument('--all', action='store_true',
33 help='Mark all packages as stable.')
34 parser.add_argument('--boards', help='Colon-separated list of boards.')
35 parser.add_argument('--chroot', type='path', help='The chroot path.')
36 parser.add_argument('--force', action='store_true',
Cindy Linb794fed2021-12-09 20:58:40 +000037 help='Force the stabilization of manually uprevved '
38 'packages. (only compatible with -p)')
Jae Hoon Kim6b29d312022-07-29 23:30:27 +000039 parser.add_argument('--force-version', type=str,
40 help='Force the version of manually uprevved packages.')
Alex Kleinf4047132019-05-30 11:25:38 -060041 parser.add_argument('--overlay-type', required=True,
42 choices=['public', 'private', 'both'],
43 help='Populates --overlays based on "public", "private", '
44 'or "both".')
45 parser.add_argument('--packages',
46 help='Colon separated list of packages to rev.')
Alex Kleinf4047132019-05-30 11:25:38 -060047 parser.add_argument('--dump-files', action='store_true',
Mike Frysinger80de5012019-08-01 14:10:53 -040048 help='Dump the revved packages, new files list, and '
49 'removed files list files. This is mostly for'
50 'debugging right now.')
Alex Kleinf4047132019-05-30 11:25:38 -060051
52 return parser
53
54
Christian Flachfb8c9b32022-02-28 15:16:18 +010055def _ParseArguments(argv: List[str]) -> commandline.ArgumentNamespace:
Alex Kleinf4047132019-05-30 11:25:38 -060056 """Parse and validate arguments."""
57 parser = GetParser()
58 options = parser.parse_args(argv)
59
60 # Parse, cleanup, and populate options.
61 if options.packages:
62 options.packages = options.packages.split(':')
63 if options.boards:
64 options.boards = options.boards.split(':')
65 options.overlays = portage_util.FindOverlays(options.overlay_type)
66
67 # Verify options.
68 if not options.packages and not options.all:
69 parser.error('Please specify at least one package (--packages)')
70 if options.force and options.all:
71 parser.error('Cannot use --force with --all. You must specify a list of '
72 'packages you want to force uprev.')
73
74 options.Freeze()
75 return options
76
77
Christian Flachfb8c9b32022-02-28 15:16:18 +010078def main(argv: List[str]) -> None:
Alex Kleinf4047132019-05-30 11:25:38 -060079 options = _ParseArguments(argv)
80
81 if not options.boards:
82 overlays = portage_util.FindOverlays(options.overlay_type)
83 else:
84 overlays = set()
85 for board in options.boards:
86 board_overlays = portage_util.FindOverlays(options.overlay_type,
87 board=board)
88 overlays = overlays.union(board_overlays)
89
90 overlays = list(overlays)
91
92 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
93
94 _WorkOnCommit(options, overlays, manifest, options.packages or None)
95
96
Christian Flachfb8c9b32022-02-28 15:16:18 +010097def CleanStalePackages(boards: List[str], package_atoms: List[str],
98 chroot: str) -> None:
Alex Kleinf4047132019-05-30 11:25:38 -060099 """Cleans up stale package info from a previous build.
100
101 Args:
102 boards: Boards to clean the packages from.
103 package_atoms: A list of package atoms to unmerge.
Christian Flachfb8c9b32022-02-28 15:16:18 +0100104 chroot: The chroot path.
Alex Kleinf4047132019-05-30 11:25:38 -0600105 """
106 if package_atoms:
107 logging.info('Cleaning up stale packages %s.', package_atoms)
108
109 # First unmerge all the packages for a board, then eclean it.
110 # We need these two steps to run in order (unmerge/eclean),
111 # but we can let all the boards run in parallel.
Christian Flachfb8c9b32022-02-28 15:16:18 +0100112 def _CleanStalePackages(board: str):
Alex Kleinf4047132019-05-30 11:25:38 -0600113 if board:
114 suffix = '-' + board
Mike Frysinger45602c72019-09-22 02:15:11 -0400115 runcmd = cros_build_lib.run
Alex Kleinf4047132019-05-30 11:25:38 -0600116 else:
117 suffix = ''
Mike Frysinger45602c72019-09-22 02:15:11 -0400118 runcmd = cros_build_lib.sudo_run
Alex Kleinf4047132019-05-30 11:25:38 -0600119
120 chroot_args = ['--chroot', chroot] if chroot else None
121 emerge, eclean = 'emerge' + suffix, 'eclean' + suffix
122 if not osutils.FindMissingBinaries([emerge, eclean]):
123 if package_atoms:
124 # If nothing was found to be unmerged, emerge will exit(1).
125 result = runcmd([emerge, '-q', '--unmerge'] + list(package_atoms),
126 enter_chroot=True, chroot_args=chroot_args,
127 extra_env={'CLEAN_DELAY': '0'},
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500128 check=False, cwd=constants.SOURCE_ROOT)
Alex Kleinf4047132019-05-30 11:25:38 -0600129 if result.returncode not in (0, 1):
130 raise cros_build_lib.RunCommandError('unexpected error', result)
131 runcmd([eclean, '-d', 'packages'],
132 cwd=constants.SOURCE_ROOT, enter_chroot=True,
Mike Frysinger0282d222019-12-17 17:15:48 -0500133 chroot_args=chroot_args, stdout=True,
134 stderr=True)
Alex Kleinf4047132019-05-30 11:25:38 -0600135
136 tasks = []
137 for board in boards:
138 tasks.append([board])
139 tasks.append([None])
140
141 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
142
143
Christian Flachfb8c9b32022-02-28 15:16:18 +0100144def _WorkOnCommit(options: commandline.ArgumentNamespace, overlays: List[str],
145 manifest: git.ManifestCheckout,
146 package_list: Optional[List[str]]) -> None:
Alex Kleinf4047132019-05-30 11:25:38 -0600147 """Commit uprevs of overlays belonging to different git projects in parallel.
148
149 Args:
150 options: The options object returned by the argument parser.
151 overlays: A list of overlays to work on.
152 manifest: The manifest of the given source root.
153 package_list: A list of packages passed from commandline to work on.
154 """
155 overlay_ebuilds = _GetOverlayToEbuildsMap(overlays, package_list,
156 options.force)
157
158 with parallel.Manager() as manager:
159 # Contains the array of packages we actually revved.
160 revved_packages = manager.list()
161 new_package_atoms = manager.list()
162 new_ebuild_files = manager.list()
163 removed_ebuild_files = manager.list()
164
165 inputs = [[manifest, [overlay], overlay_ebuilds, revved_packages,
Jae Hoon Kim6b29d312022-07-29 23:30:27 +0000166 new_package_atoms, new_ebuild_files, removed_ebuild_files,
167 options]
Alex Kleinf4047132019-05-30 11:25:38 -0600168 for overlay in overlays]
169 parallel.RunTasksInProcessPool(_UprevOverlays, inputs)
170
171 if options.chroot and os.path.exists(options.chroot):
172 CleanStalePackages(options.boards or [], new_package_atoms,
173 options.chroot)
174
175 if options.dump_files:
176 osutils.WriteFile('/tmp/revved_packages', '\n'.join(revved_packages))
177 osutils.WriteFile('/tmp/new_ebuild_files', '\n'.join(new_ebuild_files))
178 osutils.WriteFile('/tmp/removed_ebuild_files',
179 '\n'.join(removed_ebuild_files))
180
181
Christian Flachfb8c9b32022-02-28 15:16:18 +0100182def _GetOverlayToEbuildsMap(overlays: List[str],
183 package_list: Optional[List[str]],
184 force: bool) -> Dict:
Alex Kleinf4047132019-05-30 11:25:38 -0600185 """Get ebuilds for overlays.
186
187 Args:
188 overlays: A list of overlays to work on.
189 package_list: A list of packages passed from commandline to work on.
Christian Flachfb8c9b32022-02-28 15:16:18 +0100190 force: Whether to use packages even if in manual uprev list.
Alex Kleinf4047132019-05-30 11:25:38 -0600191
192 Returns:
193 A dict mapping each overlay to a list of ebuilds belonging to it.
194 """
Ram Chandrasekar60f69f32022-06-03 22:49:30 +0000195 root_version = chromeos_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
196 subdir_removal = chromeos_version.VersionInfo('10363.0.0')
Alex Kleinf4047132019-05-30 11:25:38 -0600197 require_subdir_support = root_version < subdir_removal
198 use_all = not package_list
199
200 overlay_ebuilds = {}
201 inputs = [[overlay, use_all, package_list, force, require_subdir_support]
202 for overlay in overlays]
203 result = parallel.RunTasksInProcessPool(
204 portage_util.GetOverlayEBuilds, inputs)
205 for idx, ebuilds in enumerate(result):
206 overlay_ebuilds[overlays[idx]] = ebuilds
207
208 return overlay_ebuilds
209
210
Christian Flachfb8c9b32022-02-28 15:16:18 +0100211def _UprevOverlays(manifest: git.ManifestCheckout, overlays: List[str],
212 overlay_ebuilds: Dict, revved_packages: List[str],
213 new_package_atoms: List[str], new_ebuild_files: List[str],
Jae Hoon Kim6b29d312022-07-29 23:30:27 +0000214 removed_ebuild_files: List[str],
215 options: commandline.ArgumentNamespace) -> None:
Alex Kleinf4047132019-05-30 11:25:38 -0600216 """Execute uprevs for overlays in sequence.
217
218 Args:
219 manifest: The manifest of the given source root.
220 overlays: A list over overlays to commit.
221 overlay_ebuilds: A dict mapping overlays to their ebuilds.
222 revved_packages: A shared list of revved packages.
223 new_package_atoms: A shared list of new package atoms.
224 new_ebuild_files: New stable ebuild paths.
225 removed_ebuild_files: Old ebuild paths that were removed.
Jae Hoon Kim6b29d312022-07-29 23:30:27 +0000226 options: The options object returned by the argument parser.
Alex Kleinf4047132019-05-30 11:25:38 -0600227 """
228 for overlay in overlays:
229 if not os.path.isdir(overlay):
230 logging.warning('Skipping %s, which is not a directory.', overlay)
231 continue
232
233 ebuilds = overlay_ebuilds.get(overlay, [])
234 if not ebuilds:
235 continue
236
237 with parallel.Manager() as manager:
238 # Contains the array of packages we actually revved.
239 messages = manager.list()
240
241 inputs = [[overlay, ebuild, manifest, new_ebuild_files,
242 removed_ebuild_files, messages, revved_packages,
Jae Hoon Kim6b29d312022-07-29 23:30:27 +0000243 new_package_atoms, options] for ebuild in ebuilds]
Alex Kleinf4047132019-05-30 11:25:38 -0600244 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
245
246
Christian Flachfb8c9b32022-02-28 15:16:18 +0100247def _WorkOnEbuild(overlay: str, ebuild: portage_util.EBuild,
248 manifest: git.ManifestCheckout, new_ebuild_files: List[str],
249 removed_ebuild_files: List[str], messages: List[str],
250 revved_packages: List[str],
Jae Hoon Kim6b29d312022-07-29 23:30:27 +0000251 new_package_atoms: List[str],
252 options: commandline.ArgumentNamespace) -> None:
Alex Kleinf4047132019-05-30 11:25:38 -0600253 """Work on a single ebuild.
254
255 Args:
256 overlay: The overlay where the ebuild belongs to.
257 ebuild: The ebuild to work on.
258 manifest: The manifest of the given source root.
259 new_ebuild_files: New stable ebuild paths that were created.
260 removed_ebuild_files: Old ebuild paths that were removed.
261 messages: A share list of commit messages.
262 revved_packages: A shared list of revved packages.
263 new_package_atoms: A shared list of new package atoms.
Jae Hoon Kim6b29d312022-07-29 23:30:27 +0000264 options: The options object returned by the argument parser.
Alex Kleinf4047132019-05-30 11:25:38 -0600265 """
266 logging.debug('Working on %s, info %s', ebuild.package,
267 ebuild.cros_workon_vars)
268 try:
Jae Hoon Kim6b29d312022-07-29 23:30:27 +0000269 result = ebuild.RevWorkOnEBuild(
270 os.path.join(constants.SOURCE_ROOT, 'src'), manifest,
271 new_version=options.force_version)
David Burger8cf4a762020-03-09 10:33:38 -0600272 except portage_util.InvalidUprevSourceError as e:
273 logging.error('An error occurred while uprevving %s: %s',
274 ebuild.package, e)
275 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400276 except OSError:
Alex Kleinf4047132019-05-30 11:25:38 -0600277 logging.warning(
278 'Cannot rev %s\n'
279 'Note you will have to go into %s '
280 'and reset the git repo yourself.', ebuild.package, overlay)
281 raise
282
283 if result:
284 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
285
286 if ebuild_path_to_add:
287 new_ebuild_files.append(ebuild_path_to_add)
288 if ebuild_path_to_remove:
289 osutils.SafeUnlink(ebuild_path_to_remove)
290 removed_ebuild_files.append(ebuild_path_to_remove)
291
292 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
293 revved_packages.append(ebuild.package)
294 new_package_atoms.append('=%s' % new_package)