blob: fde13165e128956456a8f5803da41c98995cfd7e [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
Alex Kleinf4047132019-05-30 11:25:38 -06007import os
8
9from chromite.lib import constants
10from chromite.lib import commandline
11from chromite.lib import cros_build_lib
12from chromite.lib import cros_logging as logging
13from chromite.lib import git
14from chromite.lib import osutils
15from chromite.lib import parallel
16from chromite.lib import portage_util
17
18from chromite.cbuildbot import manifest_version
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
28def GetParser():
29 """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',
37 help='Force the stabilization of blacklisted packages. '
38 '(only compatible with -p)')
39 parser.add_argument('--overlay-type', required=True,
40 choices=['public', 'private', 'both'],
41 help='Populates --overlays based on "public", "private", '
42 'or "both".')
43 parser.add_argument('--packages',
44 help='Colon separated list of packages to rev.')
Alex Kleinf4047132019-05-30 11:25:38 -060045 parser.add_argument('--dump-files', action='store_true',
Mike Frysinger80de5012019-08-01 14:10:53 -040046 help='Dump the revved packages, new files list, and '
47 'removed files list files. This is mostly for'
48 'debugging right now.')
Alex Kleinf4047132019-05-30 11:25:38 -060049
50 return parser
51
52
53def _ParseArguments(argv):
54 """Parse and validate arguments."""
55 parser = GetParser()
56 options = parser.parse_args(argv)
57
58 # Parse, cleanup, and populate options.
59 if options.packages:
60 options.packages = options.packages.split(':')
61 if options.boards:
62 options.boards = options.boards.split(':')
63 options.overlays = portage_util.FindOverlays(options.overlay_type)
64
65 # Verify options.
66 if not options.packages and not options.all:
67 parser.error('Please specify at least one package (--packages)')
68 if options.force and options.all:
69 parser.error('Cannot use --force with --all. You must specify a list of '
70 'packages you want to force uprev.')
71
72 options.Freeze()
73 return options
74
75
76def main(argv):
77 options = _ParseArguments(argv)
78
79 if not options.boards:
80 overlays = portage_util.FindOverlays(options.overlay_type)
81 else:
82 overlays = set()
83 for board in options.boards:
84 board_overlays = portage_util.FindOverlays(options.overlay_type,
85 board=board)
86 overlays = overlays.union(board_overlays)
87
88 overlays = list(overlays)
89
90 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
91
92 _WorkOnCommit(options, overlays, manifest, options.packages or None)
93
94
95def CleanStalePackages(boards, package_atoms, chroot):
96 """Cleans up stale package info from a previous build.
97
98 Args:
99 boards: Boards to clean the packages from.
100 package_atoms: A list of package atoms to unmerge.
101 chroot (str): The chroot path.
102 """
103 if package_atoms:
104 logging.info('Cleaning up stale packages %s.', package_atoms)
105
106 # First unmerge all the packages for a board, then eclean it.
107 # We need these two steps to run in order (unmerge/eclean),
108 # but we can let all the boards run in parallel.
109 def _CleanStalePackages(board):
110 if board:
111 suffix = '-' + board
Mike Frysinger45602c72019-09-22 02:15:11 -0400112 runcmd = cros_build_lib.run
Alex Kleinf4047132019-05-30 11:25:38 -0600113 else:
114 suffix = ''
Mike Frysinger45602c72019-09-22 02:15:11 -0400115 runcmd = cros_build_lib.sudo_run
Alex Kleinf4047132019-05-30 11:25:38 -0600116
117 chroot_args = ['--chroot', chroot] if chroot else None
118 emerge, eclean = 'emerge' + suffix, 'eclean' + suffix
119 if not osutils.FindMissingBinaries([emerge, eclean]):
120 if package_atoms:
121 # If nothing was found to be unmerged, emerge will exit(1).
122 result = runcmd([emerge, '-q', '--unmerge'] + list(package_atoms),
123 enter_chroot=True, chroot_args=chroot_args,
124 extra_env={'CLEAN_DELAY': '0'},
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500125 check=False, cwd=constants.SOURCE_ROOT)
Alex Kleinf4047132019-05-30 11:25:38 -0600126 if result.returncode not in (0, 1):
127 raise cros_build_lib.RunCommandError('unexpected error', result)
128 runcmd([eclean, '-d', 'packages'],
129 cwd=constants.SOURCE_ROOT, enter_chroot=True,
Mike Frysinger0282d222019-12-17 17:15:48 -0500130 chroot_args=chroot_args, stdout=True,
131 stderr=True)
Alex Kleinf4047132019-05-30 11:25:38 -0600132
133 tasks = []
134 for board in boards:
135 tasks.append([board])
136 tasks.append([None])
137
138 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
139
140
141def _WorkOnCommit(options, overlays, manifest, package_list):
142 """Commit uprevs of overlays belonging to different git projects in parallel.
143
144 Args:
145 options: The options object returned by the argument parser.
146 overlays: A list of overlays to work on.
147 manifest: The manifest of the given source root.
148 package_list: A list of packages passed from commandline to work on.
149 """
150 overlay_ebuilds = _GetOverlayToEbuildsMap(overlays, package_list,
151 options.force)
152
153 with parallel.Manager() as manager:
154 # Contains the array of packages we actually revved.
155 revved_packages = manager.list()
156 new_package_atoms = manager.list()
157 new_ebuild_files = manager.list()
158 removed_ebuild_files = manager.list()
159
160 inputs = [[manifest, [overlay], overlay_ebuilds, revved_packages,
161 new_package_atoms, new_ebuild_files, removed_ebuild_files]
162 for overlay in overlays]
163 parallel.RunTasksInProcessPool(_UprevOverlays, inputs)
164
165 if options.chroot and os.path.exists(options.chroot):
166 CleanStalePackages(options.boards or [], new_package_atoms,
167 options.chroot)
168
169 if options.dump_files:
170 osutils.WriteFile('/tmp/revved_packages', '\n'.join(revved_packages))
171 osutils.WriteFile('/tmp/new_ebuild_files', '\n'.join(new_ebuild_files))
172 osutils.WriteFile('/tmp/removed_ebuild_files',
173 '\n'.join(removed_ebuild_files))
174
175
176def _GetOverlayToEbuildsMap(overlays, package_list, force):
177 """Get ebuilds for overlays.
178
179 Args:
180 overlays: A list of overlays to work on.
181 package_list: A list of packages passed from commandline to work on.
182 force (bool): Whether to use packages even if in blacklist.
183
184 Returns:
185 A dict mapping each overlay to a list of ebuilds belonging to it.
186 """
187 root_version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
188 subdir_removal = manifest_version.VersionInfo('10363.0.0')
189 require_subdir_support = root_version < subdir_removal
190 use_all = not package_list
191
192 overlay_ebuilds = {}
193 inputs = [[overlay, use_all, package_list, force, require_subdir_support]
194 for overlay in overlays]
195 result = parallel.RunTasksInProcessPool(
196 portage_util.GetOverlayEBuilds, inputs)
197 for idx, ebuilds in enumerate(result):
198 overlay_ebuilds[overlays[idx]] = ebuilds
199
200 return overlay_ebuilds
201
202
203def _UprevOverlays(manifest, overlays, overlay_ebuilds,
204 revved_packages, new_package_atoms, new_ebuild_files,
205 removed_ebuild_files):
206 """Execute uprevs for overlays in sequence.
207
208 Args:
209 manifest: The manifest of the given source root.
210 overlays: A list over overlays to commit.
211 overlay_ebuilds: A dict mapping overlays to their ebuilds.
212 revved_packages: A shared list of revved packages.
213 new_package_atoms: A shared list of new package atoms.
214 new_ebuild_files: New stable ebuild paths.
215 removed_ebuild_files: Old ebuild paths that were removed.
216 """
217 for overlay in overlays:
218 if not os.path.isdir(overlay):
219 logging.warning('Skipping %s, which is not a directory.', overlay)
220 continue
221
222 ebuilds = overlay_ebuilds.get(overlay, [])
223 if not ebuilds:
224 continue
225
226 with parallel.Manager() as manager:
227 # Contains the array of packages we actually revved.
228 messages = manager.list()
229
230 inputs = [[overlay, ebuild, manifest, new_ebuild_files,
231 removed_ebuild_files, messages, revved_packages,
232 new_package_atoms] for ebuild in ebuilds]
233 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
234
235
236def _WorkOnEbuild(overlay, ebuild, manifest, new_ebuild_files,
237 removed_ebuild_files, messages, revved_packages,
238 new_package_atoms):
239 """Work on a single ebuild.
240
241 Args:
242 overlay: The overlay where the ebuild belongs to.
243 ebuild: The ebuild to work on.
244 manifest: The manifest of the given source root.
245 new_ebuild_files: New stable ebuild paths that were created.
246 removed_ebuild_files: Old ebuild paths that were removed.
247 messages: A share list of commit messages.
248 revved_packages: A shared list of revved packages.
249 new_package_atoms: A shared list of new package atoms.
250 """
251 logging.debug('Working on %s, info %s', ebuild.package,
252 ebuild.cros_workon_vars)
253 try:
254 result = ebuild.RevWorkOnEBuild(os.path.join(constants.SOURCE_ROOT, 'src'),
255 manifest)
David Burger8cf4a762020-03-09 10:33:38 -0600256 except portage_util.InvalidUprevSourceError as e:
257 logging.error('An error occurred while uprevving %s: %s',
258 ebuild.package, e)
259 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400260 except OSError:
Alex Kleinf4047132019-05-30 11:25:38 -0600261 logging.warning(
262 'Cannot rev %s\n'
263 'Note you will have to go into %s '
264 'and reset the git repo yourself.', ebuild.package, overlay)
265 raise
266
267 if result:
268 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
269
270 if ebuild_path_to_add:
271 new_ebuild_files.append(ebuild_path_to_add)
272 if ebuild_path_to_remove:
273 osutils.SafeUnlink(ebuild_path_to_remove)
274 removed_ebuild_files.append(ebuild_path_to_remove)
275
276 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
277 revved_packages.append(ebuild.package)
278 new_package_atoms.append('=%s' % new_package)