Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: scripts/tools/cros/cros_builder_convert.py

Issue 1068263003: CrOS: Update public waterfall to auto-configure. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Added experimental/documentation annotations to web UI. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « scripts/master/cros/builder_config.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2015 The Chromium 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 """Updates BuildBot builder directories to the new 'cbuildbot'-driven naming
7 scheme.
8
9 Classic BuildBot CrOS waterfalls define build directories by composing the
10 directory name from component parts resembling the target and a final branch
11 name. Oftentimes, these component parts (and, therefore, the composition) don't
12 actually match the name of the underlying 'cbuildbot' target.
13
14 This presents problems because the build target are fundamentally driven by
15 their underlying 'cbuildbot' target, but the composition scheme is extremely
16 arbitrary.
17
18 Consequently, BuildBot masters are being migrated to a new, deterministic,
19 'cbuildbot'-driven naming scheme. A builder building 'cbuildbot' target
20 <target> and checking Chromite/'cbuildbot' from branch <branch> will use the
21 builder name: <target>-<branch>. This is universally sustainable across all
22 waterfalls and ensures that 'cbuildbot' builds are tracked and numbered based
23 on their underlying 'cbuildbot' target.
24
25 This script is intended to be run on a stopped BuildBot master during build
26 directory migration. It will iterate through each build directory in the current
27 master naming scheme and rename the classic directories into their new
28 'cbuildbot'-driven namespace.
29 """
30
31 import argparse
32 import collections
33 import logging
34 import os
35 import re
36 import shutil
37 import sys
38
39 from common import cros_chromite
40
41
42 class UpdateInfo(collections.namedtuple(
43 'UpdateInfo',
44 ('src', 'cbb_name', 'branch'))):
45 """Information about a single directory update action."""
46
47 _STATIC_PERMUTATIONS = {
48 'Canary master': 'master-canary',
49 }
50
51 _TRANSFORMATIONS = (
52 (r'-canary-', r'-release-'),
53 (r'(x86|amd64)$', r'\1-generic'),
54 (r'^chromium-tot-chromeos-(.+)-asan', r'\1-tot-asan-informational'),
55 (r'^chromium-tot-chromeos-(.+)', r'\1-tot-chrome-pfq-informational'),
56 (r'^chromium-(.+)-telemetry$', r'\1-telemetry'),
57 (r'(.+)-bin$', r'\1'),
58 )
59
60 @property
61 def dst(self):
62 """Constructs the <cbuildbot>-<branch> form."""
63 return '%s-%s' % (self.cbb_name, self.branch)
64
65 @classmethod
66 def permutations(cls, name):
67 """Attempts to permute a legacy BuildBot name into a Chromite target.
68
69 Args:
70 name (str): The source name to process and map.
71 Yields (str): Various permutations of 'name'.
72 """
73 # No cbuildbot targets use upper-case letters.
74 name = name.lower()
75
76 # If 'name' is already a 'cbuildbot' target, return it unmodified.
77 yield name
78
79 # Apply static permutations.
80 p = cls._STATIC_PERMUTATIONS.get(name)
81 if p:
82 yield p
83
84 # Replace 'canary' with 'release'.
85 for find, replace in cls._TRANSFORMATIONS:
86 name = re.sub(find, replace, name)
87 print find, replace, name
88 yield name
89
90 # Is 'name' valid if it was a release group?
91 if not name.endswith('-group'):
92 # We never build 'full' group variants.
93 name_group = ('%s-group' % (name,)).replace('-full-', '-release-')
94 yield name_group
95
96 @classmethod
97 def process(cls, config, name, default_branch):
98 """Construct an UpdateInfo to map a source name.
99
100 This function works by attempting to transform a source name into a known
101 'cbuildbot' target name. If successful, it will use that successful
102 transformation as validation of the correctness and return an UpdateInfo
103 describing the transformation.
104
105 Args:
106 config (cros_chromite.ChromiteConfig) The Chromite config instance.
107 name (str): The source name to process and map.
108 default_branch (str): The default branch to apply if the field is empty.
109 Returns (UpdateInfo/None): The constructed UpdateInfo, or None if there was
110 no identified mapping.
111 """
112 def sliding_split_gen():
113 parts = name.split('-')
114 for i in xrange(len(parts), 0, -1):
115 yield '-'.join(parts[:i]), '-'.join(parts[i:])
116
117 logging.debug("Processing candidate name: %s", name)
118 candidates = set()
119 branch = None
120 for orig_name, branch in sliding_split_gen():
121 logging.debug("Trying construction: Name(%s), Branch(%s)",
122 orig_name, branch)
123
124 # See if we can properly permute the original name.
125 for permuted_name in cls.permutations(orig_name):
126 if permuted_name in config:
127 candidates.add(permuted_name)
128 if not candidates:
129 logging.debug("No 'cbuildbot' config for attempts [%s] branch [%s].",
130 orig_name, branch)
131 continue
132
133 # We've found a permutation that matches a 'cbuildbot' target.
134 break
135 else:
136 logging.info("No 'cbuildbot' permutations for [%s].", name)
137 return None
138
139 if not branch:
140 # We need to do an update to add the branch. Default to 'master'.
141 branch = default_branch
142
143 candidates = sorted(candidates)
144 for candidate in candidates:
145 logging.debug("Identified 'cbuildbot' name [%s] => [%s] branch [%s].",
146 name, candidate, branch)
147 return [cls(name, p, branch) for p in candidates]
148
149
150 def main(args):
151 """Main execution function.
152
153 Args:
154 args (list): Command-line argument array.
155 """
156 parser = argparse.ArgumentParser()
157 parser.add_argument('path', nargs='+', metavar='PATH',
158 help='The path to the master directory to process.')
159 parser.add_argument('-v', '--verbose', action='count', default=0,
160 help='Increase verbosity. Can be specified multiple times.')
161 parser.add_argument('-d', '--dry-run', action='store_true',
162 help="Print what actions will be taken, but don't modify anything.")
163 parser.add_argument('-B', '--branch', default='master',
164 help="The branch to use, if one is not present (default is %(default)s)")
165 parser.add_argument('-n', '--names', action='store_true',
166 help="If specified, then regard 'path' as directory names to test.")
167 args = parser.parse_args()
168
169 # Select verbosity.
170 if args.verbose == 0:
171 loglevel = logging.WARNING
172 elif args.verbose == 1:
173 loglevel = logging.INFO
174 else:
175 loglevel = logging.DEBUG
176 logging.getLogger().setLevel(loglevel)
177
178 # Load our Chromite config. We're going to load ToT.
179 cbuildbot_config = cros_chromite.Get()
180
181 # If we're just testing against names, do that.
182 if args.names:
183 errors = 0
184 for n in args.path:
185 update_info = UpdateInfo.process(cbuildbot_config, n, args.branch)
186 if update_info:
187 logging.warning("[%s] => [%s]", update_info.src, update_info.dst)
188 else:
189 logging.warning("No transformation for name [%s].", n)
190 errors += 1
191 return errors
192
193 # Construct the set of actions to take.
194 cbb_already = set()
195 unmatched = set()
196 multiples = {}
197 updates = []
198 for path in args.path:
199 if not os.path.isdir(path):
200 raise ValueError("Supplied master directory is not valid: %s" % (path,))
201
202 seen = set()
203 for f in os.listdir(path):
204 f_path = os.path.join(path, f)
205 if not os.path.isdir(f_path):
206 continue
207
208 update_info_list = UpdateInfo.process(cbuildbot_config, f, args.branch)
209 if not update_info_list:
210 logging.info("No update information for directory [%s]", f)
211 unmatched.add(f)
212 continue
213 elif len(update_info_list) != 1:
214 multiples[f] = update_info_list
215 continue
216 update_info = update_info_list[0]
217
218 # Make sure that we don't stomp on directory names. This shouldn't happen,
219 # since the mapping to 'cbuildbot' names is inherently deconflicting, but
220 # it's good to assert it just in case.
221 update_info_names = set((update_info.src, update_info.dst))
222 if update_info_names.intersection(seen):
223 logging.error("Updated names intersect with existing names: %s",
224 ", ".join(update_info_names.intersection(seen)))
225 return 1
226 seen.update(update_info_names)
227
228 # We are already in <cbuildbot>-<branch> format, so do nothing.
229 if update_info.src == update_info.dst:
230 cbb_already.add(update_info.src)
231 else:
232 updates.append((path, update_info))
233
234 # Execute the updates.
235 logging.info("Executing %d updates.", len(updates))
236 for master_dir, update_info in updates:
237 logging.info("Updating [%s]: [%s] => [%s]", master_dir, update_info.src,
238 update_info.dst)
239 if not args.dry_run:
240 shutil.move(os.path.join(master_dir, update_info.src),
241 os.path.join(master_dir, update_info.dst))
242 logging.info("Updated %d directories.", len(updates))
243 if logging.getLogger().isEnabledFor(logging.DEBUG):
244 logging.debug("%d directories already matching: %s",
245 len(cbb_already), ', '.join(sorted(cbb_already)))
246 if unmatched:
247 logging.warning("%d unmatched directories: %s",
248 len(unmatched), ', '.join(sorted(unmatched)))
249 if multiples:
250 for f in sorted(multiples.iterkeys()):
251 logging.warning("Multiple permutations of [%s]: %s",
252 f, ", ".join(m.dst for m in multiples[f]))
253 return 0
254
255
256 if __name__ == '__main__':
257 logging.basicConfig()
258 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « scripts/master/cros/builder_config.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698