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

Side by Side Diff: bin/cbuildbot.py

Issue 3163030: CBuildbot - Adds ability to only packages given by the sourcestamp. (Closed) Base URL: http://src.chromium.org/git/crosutils.git
Patch Set: Fix 80 char Created 10 years, 4 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 | « no previous file | bin/cbuildbot_unittest.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"""
8
7 import errno 9 import errno
8 import optparse 10 import optparse
9 import os 11 import os
12 import re
10 import shutil 13 import shutil
11 import subprocess 14 import subprocess
12 import sys 15 import sys
13 16
14 from cbuildbot_config import config 17 from cbuildbot_config import config
15 18
16 _DEFAULT_RETRIES = 3 19 _DEFAULT_RETRIES = 3
17 20
18 # Utility functions 21 # ======================== Utility functions ================================
19 22
20 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None, 23 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None,
21 exit_code=False, redirect_stdout=False, redirect_stderr=False, 24 exit_code=False, redirect_stdout=False, redirect_stderr=False,
22 cwd=None, input=None): 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
23 # Print out the command before running. 51 # Print out the command before running.
24 if print_cmd: 52 if print_cmd:
25 print >> sys.stderr, "CBUILDBOT -- RunCommand:", ' '.join(cmd) 53 print >> sys.stderr, 'CBUILDBOT -- RunCommand: ', ' '.join(cmd)
26 if redirect_stdout: 54
27 stdout = subprocess.PIPE
28 else:
29 stdout = None
30 if redirect_stderr:
31 stderr = subprocess.PIPE
32 else:
33 stderr = None
34 if input:
35 stdin = subprocess.PIPE
36 else:
37 stdin = None
38 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin, 55 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin,
39 stdout=stdout, stderr=stderr) 56 stdout=stdout, stderr=stderr)
40 (output, error) = proc.communicate(input) 57 (output, error) = proc.communicate(input)
41 if exit_code: 58 if exit_code:
42 return proc.returncode 59 return proc.returncode
43 if not error_ok and proc.returncode != 0: 60 if not error_ok and proc.returncode != 0:
44 raise Exception('Command "%s" failed.\n' % (' '.join(cmd)) + 61 raise Exception('Command "%s" failed.\n' % (' '.join(cmd)) +
45 (error_message or error or output or '')) 62 (error_message or error or output or ''))
46 return output 63 return output
47 64
65
48 def MakeDir(path, parents=False): 66 def MakeDir(path, parents=False):
67 """Basic wrapper around os.mkdirs.
68
69 Keyword arguments:
70 path -- Path to create.
71 parents -- Follow mkdir -p logic.
72
73 """
49 try: 74 try:
50 os.makedirs(path) 75 os.makedirs(path)
51 except OSError, e: 76 except OSError, e:
52 if e.errno == errno.EEXIST and parents: 77 if e.errno == errno.EEXIST and parents:
53 pass 78 pass
54 else: 79 else:
55 raise 80 raise
56 81
57 def RepoSync(buildroot, rw_checkout, retries=_DEFAULT_RETRIES): 82
83 def RepoSync(buildroot, rw_checkout=False, retries=_DEFAULT_RETRIES):
84 """Uses repo to checkout the source code.
85
86 Keyword arguments:
87 rw_checkout -- Reconfigure repo after sync'ing to read-write.
88 retries -- Number of retries to try before failing on the sync.
89
90 """
58 while retries > 0: 91 while retries > 0:
59 try: 92 try:
60 RunCommand(['repo', 'sync'], cwd=buildroot) 93 RunCommand(['repo', 'sync'], cwd=buildroot)
61 if rw_checkout: 94 if rw_checkout:
62 # Always re-run in case of new git repos or repo sync 95 # Always re-run in case of new git repos or repo sync
63 # failed in a previous run because of a forced Stop Build. 96 # failed in a previous run because of a forced Stop Build.
64 RunCommand(['repo', 'forall', '-c', 'git', 'config', 97 RunCommand(['repo', 'forall', '-c', 'git', 'config',
65 'url.ssh://git@gitrw.chromium.org:9222.pushinsteadof', 98 'url.ssh://git@gitrw.chromium.org:9222.pushinsteadof',
66 'http://src.chromium.org/git'], cwd=buildroot) 99 'http://src.chromium.org/git'], cwd=buildroot)
67 retries = 0 100 retries = 0
68 except: 101 except:
69 retries -= 1 102 retries -= 1
70 if retries > 0: 103 if retries > 0:
71 print >> sys.stderr, 'CBUILDBOT -- Repo Sync Failed, retrying' 104 print >> sys.stderr, 'CBUILDBOT -- Repo Sync Failed, retrying'
72 else: 105 else:
73 print >> sys.stderr, 'CBUILDBOT -- Retries exhausted' 106 print >> sys.stderr, 'CBUILDBOT -- Retries exhausted'
74 raise 107 raise
75 108
76 # Main functions 109 # =========================== Command Helpers =================================
110
111 def _GetAllGitRepos(buildroot, debug=False):
112 """Returns a list of tuples containing [git_repo, src_path]."""
113 manifest_tuples = []
114 # Gets all the git repos from a full repo manifest.
115 repo_cmd = "repo manifest -o -".split()
116 output = RunCommand(repo_cmd, cwd=buildroot, redirect_stdout=True,
117 redirect_stderr=True, print_cmd=debug)
118
119 # Extract all lines containg a project.
120 extract_cmd = ["grep", "project name="]
121 output = RunCommand(extract_cmd, cwd=buildroot, input=output,
122 redirect_stdout=True, print_cmd=debug)
123 # Parse line using re to get tuple.
124 result_array = re.findall('.+name=\"([\w-]+)\".+path=\"(\S+)".+', output)
125
126 # Create the array.
127 for result in result_array:
128 if len(result) != 2:
129 print >> sys.stderr, 'Found in correct xml object %s', result
130 else:
131 # Remove pre-pended src directory from manifest.
132 manifest_tuples.append([result[0], result[1].replace('src/', '')])
133 return manifest_tuples
134
135
136 def _GetCrosWorkOnSrcPath(buildroot, board, package, debug=False):
137 """Returns ${CROS_WORKON_SRC_PATH} for given package."""
138 cwd = os.path.join(buildroot, 'src', 'scripts')
139 equery_cmd = ('equery-%s which %s' % (board, package)).split()
140 ebuild_path = RunCommand(equery_cmd, cwd=cwd, redirect_stdout=True,
141 redirect_stderr=True, enter_chroot=True,
142 error_ok=True, print_cmd=debug)
143 if ebuild_path:
144 ebuild_cmd = ('ebuild-%s %s info' % (board, ebuild_path)).split()
145 cros_workon_output = RunCommand(ebuild_cmd, cwd=cwd,
146 redirect_stdout=True, redirect_stderr=True,
147 enter_chroot=True, print_cmd=debug)
148
149 temp = re.findall('CROS_WORKON_SRCDIR="(\S+)"', cros_workon_output)
150 if temp:
151 return temp[0]
152 return None
153
154
155 def _CreateRepoDictionary(buildroot, board, debug=False):
156 """Returns the repo->list_of_ebuilds dictionary."""
157 repo_dictionary = {}
158 manifest_tuples = _GetAllGitRepos(buildroot)
159 print >> sys.stderr, 'Creating dictionary of git repos to portage packages ... '
160
161 cwd = os.path.join(buildroot, 'src', 'scripts')
162 get_all_workon_pkgs_cmd = './cros_workon list --all'.split()
163 packages = RunCommand(get_all_workon_pkgs_cmd, cwd=cwd,
164 redirect_stdout=True, redirect_stderr=True,
165 enter_chroot=True, print_cmd=debug)
166 for package in packages.split():
167 cros_workon_src_path = _GetCrosWorkOnSrcPath(buildroot, board, package)
168 if cros_workon_src_path:
169 for tuple in manifest_tuples:
170 # This path tends to have the user's home_dir prepended to it.
171 if cros_workon_src_path.endswith(tuple[1]):
172 print >> sys.stderr, ('For %s found matching package %s' %
173 (tuple[0], package))
174 if repo_dictionary.has_key(tuple[0]):
175 repo_dictionary[tuple[0]] += [package]
176 else:
177 repo_dictionary[tuple[0]] = [package]
178 return repo_dictionary
179
180
181 def _ParseRevisionString(revision_string, repo_dictionary):
182 """Parses the given revision_string into a revision dictionary.
183
184 Returns a list of tuples that contain [portage_package_name, commit_id] to
185 update.
186
187 Keyword arguments:
188 revision_string -- revision_string with format
189 'repo1.git@commit_1 repo2.git@commit2 ...'.
190 repo_dictionary -- dictionary with git repository names as keys (w/out git)
191 to portage package names.
192
193 """
194 # Using a dictionary removes duplicates.
195 revisions = {}
196 for revision in revision_string.split():
197 # Format 'package@commit-id'.
198 revision_tuple = revision.split('@')
199 if len(revision_tuple) != 2:
200 print >> sys.stderr, 'Incorrectly formatted revision %s' % revision
201 repo_name = revision_tuple[0].replace('.git', '')
202 # May be many corresponding packages to a given git repo e.g. kernel)
203 for package in repo_dictionary[repo_name]:
204 revisions[package] = revision_tuple[1]
205 return revisions.items()
206
207
208 def _UprevFromRevisionList(buildroot, revision_list):
209 """Uprevs based on revision list."""
210 package_str = ''
211 commit_str = ''
212 for package, revision in revision_list:
213 package_str += package + ' '
214 commit_str += revision + ' '
215 package_str = package_str.strip()
216 commit_str = commit_str.strip()
217
218 cwd = os.path.join(buildroot, 'src', 'scripts')
219 RunCommand(['./cros_mark_as_stable',
220 '--tracking_branch="cros/master"',
221 '--packages="%s"' % package_str,
222 '--commit_ids="%s"' % commit_str,
223 'commit'],
224 cwd=cwd, enter_chroot=True)
225
226
227 def _UprevAllPackages(buildroot):
228 """Uprevs all packages that have been updated since last uprev."""
229 cwd = os.path.join(buildroot, 'src', 'scripts')
230 RunCommand(['./cros_mark_all_as_stable',
231 '--tracking_branch="cros/master"'],
232 cwd=cwd, enter_chroot=True)
233
234 # =========================== Main Commands ===================================
77 235
78 def _FullCheckout(buildroot, rw_checkout=True, retries=_DEFAULT_RETRIES): 236 def _FullCheckout(buildroot, rw_checkout=True, retries=_DEFAULT_RETRIES):
237 """Performs a full checkout and clobbers any previous checkouts."""
79 RunCommand(['sudo', 'rm', '-rf', buildroot]) 238 RunCommand(['sudo', 'rm', '-rf', buildroot])
80 MakeDir(buildroot, parents=True) 239 MakeDir(buildroot, parents=True)
81 RunCommand(['repo', 'init', '-u', 'http://src.chromium.org/git/manifest'], 240 RunCommand(['repo', 'init', '-u', 'http://src.chromium.org/git/manifest'],
82 cwd=buildroot, input='\n\ny\n') 241 cwd=buildroot, input='\n\ny\n')
83 RepoSync(buildroot, rw_checkout, retries) 242 RepoSync(buildroot, rw_checkout, retries)
84 243
244
85 def _IncrementalCheckout(buildroot, rw_checkout=True, 245 def _IncrementalCheckout(buildroot, rw_checkout=True,
86 retries=_DEFAULT_RETRIES): 246 retries=_DEFAULT_RETRIES):
247 """Performs a checkout without clobbering previous checkout."""
87 RepoSync(buildroot, rw_checkout, retries) 248 RepoSync(buildroot, rw_checkout, retries)
88 249
250
89 def _MakeChroot(buildroot): 251 def _MakeChroot(buildroot):
252 """Wrapper around make_chroot."""
90 cwd = os.path.join(buildroot, 'src', 'scripts') 253 cwd = os.path.join(buildroot, 'src', 'scripts')
91 RunCommand(['./make_chroot', '--fast'], cwd=cwd) 254 RunCommand(['./make_chroot', '--fast'], cwd=cwd)
92 255
256
93 def _SetupBoard(buildroot, board='x86-generic'): 257 def _SetupBoard(buildroot, board='x86-generic'):
258 """Wrapper around setup_board."""
94 cwd = os.path.join(buildroot, 'src', 'scripts') 259 cwd = os.path.join(buildroot, 'src', 'scripts')
95 RunCommand(['./setup_board', '--fast', '--default', '--board=%s' % board], 260 RunCommand(['./setup_board', '--fast', '--default', '--board=%s' % board],
96 cwd=cwd) 261 cwd=cwd)
97 262
263
98 def _Build(buildroot): 264 def _Build(buildroot):
265 """Wrapper around build_packages."""
99 cwd = os.path.join(buildroot, 'src', 'scripts') 266 cwd = os.path.join(buildroot, 'src', 'scripts')
100 RunCommand(['./build_packages'], cwd=cwd) 267 RunCommand(['./build_packages'], cwd=cwd)
101 268
102 def _UprevAllPackages(buildroot): 269
103 cwd = os.path.join(buildroot, 'src', 'scripts') 270 def _UprevPackages(buildroot, revisionfile, board):
104 RunCommand(['./enter_chroot.sh', '--', './cros_mark_all_as_stable', 271 """Uprevs a package based on given revisionfile.
105 '--tracking_branch="cros/master"'], 272
106 cwd=cwd) 273 If revisionfile is set to None or does not resolve to an actual file, this
107 274 function will uprev all packages.
108 def _UprevPackages(buildroot, revisionfile): 275
109 revisions = None 276 Keyword arguments:
277 revisionfile -- string specifying a file that contains a list of revisions to
278 uprev.
279 """
280 # Purposefully set to None as it means Force Build was pressed.
281 revisions = 'None'
110 if (revisionfile): 282 if (revisionfile):
111 try: 283 try:
112 rev_file = open(revisionfile) 284 rev_file = open(revisionfile)
113 revisions = rev_file.read() 285 revisions = rev_file.read()
114 rev_file.close() 286 rev_file.close()
115 except: 287 except Exception, e:
116 print >> sys.stderr, 'Error reading %s' % revisionfile 288 print >> sys.stderr, 'Error reading %s, revving all' % revisionfile
117 revisions = None 289 print e
118 290 revisions = 'None'
119 # Note: Revisions == "None" indicates a Force Build. 291
120 if revisions and revisions != 'None': 292 revisions = revisions.strip()
121 print 'CBUILDBOT - Revision list found %s' % revisions 293
122 print 'Revision list not yet propagating to build, marking all instead' 294 # Revisions == "None" indicates a Force Build.
123 295 if revisions != 'None':
124 _UprevAllPackages(buildroot) 296 print >> sys.stderr, 'CBUILDBOT Revision list found %s' % revisions
297 revision_list = _ParseRevisionString(revisions,
298 _CreateRepoDictionary(buildroot, board))
299 _UprevFromRevisionList(buildroot, revision_list)
300 else:
301 print >> sys.stderr, 'CBUILDBOT Revving all'
302 _UprevAllPackages(buildroot)
303
125 304
126 def _UprevCleanup(buildroot): 305 def _UprevCleanup(buildroot):
306 """Clean up after a previous uprev attempt."""
127 cwd = os.path.join(buildroot, 'src', 'scripts') 307 cwd = os.path.join(buildroot, 'src', 'scripts')
128 RunCommand(['./cros_mark_as_stable', '--srcroot=..', 308 RunCommand(['./cros_mark_as_stable', '--srcroot=..',
129 '--tracking_branch="cros/master"', 'clean'], 309 '--tracking_branch="cros/master"', 'clean'],
130 cwd=cwd) 310 cwd=cwd)
131 311
312
132 def _UprevPush(buildroot): 313 def _UprevPush(buildroot):
314 """Pushes uprev changes to the main line."""
133 cwd = os.path.join(buildroot, 'src', 'scripts') 315 cwd = os.path.join(buildroot, 'src', 'scripts')
134 RunCommand(['./cros_mark_as_stable', '--srcroot=..', 316 RunCommand(['./cros_mark_as_stable', '--srcroot=..',
135 '--tracking_branch="cros/master"', 317 '--tracking_branch="cros/master"',
136 '--push_options', '--bypass-hooks -f', 'push'], 318 '--push_options', '--bypass-hooks -f', 'push'],
137 cwd=cwd) 319 cwd=cwd)
138 320
321
139 def _GetConfig(config_name): 322 def _GetConfig(config_name):
323 """Gets the configuration for the build"""
140 default = config['default'] 324 default = config['default']
141 buildconfig = {} 325 buildconfig = {}
142 if config.has_key(config_name): 326 if config.has_key(config_name):
143 buildconfig = config[config_name] 327 buildconfig = config[config_name]
144 for key in default.iterkeys(): 328 for key in default.iterkeys():
145 if not buildconfig.has_key(key): 329 if not buildconfig.has_key(key):
146 buildconfig[key] = default[key] 330 buildconfig[key] = default[key]
147 return buildconfig 331 return buildconfig
148 332
333
149 def main(): 334 def main():
150 # Parse options 335 # Parse options
151 usage = "usage: %prog [options] cbuildbot_config" 336 usage = "usage: %prog [options] cbuildbot_config"
152 parser = optparse.OptionParser(usage=usage) 337 parser = optparse.OptionParser(usage=usage)
153 parser.add_option('-r', '--buildroot', 338 parser.add_option('-r', '--buildroot',
154 help='root directory where build occurs', default=".") 339 help='root directory where build occurs', default=".")
155 parser.add_option('-n', '--buildnumber', 340 parser.add_option('-n', '--buildnumber',
156 help='build number', type='int', default=0) 341 help='build number', type='int', default=0)
157 parser.add_option('-f', '--revisionfile', 342 parser.add_option('-f', '--revisionfile',
158 help='file where new revisions are stored') 343 help='file where new revisions are stored')
(...skipping 17 matching lines...) Expand all
176 _FullCheckout(buildroot) 361 _FullCheckout(buildroot)
177 else: 362 else:
178 _IncrementalCheckout(buildroot) 363 _IncrementalCheckout(buildroot)
179 chroot_path = os.path.join(buildroot, 'chroot') 364 chroot_path = os.path.join(buildroot, 'chroot')
180 if not os.path.isdir(chroot_path): 365 if not os.path.isdir(chroot_path):
181 _MakeChroot(buildroot) 366 _MakeChroot(buildroot)
182 boardpath = os.path.join(chroot_path, 'build', buildconfig['board']) 367 boardpath = os.path.join(chroot_path, 'build', buildconfig['board'])
183 if not os.path.isdir(boardpath): 368 if not os.path.isdir(boardpath):
184 _SetupBoard(buildroot, board=buildconfig['board']) 369 _SetupBoard(buildroot, board=buildconfig['board'])
185 if buildconfig['uprev']: 370 if buildconfig['uprev']:
186 _UprevPackages(buildroot, revisionfile) 371 _UprevPackages(buildroot, revisionfile, board=buildconfig['board'])
187 _Build(buildroot) 372 _Build(buildroot)
188 if buildconfig['uprev']: 373 if buildconfig['uprev']:
189 _UprevPush(buildroot) 374 _UprevPush(buildroot)
190 _UprevCleanup(buildroot) 375 _UprevCleanup(buildroot)
191 except: 376 except:
192 # something went wrong, cleanup (being paranoid) for next build 377 # something went wrong, cleanup (being paranoid) for next build
193 if clobber: 378 if clobber:
194 RunCommand(['sudo', 'rm', '-rf', buildroot], print_cmd=False) 379 RunCommand(['sudo', 'rm', '-rf', buildroot], print_cmd=False)
195 raise 380 raise
196 381
382
197 if __name__ == '__main__': 383 if __name__ == '__main__':
198 main() 384 main()
OLDNEW
« no previous file with comments | « no previous file | bin/cbuildbot_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698