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

Side by Side Diff: bin/cbuildbot.py

Issue 3266004: Move RunCommand, and Info/Warning/Die into common pylib (Closed) Base URL: ssh://git@chromiumos-git//crosutils.git
Patch Set: rebased Created 10 years, 3 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
« no previous file with comments | « archive_hwqual ('k') | bin/cbuildbot_comm.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """CBuildbot is wrapper around the build process used by the pre-flight queue""" 7 """CBuildbot is wrapper around the build process used by the pre-flight queue"""
8 8
9 import errno 9 import errno
10 import re 10 import re
11 import optparse 11 import optparse
12 import os 12 import os
13 import subprocess
14 import sys 13 import sys
15 14
16 import cbuildbot_comm 15 import cbuildbot_comm
17 from cbuildbot_config import config 16 from cbuildbot_config import config
18 17
18 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib'))
19 from cros_build_lib import Die, Info, RunCommand, Warning
20
19 _DEFAULT_RETRIES = 3 21 _DEFAULT_RETRIES = 3
20 22
21 # ======================== Utility functions ================================ 23 # ======================== Utility functions ================================
22 24
23 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None,
24 exit_code=False, redirect_stdout=False, redirect_stderr=False,
25 cwd=None, input=None, enter_chroot=False):
26 """Runs a shell command.
27
28 Keyword arguments:
29 print_cmd -- prints the command before running it.
30 error_ok -- does not raise an exception on error.
31 error_message -- prints out this message when an error occurrs.
32 exit_code -- returns the return code of the shell command.
33 redirect_stdout -- returns the stdout.
34 redirect_stderr -- holds stderr output until input is communicated.
35 cwd -- the working directory to run this cmd.
36 input -- input to pipe into this command through stdin.
37 enter_chroot -- this command should be run from within the chroot.
38
39 """
40 # Set default for variables.
41 stdout = None
42 stderr = None
43 stdin = None
44
45 # Modify defaults based on parameters.
46 if redirect_stdout: stdout = subprocess.PIPE
47 if redirect_stderr: stderr = subprocess.PIPE
48 if input: stdin = subprocess.PIPE
49 if enter_chroot: cmd = ['./enter_chroot.sh', '--'] + cmd
50
51 # Print out the command before running.
52 if print_cmd:
53 print >> sys.stderr, 'CBUILDBOT -- RunCommand: ', ' '.join(cmd)
54
55 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin,
56 stdout=stdout, stderr=stderr)
57 (output, error) = proc.communicate(input)
58 if exit_code:
59 return proc.returncode
60
61 if not error_ok and proc.returncode != 0:
62 raise Exception('Command "%s" failed.\n' % (' '.join(cmd)) +
63 (error_message or error or output or ''))
64
65 return output
66
67
68 def MakeDir(path, parents=False): 25 def MakeDir(path, parents=False):
69 """Basic wrapper around os.mkdirs. 26 """Basic wrapper around os.mkdirs.
70 27
71 Keyword arguments: 28 Keyword arguments:
72 path -- Path to create. 29 path -- Path to create.
73 parents -- Follow mkdir -p logic. 30 parents -- Follow mkdir -p logic.
74 31
75 """ 32 """
76 try: 33 try:
77 os.makedirs(path) 34 os.makedirs(path)
(...skipping 19 matching lines...) Expand all
97 # Always re-run in case of new git repos or repo sync 54 # Always re-run in case of new git repos or repo sync
98 # failed in a previous run because of a forced Stop Build. 55 # failed in a previous run because of a forced Stop Build.
99 RunCommand(['repo', 'forall', '-c', 'git', 'config', 56 RunCommand(['repo', 'forall', '-c', 'git', 'config',
100 'url.ssh://git@gitrw.chromium.org:9222.pushinsteadof', 57 'url.ssh://git@gitrw.chromium.org:9222.pushinsteadof',
101 'http://git.chromium.org/git'], cwd=buildroot) 58 'http://git.chromium.org/git'], cwd=buildroot)
102 59
103 retries = 0 60 retries = 0
104 except: 61 except:
105 retries -= 1 62 retries -= 1
106 if retries > 0: 63 if retries > 0:
107 print >> sys.stderr, 'CBUILDBOT -- Repo Sync Failed, retrying' 64 Warning('CBUILDBOT -- Repo Sync Failed, retrying')
108 else: 65 else:
109 print >> sys.stderr, 'CBUILDBOT -- Retries exhausted' 66 Warning('CBUILDBOT -- Retries exhausted')
110 raise 67 raise
111 68
112 # =========================== Command Helpers ================================= 69 # =========================== Command Helpers =================================
113 70
114 def _GetAllGitRepos(buildroot, debug=False): 71 def _GetAllGitRepos(buildroot, debug=False):
115 """Returns a list of tuples containing [git_repo, src_path].""" 72 """Returns a list of tuples containing [git_repo, src_path]."""
116 manifest_tuples = [] 73 manifest_tuples = []
117 # Gets all the git repos from a full repo manifest. 74 # Gets all the git repos from a full repo manifest.
118 repo_cmd = "repo manifest -o -".split() 75 repo_cmd = "repo manifest -o -".split()
119 output = RunCommand(repo_cmd, cwd=buildroot, redirect_stdout=True, 76 output = RunCommand(repo_cmd, cwd=buildroot, redirect_stdout=True,
120 redirect_stderr=True, print_cmd=debug) 77 redirect_stderr=True, print_cmd=debug)
121 78
122 # Extract all lines containg a project. 79 # Extract all lines containg a project.
123 extract_cmd = ["grep", "project name="] 80 extract_cmd = ["grep", "project name="]
124 output = RunCommand(extract_cmd, cwd=buildroot, input=output, 81 output = RunCommand(extract_cmd, cwd=buildroot, input=output,
125 redirect_stdout=True, print_cmd=debug) 82 redirect_stdout=True, print_cmd=debug)
126 # Parse line using re to get tuple. 83 # Parse line using re to get tuple.
127 result_array = re.findall('.+name=\"([\w-]+)\".+path=\"(\S+)".+', output) 84 result_array = re.findall('.+name=\"([\w-]+)\".+path=\"(\S+)".+', output)
128 85
129 # Create the array. 86 # Create the array.
130 for result in result_array: 87 for result in result_array:
131 if len(result) != 2: 88 if len(result) != 2:
132 print >> sys.stderr, 'Found in correct xml object %s', result 89 Warning('Found incorrect xml object %s' % result)
133 else: 90 else:
134 # Remove pre-pended src directory from manifest. 91 # Remove pre-pended src directory from manifest.
135 manifest_tuples.append([result[0], result[1].replace('src/', '')]) 92 manifest_tuples.append([result[0], result[1].replace('src/', '')])
136 93
137 return manifest_tuples 94 return manifest_tuples
138 95
139 96
140 def _GetCrosWorkOnSrcPath(buildroot, board, package, debug=False): 97 def _GetCrosWorkOnSrcPath(buildroot, board, package, debug=False):
141 """Returns ${CROS_WORKON_SRC_PATH} for given package.""" 98 """Returns ${CROS_WORKON_SRC_PATH} for given package."""
142 cwd = os.path.join(buildroot, 'src', 'scripts') 99 cwd = os.path.join(buildroot, 'src', 'scripts')
(...skipping 11 matching lines...) Expand all
154 if temp: 111 if temp:
155 return temp[0] 112 return temp[0]
156 113
157 return None 114 return None
158 115
159 116
160 def _CreateRepoDictionary(buildroot, board, debug=False): 117 def _CreateRepoDictionary(buildroot, board, debug=False):
161 """Returns the repo->list_of_ebuilds dictionary.""" 118 """Returns the repo->list_of_ebuilds dictionary."""
162 repo_dictionary = {} 119 repo_dictionary = {}
163 manifest_tuples = _GetAllGitRepos(buildroot) 120 manifest_tuples = _GetAllGitRepos(buildroot)
164 print >> sys.stderr, ( 121 Info('Creating dictionary of git repos to portage packages ...')
165 'Creating dictionary of git repos to portage packages ...')
166 122
167 cwd = os.path.join(buildroot, 'src', 'scripts') 123 cwd = os.path.join(buildroot, 'src', 'scripts')
168 get_all_workon_pkgs_cmd = './cros_workon list --all'.split() 124 get_all_workon_pkgs_cmd = './cros_workon list --all'.split()
169 packages = RunCommand(get_all_workon_pkgs_cmd, cwd=cwd, 125 packages = RunCommand(get_all_workon_pkgs_cmd, cwd=cwd,
170 redirect_stdout=True, redirect_stderr=True, 126 redirect_stdout=True, redirect_stderr=True,
171 enter_chroot=True, print_cmd=debug) 127 enter_chroot=True, print_cmd=debug)
172 for package in packages.split(): 128 for package in packages.split():
173 cros_workon_src_path = _GetCrosWorkOnSrcPath(buildroot, board, package) 129 cros_workon_src_path = _GetCrosWorkOnSrcPath(buildroot, board, package)
174 if cros_workon_src_path: 130 if cros_workon_src_path:
175 for tuple in manifest_tuples: 131 for tuple in manifest_tuples:
176 # This path tends to have the user's home_dir prepended to it. 132 # This path tends to have the user's home_dir prepended to it.
177 if cros_workon_src_path.endswith(tuple[1]): 133 if cros_workon_src_path.endswith(tuple[1]):
178 print >> sys.stderr, ('For %s found matching package %s' % 134 Info('For %s found matching package %s' % (tuple[0], package))
179 (tuple[0], package))
180 if repo_dictionary.has_key(tuple[0]): 135 if repo_dictionary.has_key(tuple[0]):
181 repo_dictionary[tuple[0]] += [package] 136 repo_dictionary[tuple[0]] += [package]
182 else: 137 else:
183 repo_dictionary[tuple[0]] = [package] 138 repo_dictionary[tuple[0]] = [package]
184 139
185 return repo_dictionary 140 return repo_dictionary
186 141
187 142
188 def _ParseRevisionString(revision_string, repo_dictionary): 143 def _ParseRevisionString(revision_string, repo_dictionary):
189 """Parses the given revision_string into a revision dictionary. 144 """Parses the given revision_string into a revision dictionary.
190 145
191 Returns a list of tuples that contain [portage_package_name, commit_id] to 146 Returns a list of tuples that contain [portage_package_name, commit_id] to
192 update. 147 update.
193 148
194 Keyword arguments: 149 Keyword arguments:
195 revision_string -- revision_string with format 150 revision_string -- revision_string with format
196 'repo1.git@commit_1 repo2.git@commit2 ...'. 151 'repo1.git@commit_1 repo2.git@commit2 ...'.
197 repo_dictionary -- dictionary with git repository names as keys (w/out git) 152 repo_dictionary -- dictionary with git repository names as keys (w/out git)
198 to portage package names. 153 to portage package names.
199 154
200 """ 155 """
201 # Using a dictionary removes duplicates. 156 # Using a dictionary removes duplicates.
202 revisions = {} 157 revisions = {}
203 for revision in revision_string.split(): 158 for revision in revision_string.split():
204 # Format 'package@commit-id'. 159 # Format 'package@commit-id'.
205 revision_tuple = revision.split('@') 160 revision_tuple = revision.split('@')
206 if len(revision_tuple) != 2: 161 if len(revision_tuple) != 2:
207 print >> sys.stderr, 'Incorrectly formatted revision %s' % revision 162 Warning('Incorrectly formatted revision %s' % revision)
208 163
209 repo_name = revision_tuple[0].replace('.git', '') 164 repo_name = revision_tuple[0].replace('.git', '')
210 # Might not have entry if no matching ebuild. 165 # Might not have entry if no matching ebuild.
211 if repo_dictionary.has_key(repo_name): 166 if repo_dictionary.has_key(repo_name):
212 # May be many corresponding packages to a given git repo e.g. kernel). 167 # May be many corresponding packages to a given git repo e.g. kernel).
213 for package in repo_dictionary[repo_name]: 168 for package in repo_dictionary[repo_name]:
214 revisions[package] = revision_tuple[1] 169 revisions[package] = revision_tuple[1]
215 170
216 return revisions.items() 171 return revisions.items()
217 172
218 173
219 def _UprevFromRevisionList(buildroot, revision_list): 174 def _UprevFromRevisionList(buildroot, revision_list):
220 """Uprevs based on revision list.""" 175 """Uprevs based on revision list."""
221 if not revision_list: 176 if not revision_list:
222 print >> sys.stderr, 'No packages found to uprev' 177 Info('No packages found to uprev')
223 return 178 return
224 179
225 package_str = '' 180 package_str = ''
226 commit_str = '' 181 commit_str = ''
227 for package, revision in revision_list: 182 for package, revision in revision_list:
228 package_str += package + ' ' 183 package_str += package + ' '
229 commit_str += revision + ' ' 184 commit_str += revision + ' '
230 185
231 package_str = package_str.strip() 186 package_str = package_str.strip()
232 commit_str = commit_str.strip() 187 commit_str = commit_str.strip()
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 uprev. 257 uprev.
303 """ 258 """
304 # Purposefully set to None as it means Force Build was pressed. 259 # Purposefully set to None as it means Force Build was pressed.
305 revisions = 'None' 260 revisions = 'None'
306 if (revisionfile): 261 if (revisionfile):
307 try: 262 try:
308 rev_file = open(revisionfile) 263 rev_file = open(revisionfile)
309 revisions = rev_file.read() 264 revisions = rev_file.read()
310 rev_file.close() 265 rev_file.close()
311 except Exception, e: 266 except Exception, e:
312 print >> sys.stderr, 'Error reading %s, revving all' % revisionfile 267 Warning('Error reading %s, revving all' % revisionfile)
313 print e
314 revisions = 'None' 268 revisions = 'None'
315 269
316 revisions = revisions.strip() 270 revisions = revisions.strip()
317 271
318 # TODO(sosa): Un-comment once we close individual trees. 272 # TODO(sosa): Un-comment once we close individual trees.
319 # Revisions == "None" indicates a Force Build. 273 # revisions == "None" indicates a Force Build.
320 #if revisions != 'None': 274 #if revisions != 'None':
321 # print >> sys.stderr, 'CBUILDBOT Revision list found %s' % revisions 275 # print >> sys.stderr, 'CBUILDBOT Revision list found %s' % revisions
322 # revision_list = _ParseRevisionString(revisions, 276 # revision_list = _ParseRevisionString(revisions,
323 # _CreateRepoDictionary(buildroot, board)) 277 # _CreateRepoDictionary(buildroot, board))
324 # _UprevFromRevisionList(buildroot, revision_list) 278 # _UprevFromRevisionList(buildroot, revision_list)
325 #else: 279 #else:
326 print >> sys.stderr, 'CBUILDBOT Revving all' 280 Info('CBUILDBOT Revving all')
327 _UprevAllPackages(buildroot) 281 _UprevAllPackages(buildroot)
328 282
329 283
330 def _UprevCleanup(buildroot): 284 def _UprevCleanup(buildroot):
331 """Clean up after a previous uprev attempt.""" 285 """Clean up after a previous uprev attempt."""
332 cwd = os.path.join(buildroot, 'src', 'scripts') 286 cwd = os.path.join(buildroot, 'src', 'scripts')
333 RunCommand(['./cros_mark_as_stable', '--srcroot=..', 287 RunCommand(['./cros_mark_as_stable', '--srcroot=..',
334 '--tracking_branch="cros/master"', 'clean'], 288 '--tracking_branch="cros/master"', 'clean'],
335 cwd=cwd) 289 cwd=cwd)
336 290
337 291
338 def _UprevPush(buildroot): 292 def _UprevPush(buildroot):
339 """Pushes uprev changes to the main line.""" 293 """Pushes uprev changes to the main line."""
340 cwd = os.path.join(buildroot, 'src', 'scripts') 294 cwd = os.path.join(buildroot, 'src', 'scripts')
341 RunCommand(['./cros_mark_as_stable', '--srcroot=..', 295 RunCommand(['./cros_mark_as_stable', '--srcroot=..',
342 '--tracking_branch="cros/master"', 296 '--tracking_branch="cros/master"',
343 '--push_options', '--bypass-hooks -f', 'push'], 297 '--push_options', '--bypass-hooks -f', 'push'],
344 cwd=cwd) 298 cwd=cwd)
345 299
346 300
347 def _GetConfig(config_name): 301 def _GetConfig(config_name):
348 """Gets the configuration for the build""" 302 """Gets the configuration for the build"""
349 default = config['default'] 303 default = config['default']
350 buildconfig = {} 304 buildconfig = {}
351 if not config.has_key(config_name): 305 if not config.has_key(config_name):
352 print >> sys.stderr, 'Non-existent configuration specified.' 306 Warning('Non-existent configuration specified.')
353 print >> sys.stderr, 'Please specify one of:' 307 Warning('Please specify one of:')
354 config_names = config.keys() 308 config_names = config.keys()
355 config_names.sort() 309 config_names.sort()
356 for name in config_names: 310 for name in config_names:
357 print >> sys.stderr, ' %s' % name 311 Warning(' %s' % name)
358 sys.exit(1) 312 sys.exit(1)
359 313
360 buildconfig = config[config_name] 314 buildconfig = config[config_name]
361 315
362 for key in default.iterkeys(): 316 for key in default.iterkeys():
363 if not buildconfig.has_key(key): 317 if not buildconfig.has_key(key):
364 buildconfig[key] = default[key] 318 buildconfig[key] = default[key]
365 319
366 return buildconfig 320 return buildconfig
367 321
(...skipping 16 matching lines...) Expand all
384 buildroot = options.buildroot 338 buildroot = options.buildroot
385 revisionfile = options.revisionfile 339 revisionfile = options.revisionfile
386 340
387 # Passed option to clobber. 341 # Passed option to clobber.
388 if options.clobber: 342 if options.clobber:
389 RunCommand(['sudo', 'rm', '-rf', buildroot]) 343 RunCommand(['sudo', 'rm', '-rf', buildroot])
390 344
391 if len(args) == 1: 345 if len(args) == 1:
392 buildconfig = _GetConfig(args[0]) 346 buildconfig = _GetConfig(args[0])
393 else: 347 else:
394 print >> sys.stderr, "Missing configuration description" 348 Warning('Missing configuration description')
395 parser.print_usage() 349 parser.print_usage()
396 sys.exit(1) 350 sys.exit(1)
397 351
398 try: 352 try:
399 if not os.path.isdir(buildroot): 353 if not os.path.isdir(buildroot):
400 _FullCheckout(buildroot) 354 _FullCheckout(buildroot)
401 else: 355 else:
402 _IncrementalCheckout(buildroot) 356 _IncrementalCheckout(buildroot)
403 357
404 chroot_path = os.path.join(buildroot, 'chroot') 358 chroot_path = os.path.join(buildroot, 'chroot')
(...skipping 14 matching lines...) Expand all
419 _BuildImage(buildroot) 373 _BuildImage(buildroot)
420 if buildconfig['uprev']: 374 if buildconfig['uprev']:
421 if buildconfig['master']: 375 if buildconfig['master']:
422 # Master bot needs to check if the other slaves completed. 376 # Master bot needs to check if the other slaves completed.
423 if cbuildbot_comm.HaveSlavesCompleted(config): 377 if cbuildbot_comm.HaveSlavesCompleted(config):
424 _UprevPush(buildroot) 378 _UprevPush(buildroot)
425 _UprevCleanup(buildroot) 379 _UprevCleanup(buildroot)
426 else: 380 else:
427 # At least one of the slaves failed or we timed out. 381 # At least one of the slaves failed or we timed out.
428 _UprevCleanup(buildroot) 382 _UprevCleanup(buildroot)
429 sys.stderr('CBUILDBOT - One of the slaves has failed!!!') 383 Die('CBUILDBOT - One of the slaves has failed!!!')
430 sys.exit(1)
431 else: 384 else:
432 # Publish my status to the master if its expecting it. 385 # Publish my status to the master if its expecting it.
433 if buildconfig['important']: 386 if buildconfig['important']:
434 cbuildbot_comm.PublishStatus(cbuildbot_comm.STATUS_BUILD_COMPLETE) 387 cbuildbot_comm.PublishStatus(cbuildbot_comm.STATUS_BUILD_COMPLETE)
435 388
436 _UprevCleanup(buildroot) 389 _UprevCleanup(buildroot)
437 except: 390 except:
438 # Send failure to master bot. 391 # Send failure to master bot.
439 if not buildconfig['master'] and buildconfig['important']: 392 if not buildconfig['master'] and buildconfig['important']:
440 cbuildbot_comm.PublishStatus(cbuildbot_comm.STATUS_BUILD_FAILED) 393 cbuildbot_comm.PublishStatus(cbuildbot_comm.STATUS_BUILD_FAILED)
441 394
442 raise 395 raise
443 396
444 397
445 if __name__ == '__main__': 398 if __name__ == '__main__':
446 main() 399 main()
OLDNEW
« no previous file with comments | « archive_hwqual ('k') | bin/cbuildbot_comm.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698