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

Side by Side Diff: recipe_modules/bot_update/resources/bot_update.py

Issue 2325513002: Reland "Delete lots of svn logic from bot_update" (Closed)
Patch Set: Comply with bot_update_coverage_test Created 4 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 | « no previous file | tests/bot_update_coverage_test.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/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # TODO(hinoka): Use logging. 6 # TODO(hinoka): Use logging.
7 7
8 import cStringIO 8 import cStringIO
9 import codecs 9 import codecs
10 import collections 10 import collections
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 path.join(ROOT_DIR, # .recipe_deps 79 path.join(ROOT_DIR, # .recipe_deps
80 path.pardir, # slave 80 path.pardir, # slave
81 path.pardir, # scripts 81 path.pardir, # scripts
82 path.pardir), # build_internal 82 path.pardir), # build_internal
83 ]) 83 ])
84 84
85 85
86 CHROMIUM_GIT_HOST = 'https://chromium.googlesource.com' 86 CHROMIUM_GIT_HOST = 'https://chromium.googlesource.com'
87 CHROMIUM_SRC_URL = CHROMIUM_GIT_HOST + '/chromium/src.git' 87 CHROMIUM_SRC_URL = CHROMIUM_GIT_HOST + '/chromium/src.git'
88 88
89 # Official builds use buildspecs, so this is a special case.
90 BUILDSPEC_TYPE = collections.namedtuple('buildspec',
91 ('container', 'version'))
92 BUILDSPEC_RE = (r'^/chrome-internal/trunk/tools/buildspec/'
93 '(build|branches|releases)/(.+)$')
94 GIT_BUILDSPEC_PATH = ('https://chrome-internal.googlesource.com/chrome/tools/'
95 'buildspec')
96 BRANCH_HEADS_REFSPEC = '+refs/branch-heads/*' 89 BRANCH_HEADS_REFSPEC = '+refs/branch-heads/*'
97 90
98 BUILDSPEC_COMMIT_RE = (
99 re.compile(r'Buildspec for.*version (\d+\.\d+\.\d+\.\d+)'),
100 re.compile(r'Create (\d+\.\d+\.\d+\.\d+) buildspec'),
101 re.compile(r'Auto-converted (\d+\.\d+\.\d+\.\d+) buildspec to git'),
102 )
103
104 # Regular expression that matches a single commit footer line. 91 # Regular expression that matches a single commit footer line.
105 COMMIT_FOOTER_ENTRY_RE = re.compile(r'([^:]+):\s+(.+)') 92 COMMIT_FOOTER_ENTRY_RE = re.compile(r'([^:]+):\s+(.+)')
106 93
107 # Footer metadata keys for regular and gsubtreed mirrored commit positions. 94 # Footer metadata keys for regular and gsubtreed mirrored commit positions.
108 COMMIT_POSITION_FOOTER_KEY = 'Cr-Commit-Position' 95 COMMIT_POSITION_FOOTER_KEY = 'Cr-Commit-Position'
109 COMMIT_ORIGINAL_POSITION_FOOTER_KEY = 'Cr-Original-Commit-Position' 96 COMMIT_ORIGINAL_POSITION_FOOTER_KEY = 'Cr-Original-Commit-Position'
110 # Regular expression to parse a commit position
111 COMMIT_POSITION_RE = re.compile(r'(.+)@\{#(\d+)\}')
112 97
113 # Regular expression to parse gclient's revinfo entries. 98 # Regular expression to parse gclient's revinfo entries.
114 REVINFO_RE = re.compile(r'^([^:]+):\s+([^@]+)@(.+)$') 99 REVINFO_RE = re.compile(r'^([^:]+):\s+([^@]+)@(.+)$')
115 100
116 # Used by 'ResolveSvnRevisionFromGitiles'
117 GIT_SVN_PROJECT_MAP = {
118 'webkit': {
119 'svn_url': 'svn://svn.chromium.org/blink',
120 'branch_map': [
121 (r'trunk', r'refs/heads/master'),
122 (r'branches/([^/]+)', r'refs/branch-heads/\1'),
123 ],
124 },
125 'v8': {
126 'svn_url': 'https://v8.googlecode.com/svn',
127 'branch_map': [
128 (r'trunk', r'refs/heads/candidates'),
129 (r'branches/bleeding_edge', r'refs/heads/master'),
130 (r'branches/([^/]+)', r'refs/branch-heads/\1'),
131 ],
132 },
133 'nacl': {
134 'svn_url': 'svn://svn.chromium.org/native_client',
135 'branch_map': [
136 (r'trunk/src/native_client', r'refs/heads/master'),
137 ],
138 },
139 }
140
141 # Key for the 'git-svn' ID metadata commit footer entry.
142 GIT_SVN_ID_FOOTER_KEY = 'git-svn-id'
143 # e.g., git-svn-id: https://v8.googlecode.com/svn/trunk@23117
144 # ce2b1a6d-e550-0410-aec6-3dcde31c8c00
145 GIT_SVN_ID_RE = re.compile(r'((?:\w+)://[^@]+)@(\d+)\s+(?:[a-zA-Z0-9\-]+)')
146
147
148 # This is the git mirror of the buildspecs repository. We could rely on the svn
149 # checkout, now that the git buildspecs are checked in alongside the svn
150 # buildspecs, but we're going to want to pull all the buildspecs from here
151 # eventually anyhow, and there's already some logic to pull from git (for the
152 # old git_buildspecs.git repo), so just stick with that.
153 GIT_BUILDSPEC_REPO = (
154 'https://chrome-internal.googlesource.com/chrome/tools/buildspec')
155 101
156 # Copied from scripts/recipes/chromium.py. 102 # Copied from scripts/recipes/chromium.py.
157 GOT_REVISION_MAPPINGS = { 103 GOT_REVISION_MAPPINGS = {
158 '/chrome/trunk/src': { 104 CHROMIUM_SRC_URL: {
159 'src/': 'got_revision', 105 'src/': 'got_revision',
160 'src/native_client/': 'got_nacl_revision', 106 'src/native_client/': 'got_nacl_revision',
161 'src/tools/swarm_client/': 'got_swarm_client_revision', 107 'src/tools/swarm_client/': 'got_swarm_client_revision',
162 'src/tools/swarming_client/': 'got_swarming_client_revision', 108 'src/tools/swarming_client/': 'got_swarming_client_revision',
163 'src/third_party/WebKit/': 'got_webkit_revision', 109 'src/third_party/WebKit/': 'got_webkit_revision',
164 'src/third_party/webrtc/': 'got_webrtc_revision', 110 'src/third_party/webrtc/': 'got_webrtc_revision',
165 'src/v8/': 'got_v8_revision', 111 'src/v8/': 'got_v8_revision',
166 } 112 }
167 } 113 }
168 114
(...skipping 12 matching lines...) Expand all
181 try: 127 try:
182 execfile(os.path.join( 128 execfile(os.path.join(
183 BUILD_INTERNAL_DIR, 'scripts', 'slave', 'bot_update_cfg.py'), 129 BUILD_INTERNAL_DIR, 'scripts', 'slave', 'bot_update_cfg.py'),
184 local_vars) 130 local_vars)
185 except Exception: 131 except Exception:
186 # Same as if BUILD_INTERNAL_DIR didn't exist in the first place. 132 # Same as if BUILD_INTERNAL_DIR didn't exist in the first place.
187 print 'Warning: unable to read internal configuration file.' 133 print 'Warning: unable to read internal configuration file.'
188 print 'If this is an internal bot, this step may be erroneously inactive.' 134 print 'If this is an internal bot, this step may be erroneously inactive.'
189 internal_data = local_vars 135 internal_data = local_vars
190 136
191 RECOGNIZED_PATHS = {
192 # If SVN path matches key, the entire URL is rewritten to the Git url.
193 '/chrome/trunk/src':
194 CHROMIUM_SRC_URL,
195 '/chrome/trunk/src/tools/cros.DEPS':
196 CHROMIUM_GIT_HOST + '/chromium/src/tools/cros.DEPS.git',
197 '/chrome-internal/trunk/src-internal':
198 'https://chrome-internal.googlesource.com/chrome/src-internal.git',
199 }
200 RECOGNIZED_PATHS.update(internal_data.get('RECOGNIZED_PATHS', {}))
201 137
202 138
203 # How many times to try before giving up. 139 # How many times to try before giving up.
204 ATTEMPTS = 5 140 ATTEMPTS = 5
205 141
206 GIT_CACHE_PATH = path.join(DEPOT_TOOLS_DIR, 'git_cache.py') 142 GIT_CACHE_PATH = path.join(DEPOT_TOOLS_DIR, 'git_cache.py')
207 143
208 # Find the patch tool. 144 # Find the patch tool.
209 if sys.platform.startswith('win'): 145 if sys.platform.startswith('win'):
210 if not BUILD_INTERNAL_DIR: 146 if not BUILD_INTERNAL_DIR:
(...skipping 18 matching lines...) Expand all
229 165
230 166
231 class PatchFailed(SubprocessFailed): 167 class PatchFailed(SubprocessFailed):
232 pass 168 pass
233 169
234 170
235 class GclientSyncFailed(SubprocessFailed): 171 class GclientSyncFailed(SubprocessFailed):
236 pass 172 pass
237 173
238 174
239 class SVNRevisionNotFound(Exception):
240 pass
241
242
243 class InvalidDiff(Exception): 175 class InvalidDiff(Exception):
244 pass 176 pass
245 177
246 178
247 class Inactive(Exception):
248 """Not really an exception, just used to exit early cleanly."""
249 pass
250
251
252 RETRY = object() 179 RETRY = object()
253 OK = object() 180 OK = object()
254 FAIL = object() 181 FAIL = object()
255 182
256 183
257 class PsPrinter(object): 184 class PsPrinter(object):
258 def __init__(self, interval=300): 185 def __init__(self, interval=300):
259 self.interval = interval 186 self.interval = interval
260 self.active = sys.platform.startswith('linux2') 187 self.active = sys.platform.startswith('linux2')
261 self.thread = None 188 self.thread = None
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 297
371 def get_gclient_spec(solutions, target_os, target_os_only, git_cache_dir): 298 def get_gclient_spec(solutions, target_os, target_os_only, git_cache_dir):
372 return GCLIENT_TEMPLATE % { 299 return GCLIENT_TEMPLATE % {
373 'solutions': pprint.pformat(solutions, indent=4), 300 'solutions': pprint.pformat(solutions, indent=4),
374 'cache_dir': '"%s"' % git_cache_dir, 301 'cache_dir': '"%s"' % git_cache_dir,
375 'target_os': ('\ntarget_os=%s' % target_os) if target_os else '', 302 'target_os': ('\ntarget_os=%s' % target_os) if target_os else '',
376 'target_os_only': '\ntarget_os_only=%s' % target_os_only 303 'target_os_only': '\ntarget_os_only=%s' % target_os_only
377 } 304 }
378 305
379 306
380 def maybe_ignore_revision(revision, buildspec):
381 """Handle builders that don't care what buildbot tells them to build.
382
383 This is especially the case with branch builders that build from buildspecs
384 and/or trigger off multiple repositories, where the --revision passed in has
385 nothing to do with the solution being built. Clearing the revision in this
386 case causes bot_update to use HEAD rather that trying to checkout an
387 inappropriate version of the solution.
388 """
389 if buildspec and buildspec.container == 'branches':
390 return []
391 return revision
392
393
394 def solutions_printer(solutions): 307 def solutions_printer(solutions):
395 """Prints gclient solution to stdout.""" 308 """Prints gclient solution to stdout."""
396 print 'Gclient Solutions' 309 print 'Gclient Solutions'
397 print '=================' 310 print '================='
398 for solution in solutions: 311 for solution in solutions:
399 name = solution.get('name') 312 name = solution.get('name')
400 url = solution.get('url') 313 url = solution.get('url')
401 print '%s (%s)' % (name, url) 314 print '%s (%s)' % (name, url)
402 if solution.get('deps_file'): 315 if solution.get('deps_file'):
403 print ' Dependencies file is %s' % solution['deps_file'] 316 print ' Dependencies file is %s' % solution['deps_file']
(...skipping 14 matching lines...) Expand all
418 print ' %s: Ignore' % deps_name 331 print ' %s: Ignore' % deps_name
419 for k, v in solution.iteritems(): 332 for k, v in solution.iteritems():
420 # Print out all the keys we don't know about. 333 # Print out all the keys we don't know about.
421 if k in ['name', 'url', 'deps_file', 'custom_vars', 'custom_deps', 334 if k in ['name', 'url', 'deps_file', 'custom_vars', 'custom_deps',
422 'managed']: 335 'managed']:
423 continue 336 continue
424 print ' %s is %s' % (k, v) 337 print ' %s is %s' % (k, v)
425 print 338 print
426 339
427 340
428 def solutions_to_git(input_solutions): 341 def modify_solutions(input_solutions):
429 """Modifies urls in solutions to point at Git repos. 342 """Modifies urls in solutions to point at Git repos.
430 343
431 returns: (git solution, svn root of first solution) tuple. 344 returns: new solution dictionary
432 """ 345 """
433 assert input_solutions 346 assert input_solutions
434 solutions = copy.deepcopy(input_solutions) 347 solutions = copy.deepcopy(input_solutions)
435 first_solution = True
436 buildspec = None
437 for solution in solutions: 348 for solution in solutions:
438 original_url = solution['url'] 349 original_url = solution['url']
439 parsed_url = urlparse.urlparse(original_url) 350 parsed_url = urlparse.urlparse(original_url)
440 parsed_path = parsed_url.path 351 parsed_path = parsed_url.path
441 352
442 # Rewrite SVN urls into Git urls.
443 buildspec_m = re.match(BUILDSPEC_RE, parsed_path)
444 if first_solution and buildspec_m:
445 solution['url'] = GIT_BUILDSPEC_PATH
446 buildspec = BUILDSPEC_TYPE(
447 container=buildspec_m.group(1),
448 version=buildspec_m.group(2),
449 )
450 solution['deps_file'] = path.join(buildspec.container, buildspec.version,
451 'DEPS')
452 elif parsed_path in RECOGNIZED_PATHS:
453 solution['url'] = RECOGNIZED_PATHS[parsed_path]
454 solution['deps_file'] = '.DEPS.git'
455 elif parsed_url.scheme == 'https' and 'googlesource' in parsed_url.netloc:
456 pass
457 else:
458 print 'Warning: %s' % ('path %r not recognized' % parsed_path,)
459
460 # Strip out deps containing $$V8_REV$$, etc.
461 if 'custom_deps' in solution:
462 new_custom_deps = {}
463 for deps_name, deps_value in solution['custom_deps'].iteritems():
464 if deps_value and '$$' in deps_value:
465 print 'Dropping %s:%s from custom deps' % (deps_name, deps_value)
466 else:
467 new_custom_deps[deps_name] = deps_value
468 solution['custom_deps'] = new_custom_deps
469
470 if first_solution:
471 root = parsed_path
472 first_solution = False
473
474 solution['managed'] = False 353 solution['managed'] = False
475 # We don't want gclient to be using a safesync URL. Instead it should 354 # We don't want gclient to be using a safesync URL. Instead it should
476 # using the lkgr/lkcr branch/tags. 355 # using the lkgr/lkcr branch/tags.
477 if 'safesync_url' in solution: 356 if 'safesync_url' in solution:
478 print 'Removing safesync url %s from %s' % (solution['safesync_url'], 357 print 'Removing safesync url %s from %s' % (solution['safesync_url'],
479 parsed_path) 358 parsed_path)
480 del solution['safesync_url'] 359 del solution['safesync_url']
481 return solutions, root, buildspec 360
361 return solutions
482 362
483 363
484 def remove(target): 364 def remove(target):
485 """Remove a target by moving it into build.dead.""" 365 """Remove a target by moving it into build.dead."""
486 dead_folder = path.join(BUILDER_DIR, 'build.dead') 366 dead_folder = path.join(BUILDER_DIR, 'build.dead')
487 if not path.exists(dead_folder): 367 if not path.exists(dead_folder):
488 os.makedirs(dead_folder) 368 os.makedirs(dead_folder)
489 os.rename(target, path.join(dead_folder, uuid.uuid4().hex)) 369 os.rename(target, path.join(dead_folder, uuid.uuid4().hex))
490 370
491 371
492 def ensure_no_checkout(dir_names, scm_dirname): 372 def ensure_no_checkout(dir_names):
493 """Ensure that there is no undesired checkout under build/. 373 """Ensure that there is no undesired checkout under build/."""
494 374 build_dir = os.getcwd()
495 If there is an incorrect checkout under build/, then 375 has_checkout = any(path.exists(path.join(build_dir, dir_name, '.git'))
496 move build/ to build.dead/
497 This function will check each directory in dir_names.
498
499 scm_dirname is expected to be either ['.svn', '.git']
500 """
501 assert scm_dirname in ['.svn', '.git', '*']
502 has_checkout = any(path.exists(path.join(os.getcwd(), dir_name, scm_dirname))
503 for dir_name in dir_names) 376 for dir_name in dir_names)
504 377 if has_checkout:
505 if has_checkout or scm_dirname == '*':
506 build_dir = os.getcwd()
507 prefix = ''
508 if scm_dirname != '*':
509 prefix = '%s detected in checkout, ' % scm_dirname
510
511 for filename in os.listdir(build_dir): 378 for filename in os.listdir(build_dir):
512 deletion_target = path.join(build_dir, filename) 379 deletion_target = path.join(build_dir, filename)
513 print '%sdeleting %s...' % (prefix, deletion_target), 380 print '.git detected in checkout, deleting %s...' % deletion_target,
514 remove(deletion_target) 381 remove(deletion_target)
515 print 'done' 382 print 'done'
516 383
517 384
518 def gclient_configure(solutions, target_os, target_os_only, git_cache_dir): 385 def gclient_configure(solutions, target_os, target_os_only, git_cache_dir):
519 """Should do the same thing as gclient --spec='...'.""" 386 """Should do the same thing as gclient --spec='...'."""
520 with codecs.open('.gclient', mode='w', encoding='utf-8') as f: 387 with codecs.open('.gclient', mode='w', encoding='utf-8') as f:
521 f.write(get_gclient_spec( 388 f.write(get_gclient_spec(
522 solutions, target_os, target_os_only, git_cache_dir)) 389 solutions, target_os, target_os_only, git_cache_dir))
523 390
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 footers[m.group(1)] = m.group(2).strip() 464 footers[m.group(1)] = m.group(2).strip()
598 return footers 465 return footers
599 466
600 467
601 def get_commit_message_footer(message, key): 468 def get_commit_message_footer(message, key):
602 """Returns: (str/None) The footer value for 'key', or None if none was found. 469 """Returns: (str/None) The footer value for 'key', or None if none was found.
603 """ 470 """
604 return get_commit_message_footer_map(message).get(key) 471 return get_commit_message_footer_map(message).get(key)
605 472
606 473
607 def get_svn_rev(git_hash, dir_name):
608 log = git('log', '-1', git_hash, cwd=dir_name)
609 git_svn_id = get_commit_message_footer(log, GIT_SVN_ID_FOOTER_KEY)
610 if not git_svn_id:
611 return None
612 m = GIT_SVN_ID_RE.match(git_svn_id)
613 if not m:
614 return None
615 return int(m.group(2))
616
617
618 def get_git_hash(revision, branch, sln_dir):
619 """We want to search for the SVN revision on the git-svn branch.
620
621 Note that git will search backwards from origin/master.
622 """
623 match = "^%s: [^ ]*@%s " % (GIT_SVN_ID_FOOTER_KEY, revision)
624 ref = branch if branch.startswith('refs/') else 'origin/%s' % branch
625 cmd = ['log', '-E', '--grep', match, '--format=%H', '--max-count=1', ref]
626 result = git(*cmd, cwd=sln_dir).strip()
627 if result:
628 return result
629 raise SVNRevisionNotFound('We can\'t resolve svn r%s into a git hash in %s' %
630 (revision, sln_dir))
631
632
633 def emit_log_lines(name, lines): 474 def emit_log_lines(name, lines):
634 for line in lines.splitlines(): 475 for line in lines.splitlines():
635 print '@@@STEP_LOG_LINE@%s@%s@@@' % (name, line) 476 print '@@@STEP_LOG_LINE@%s@%s@@@' % (name, line)
636 print '@@@STEP_LOG_END@%s@@@' % name 477 print '@@@STEP_LOG_END@%s@@@' % name
637 478
638 479
639 def emit_properties(properties): 480 def emit_properties(properties):
640 for property_name, property_value in sorted(properties.items()): 481 for property_name, property_value in sorted(properties.items()):
641 print '@@@SET_BUILD_PROPERTY@%s@"%s"@@@' % (property_name, property_value) 482 print '@@@SET_BUILD_PROPERTY@%s@"%s"@@@' % (property_name, property_value)
642 483
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 518
678 519
679 def force_revision(folder_name, revision): 520 def force_revision(folder_name, revision):
680 split_revision = revision.split(':', 1) 521 split_revision = revision.split(':', 1)
681 branch = 'master' 522 branch = 'master'
682 if len(split_revision) == 2: 523 if len(split_revision) == 2:
683 # Support for "branch:revision" syntax. 524 # Support for "branch:revision" syntax.
684 branch, revision = split_revision 525 branch, revision = split_revision
685 526
686 if revision and revision.upper() != 'HEAD': 527 if revision and revision.upper() != 'HEAD':
687 if revision and revision.isdigit() and len(revision) < 40: 528 git('checkout', '--force', revision, cwd=folder_name)
688 # rev_num is really a svn revision number, convert it into a git hash.
689 git_ref = get_git_hash(int(revision), branch, folder_name)
690 else:
691 # rev_num is actually a git hash or ref, we can just use it.
692 git_ref = revision
693 git('checkout', '--force', git_ref, cwd=folder_name)
694 else: 529 else:
695 ref = branch if branch.startswith('refs/') else 'origin/%s' % branch 530 ref = branch if branch.startswith('refs/') else 'origin/%s' % branch
696 git('checkout', '--force', ref, cwd=folder_name) 531 git('checkout', '--force', ref, cwd=folder_name)
697 532
533
698 def git_checkout(solutions, revisions, shallow, refs, git_cache_dir): 534 def git_checkout(solutions, revisions, shallow, refs, git_cache_dir):
699 build_dir = os.getcwd() 535 build_dir = os.getcwd()
700 # Before we do anything, break all git_cache locks. 536 # Before we do anything, break all git_cache locks.
701 if path.isdir(git_cache_dir): 537 if path.isdir(git_cache_dir):
702 git('cache', 'unlock', '-vv', '--force', '--all', 538 git('cache', 'unlock', '-vv', '--force', '--all',
703 '--cache-dir', git_cache_dir) 539 '--cache-dir', git_cache_dir)
704 for item in os.listdir(git_cache_dir): 540 for item in os.listdir(git_cache_dir):
705 filename = os.path.join(git_cache_dir, item) 541 filename = os.path.join(git_cache_dir, item)
706 if item.endswith('.lock'): 542 if item.endswith('.lock'):
707 raise Exception('%s exists after cache unlock' % filename) 543 raise Exception('%s exists after cache unlock' % filename)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 # Exited abnormally, theres probably something wrong. 584 # Exited abnormally, theres probably something wrong.
749 # Lets wipe the checkout and try again. 585 # Lets wipe the checkout and try again.
750 tries_left -= 1 586 tries_left -= 1
751 if tries_left > 0: 587 if tries_left > 0:
752 print 'Something failed: %s.' % str(e) 588 print 'Something failed: %s.' % str(e)
753 print 'waiting 5 seconds and trying again...' 589 print 'waiting 5 seconds and trying again...'
754 time.sleep(5) 590 time.sleep(5)
755 else: 591 else:
756 raise 592 raise
757 remove(sln_dir) 593 remove(sln_dir)
758 except SVNRevisionNotFound:
759 tries_left -= 1
760 if tries_left > 0:
761 # If we don't have the correct revision, wait and try again.
762 print 'We can\'t find revision %s.' % revision
763 print 'The svn to git replicator is probably falling behind.'
764 print 'waiting 5 seconds and trying again...'
765 time.sleep(5)
766 else:
767 raise
768 594
769 git('clean', '-dff', cwd=sln_dir) 595 git('clean', '-dff', cwd=sln_dir)
770 596
771 if first_solution: 597 if first_solution:
772 git_ref = git('log', '--format=%H', '--max-count=1', 598 git_ref = git('log', '--format=%H', '--max-count=1',
773 cwd=sln_dir).strip() 599 cwd=sln_dir).strip()
774 first_solution = False 600 first_solution = False
775 return git_ref 601 return git_ref
776 602
777 603
778 def _download(url): 604 def _download(url):
779 """Fetch url and return content, with retries for flake.""" 605 """Fetch url and return content, with retries for flake."""
780 for attempt in xrange(ATTEMPTS): 606 for attempt in xrange(ATTEMPTS):
781 try: 607 try:
782 return urllib2.urlopen(url).read() 608 return urllib2.urlopen(url).read()
783 except Exception: 609 except Exception:
784 if attempt == ATTEMPTS - 1: 610 if attempt == ATTEMPTS - 1:
785 raise 611 raise
786 612
787 613
788 def parse_diff(diff):
789 """Takes a unified diff and returns a list of diffed files and their diffs.
790
791 The return format is a list of pairs of:
792 (<filename>, <diff contents>)
793 <diff contents> is inclusive of the diff line.
794 """
795 result = []
796 current_diff = ''
797 current_header = None
798 for line in diff.splitlines():
799 # "diff" is for git style patches, and "Index: " is for SVN style patches.
800 if line.startswith('diff') or line.startswith('Index: '):
801 if current_header:
802 # If we are in a diff portion, then save the diff.
803 result.append((current_header, '%s\n' % current_diff))
804 git_header_match = re.match(r'diff (?:--git )?(\S+) (\S+)', line)
805 svn_header_match = re.match(r'Index: (.*)', line)
806
807 if git_header_match:
808 # First, see if its a git style header.
809 from_file = git_header_match.group(1)
810 to_file = git_header_match.group(2)
811 if from_file != to_file and from_file.startswith('a/'):
812 # Sometimes git prepends 'a/' and 'b/' in front of file paths.
813 from_file = from_file[2:]
814 current_header = from_file
815
816 elif svn_header_match:
817 # Otherwise, check if its an SVN style header.
818 current_header = svn_header_match.group(1)
819
820 else:
821 # Otherwise... I'm not really sure what to do with this.
822 raise InvalidDiff('Can\'t process header: %s\nFull diff:\n%s' %
823 (line, diff))
824
825 current_diff = ''
826 current_diff += '%s\n' % line
827 if current_header:
828 # We hit EOF, gotta save the last diff.
829 result.append((current_header, current_diff))
830 return result
831
832
833 def apply_rietveld_issue(issue, patchset, root, server, _rev_map, _revision, 614 def apply_rietveld_issue(issue, patchset, root, server, _rev_map, _revision,
834 email_file, key_file, whitelist=None, blacklist=None): 615 email_file, key_file, whitelist=None, blacklist=None):
835 apply_issue_bin = ('apply_issue.bat' if sys.platform.startswith('win') 616 apply_issue_bin = ('apply_issue.bat' if sys.platform.startswith('win')
836 else 'apply_issue') 617 else 'apply_issue')
837 cmd = [apply_issue_bin, 618 cmd = [apply_issue_bin,
838 # The patch will be applied on top of this directory. 619 # The patch will be applied on top of this directory.
839 '--root_dir', root, 620 '--root_dir', root,
840 # Tell apply_issue how to fetch the patch. 621 # Tell apply_issue how to fetch the patch.
841 '--issue', issue, 622 '--issue', issue,
842 '--server', server, 623 '--server', server,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
920 os.remove(flag_file) 701 os.remove(flag_file)
921 702
922 703
923 def emit_flag(flag_file): 704 def emit_flag(flag_file):
924 """Deposit a bot update flag on the system to tell gclient not to run.""" 705 """Deposit a bot update flag on the system to tell gclient not to run."""
925 print 'Emitting flag file at %s' % flag_file 706 print 'Emitting flag file at %s' % flag_file
926 with open(flag_file, 'wb') as f: 707 with open(flag_file, 'wb') as f:
927 f.write('Success!') 708 f.write('Success!')
928 709
929 710
930 def get_commit_position_for_git_svn(url, revision):
931 """Generates a commit position string for a 'git-svn' URL/revision.
932
933 If the 'git-svn' URL maps to a known project, we will construct a commit
934 position branch value by applying substitution on the SVN URL.
935 """
936 # Identify the base URL so we can strip off trunk/branch name
937 project_config = branch = None
938 for _, project_config in GIT_SVN_PROJECT_MAP.iteritems():
939 if url.startswith(project_config['svn_url']):
940 branch = url[len(project_config['svn_url']):]
941 break
942
943 if branch:
944 # Strip any leading slashes
945 branch = branch.lstrip('/')
946
947 # Try and map the branch
948 for pattern, repl in project_config.get('branch_map', ()):
949 nbranch, subn = re.subn(pattern, repl, branch, count=1)
950 if subn:
951 print 'INFO: Mapped SVN branch to Git branch [%s] => [%s]' % (
952 branch, nbranch)
953 branch = nbranch
954 break
955 else:
956 # Use generic 'svn' branch
957 print 'INFO: Could not resolve project for SVN URL %r' % (url,)
958 branch = 'svn'
959 return '%s@{#%s}' % (branch, revision)
960
961
962 def get_commit_position(git_path, revision='HEAD'): 711 def get_commit_position(git_path, revision='HEAD'):
963 """Dumps the 'git' log for a specific revision and parses out the commit 712 """Dumps the 'git' log for a specific revision and parses out the commit
964 position. 713 position.
965 714
966 If a commit position metadata key is found, its value will be returned. 715 If a commit position metadata key is found, its value will be returned.
967
968 Otherwise, we will search for a 'git-svn' metadata entry. If one is found,
969 we will compose a commit position from it, using its SVN revision value as
970 the revision.
971
972 If the 'git-svn' URL maps to a known project, we will construct a commit
973 position branch value by truncating the URL, mapping 'trunk' to
974 "refs/heads/master". Otherwise, we will return the generic branch, 'svn'.
975 """ 716 """
717 # TODO(iannucci): Use git-footers for this.
976 git_log = git('log', '--format=%B', '-n1', revision, cwd=git_path) 718 git_log = git('log', '--format=%B', '-n1', revision, cwd=git_path)
977 footer_map = get_commit_message_footer_map(git_log) 719 footer_map = get_commit_message_footer_map(git_log)
978 720
979 # Search for commit position metadata 721 # Search for commit position metadata
980 value = (footer_map.get(COMMIT_POSITION_FOOTER_KEY) or 722 value = (footer_map.get(COMMIT_POSITION_FOOTER_KEY) or
981 footer_map.get(COMMIT_ORIGINAL_POSITION_FOOTER_KEY)) 723 footer_map.get(COMMIT_ORIGINAL_POSITION_FOOTER_KEY))
982 if value: 724 if value:
983 return value 725 return value
984
985 # Compose a commit position from 'git-svn' metadata
986 value = footer_map.get(GIT_SVN_ID_FOOTER_KEY)
987 if value:
988 m = GIT_SVN_ID_RE.match(value)
989 if not m:
990 raise ValueError("Invalid 'git-svn' value: [%s]" % (value,))
991 return get_commit_position_for_git_svn(m.group(1), m.group(2))
992 return None 726 return None
993 727
994 728
995 def parse_got_revision(gclient_output, got_revision_mapping, use_svn_revs): 729 def parse_got_revision(gclient_output, got_revision_mapping):
996 """Translate git gclient revision mapping to build properties. 730 """Translate git gclient revision mapping to build properties."""
997
998 If use_svn_revs is True, then translate git hashes in the revision mapping
999 to svn revision numbers.
1000 """
1001 properties = {} 731 properties = {}
1002 solutions_output = { 732 solutions_output = {
1003 # Make sure path always ends with a single slash. 733 # Make sure path always ends with a single slash.
1004 '%s/' % path.rstrip('/') : solution_output for path, solution_output 734 '%s/' % path.rstrip('/') : solution_output for path, solution_output
1005 in gclient_output['solutions'].iteritems() 735 in gclient_output['solutions'].iteritems()
1006 } 736 }
1007 for dir_name, property_name in got_revision_mapping.iteritems(): 737 for dir_name, property_name in got_revision_mapping.iteritems():
1008 # Make sure dir_name always ends with a single slash. 738 # Make sure dir_name always ends with a single slash.
1009 dir_name = '%s/' % dir_name.rstrip('/') 739 dir_name = '%s/' % dir_name.rstrip('/')
1010 if dir_name not in solutions_output: 740 if dir_name not in solutions_output:
1011 continue 741 continue
1012 solution_output = solutions_output[dir_name] 742 solution_output = solutions_output[dir_name]
1013 if solution_output.get('scm') is None: 743 if solution_output.get('scm') is None:
1014 # This is an ignored DEPS, so the output got_revision should be 'None'. 744 # This is an ignored DEPS, so the output got_revision should be 'None'.
1015 git_revision = revision = commit_position = None 745 revision = commit_position = None
1016 else: 746 else:
1017 # Since we are using .DEPS.git, everything had better be git. 747 # Since we are using .DEPS.git, everything had better be git.
1018 assert solution_output.get('scm') == 'git' 748 assert solution_output.get('scm') == 'git'
1019 git_revision = git('rev-parse', 'HEAD', cwd=dir_name).strip() 749 revision = git('rev-parse', 'HEAD', cwd=dir_name).strip()
1020 if use_svn_revs:
1021 revision = get_svn_rev(git_revision, dir_name)
1022 if not revision:
1023 revision = git_revision
1024 else:
1025 revision = git_revision
1026 commit_position = get_commit_position(dir_name) 750 commit_position = get_commit_position(dir_name)
1027 751
1028 properties[property_name] = revision 752 properties[property_name] = revision
1029 if revision != git_revision:
1030 properties['%s_git' % property_name] = git_revision
1031 if commit_position: 753 if commit_position:
1032 properties['%s_cp' % property_name] = commit_position 754 properties['%s_cp' % property_name] = commit_position
1033 755
1034 return properties 756 return properties
1035 757
1036 758
1037 def emit_json(out_file, did_run, gclient_output=None, **kwargs): 759 def emit_json(out_file, did_run, gclient_output=None, **kwargs):
1038 """Write run information into a JSON file.""" 760 """Write run information into a JSON file."""
1039 output = {} 761 output = {}
1040 output.update(gclient_output if gclient_output else {}) 762 output.update(gclient_output if gclient_output else {})
1041 output.update({'did_run': did_run}) 763 output.update({'did_run': did_run})
1042 output.update(kwargs) 764 output.update(kwargs)
1043 with open(out_file, 'wb') as f: 765 with open(out_file, 'wb') as f:
1044 f.write(json.dumps(output, sort_keys=True)) 766 f.write(json.dumps(output, sort_keys=True))
1045 767
1046 768
1047 def ensure_deps_revisions(deps_url_mapping, solutions, revisions): 769 def ensure_deps_revisions(deps_url_mapping, solutions, revisions):
1048 """Ensure correct DEPS revisions, ignores solutions.""" 770 """Ensure correct DEPS revisions, ignores solutions."""
1049 for deps_name, deps_data in sorted(deps_url_mapping.items()): 771 for deps_name, deps_data in sorted(deps_url_mapping.items()):
1050 if deps_name.strip('/') in solutions: 772 if deps_name.strip('/') in solutions:
1051 # This has already been forced to the correct solution by git_checkout(). 773 # This has already been forced to the correct solution by git_checkout().
1052 continue 774 continue
1053 revision = get_target_revision(deps_name, deps_data.get('url', None), 775 revision = get_target_revision(deps_name, deps_data.get('url', None),
1054 revisions) 776 revisions)
1055 if not revision: 777 if not revision:
1056 continue 778 continue
1057 # TODO(hinoka): Catch SVNRevisionNotFound error maybe?
1058 git('fetch', 'origin', cwd=deps_name) 779 git('fetch', 'origin', cwd=deps_name)
1059 force_revision(deps_name, revision) 780 force_revision(deps_name, revision)
1060 781
1061 782
1062 def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only, 783 def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only,
1063 patch_root, issue, patchset, rietveld_server, 784 patch_root, issue, patchset, rietveld_server,
1064 gerrit_repo, gerrit_ref, gerrit_rebase_patch_ref, 785 gerrit_repo, gerrit_ref, gerrit_rebase_patch_ref,
1065 revision_mapping, apply_issue_email_file, 786 revision_mapping, apply_issue_email_file,
1066 apply_issue_key_file, buildspec, gyp_env, shallow, runhooks, 787 apply_issue_key_file, gyp_env, shallow, runhooks,
1067 refs, git_cache_dir, gerrit_reset): 788 refs, git_cache_dir, gerrit_reset):
1068 # Get a checkout of each solution, without DEPS or hooks. 789 # Get a checkout of each solution, without DEPS or hooks.
1069 # Calling git directly because there is no way to run Gclient without 790 # Calling git directly because there is no way to run Gclient without
1070 # invoking DEPS. 791 # invoking DEPS.
1071 print 'Fetching Git checkout' 792 print 'Fetching Git checkout'
1072 793
1073 git_ref = git_checkout(solutions, revisions, shallow, refs, git_cache_dir) 794 git_ref = git_checkout(solutions, revisions, shallow, refs, git_cache_dir)
1074 795
1075 print '===Processing patch solutions===' 796 print '===Processing patch solutions==='
1076 already_patched = [] 797 already_patched = []
(...skipping 16 matching lines...) Expand all
1093 apply_gerrit_ref(gerrit_repo, gerrit_ref, patch_root, gerrit_reset, 814 apply_gerrit_ref(gerrit_repo, gerrit_ref, patch_root, gerrit_reset,
1094 gerrit_rebase_patch_ref) 815 gerrit_rebase_patch_ref)
1095 applied_gerrit_patch = True 816 applied_gerrit_patch = True
1096 817
1097 # Ensure our build/ directory is set up with the correct .gclient file. 818 # Ensure our build/ directory is set up with the correct .gclient file.
1098 gclient_configure(solutions, target_os, target_os_only, git_cache_dir) 819 gclient_configure(solutions, target_os, target_os_only, git_cache_dir)
1099 820
1100 # Let gclient do the DEPS syncing. 821 # Let gclient do the DEPS syncing.
1101 # The branch-head refspec is a special case because its possible Chrome 822 # The branch-head refspec is a special case because its possible Chrome
1102 # src, which contains the branch-head refspecs, is DEPSed in. 823 # src, which contains the branch-head refspecs, is DEPSed in.
1103 gclient_output = gclient_sync(buildspec or BRANCH_HEADS_REFSPEC in refs, 824 gclient_output = gclient_sync(BRANCH_HEADS_REFSPEC in refs, shallow)
1104 shallow)
1105 825
1106 # Now that gclient_sync has finished, we should revert any .DEPS.git so that 826 # Now that gclient_sync has finished, we should revert any .DEPS.git so that
1107 # presubmit doesn't complain about it being modified. 827 # presubmit doesn't complain about it being modified.
1108 if (not buildspec and 828 if git('ls-files', '.DEPS.git', cwd=first_sln).strip():
1109 git('ls-files', '.DEPS.git', cwd=first_sln).strip()):
1110 git('checkout', 'HEAD', '--', '.DEPS.git', cwd=first_sln) 829 git('checkout', 'HEAD', '--', '.DEPS.git', cwd=first_sln)
1111 830
1112 if buildspec and runhooks:
1113 # Run gclient runhooks if we're on an official builder.
1114 # TODO(hinoka): Remove this when the official builders run their own
1115 # runhooks step.
1116 gclient_runhooks(gyp_env)
1117
1118 # Finally, ensure that all DEPS are pinned to the correct revision. 831 # Finally, ensure that all DEPS are pinned to the correct revision.
1119 dir_names = [sln['name'] for sln in solutions] 832 dir_names = [sln['name'] for sln in solutions]
1120 ensure_deps_revisions(gclient_output.get('solutions', {}), 833 ensure_deps_revisions(gclient_output.get('solutions', {}),
1121 dir_names, revisions) 834 dir_names, revisions)
1122 # Apply the rest of the patch here (sans DEPS) 835 # Apply the rest of the patch here (sans DEPS)
1123 if issue: 836 if issue:
1124 apply_rietveld_issue(issue, patchset, patch_root, rietveld_server, 837 apply_rietveld_issue(issue, patchset, patch_root, rietveld_server,
1125 revision_mapping, git_ref, apply_issue_email_file, 838 revision_mapping, git_ref, apply_issue_email_file,
1126 apply_issue_key_file, blacklist=already_patched) 839 apply_issue_key_file, blacklist=already_patched)
1127 elif gerrit_ref and not applied_gerrit_patch: 840 elif gerrit_ref and not applied_gerrit_patch:
(...skipping 25 matching lines...) Expand all
1153 expanded_revisions.extend(revision.split(',')) 866 expanded_revisions.extend(revision.split(','))
1154 for revision in expanded_revisions: 867 for revision in expanded_revisions:
1155 split_revision = revision.split('@') 868 split_revision = revision.split('@')
1156 if len(split_revision) == 1: 869 if len(split_revision) == 1:
1157 # This is just a plain revision, set it as the revision for root. 870 # This is just a plain revision, set it as the revision for root.
1158 results[root] = split_revision[0] 871 results[root] = split_revision[0]
1159 elif len(split_revision) == 2: 872 elif len(split_revision) == 2:
1160 # This is an alt_root@revision argument. 873 # This is an alt_root@revision argument.
1161 current_root, current_rev = split_revision 874 current_root, current_rev = split_revision
1162 875
1163 # We want to normalize svn/git urls into .git urls.
1164 parsed_root = urlparse.urlparse(current_root) 876 parsed_root = urlparse.urlparse(current_root)
1165 if parsed_root.scheme == 'svn': 877 if parsed_root.scheme in ['http', 'https']:
1166 if parsed_root.path in RECOGNIZED_PATHS: 878 # We want to normalize git urls into .git urls.
1167 normalized_root = RECOGNIZED_PATHS[parsed_root.path]
1168 else:
1169 print 'WARNING: SVN path %s not recognized, ignoring' % current_root
1170 continue
1171 elif parsed_root.scheme in ['http', 'https']:
1172 normalized_root = 'https://%s/%s' % (parsed_root.netloc, 879 normalized_root = 'https://%s/%s' % (parsed_root.netloc,
1173 parsed_root.path) 880 parsed_root.path)
1174 if not normalized_root.endswith('.git'): 881 if not normalized_root.endswith('.git'):
1175 normalized_root = '%s.git' % normalized_root 882 normalized_root = '%s.git' % normalized_root
1176 elif parsed_root.scheme: 883 elif parsed_root.scheme:
1177 print 'WARNING: Unrecognized scheme %s, ignoring' % parsed_root.scheme 884 print 'WARNING: Unrecognized scheme %s, ignoring' % parsed_root.scheme
1178 continue 885 continue
1179 else: 886 else:
1180 # This is probably a local path. 887 # This is probably a local path.
1181 normalized_root = current_root.strip('/') 888 normalized_root = current_root.strip('/')
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1214 parse.add_option('--specs', help='Gcilent spec.') 921 parse.add_option('--specs', help='Gcilent spec.')
1215 parse.add_option('-f', '--force', action='store_true', 922 parse.add_option('-f', '--force', action='store_true',
1216 help='Bypass check to see if we want to be run. ' 923 help='Bypass check to see if we want to be run. '
1217 'Should ONLY be used locally or by smart recipes.') 924 'Should ONLY be used locally or by smart recipes.')
1218 parse.add_option('--revision_mapping', 925 parse.add_option('--revision_mapping',
1219 help='{"path/to/repo/": "property_name"}') 926 help='{"path/to/repo/": "property_name"}')
1220 parse.add_option('--revision_mapping_file', 927 parse.add_option('--revision_mapping_file',
1221 help=('Same as revision_mapping, except its a path to a json' 928 help=('Same as revision_mapping, except its a path to a json'
1222 ' file containing that format.')) 929 ' file containing that format.'))
1223 parse.add_option('--revision', action='append', default=[], 930 parse.add_option('--revision', action='append', default=[],
1224 help='Revision to check out. Can be an SVN revision number, ' 931 help='Revision to check out. Can be any form of git ref. '
1225 'git hash, or any form of git ref. Can prepend ' 932 'Can prepend root@<rev> to specify which repository, '
1226 'root@<rev> to specify which repository, where root ' 933 'where root is either a filesystem path or git https '
1227 'is either a filesystem path, git https url, or ' 934 'url. To specify Tip of Tree, set rev to HEAD. ')
1228 'svn url. To specify Tip of Tree, set rev to HEAD.'
1229 'To specify a git branch and an SVN rev, <rev> can be '
1230 'set to <branch>:<revision>.')
1231 parse.add_option('--output_manifest', action='store_true', 935 parse.add_option('--output_manifest', action='store_true',
1232 help=('Add manifest json to the json output.')) 936 help=('Add manifest json to the json output.'))
1233 parse.add_option('--slave_name', default=socket.getfqdn().split('.')[0], 937 parse.add_option('--slave_name', default=socket.getfqdn().split('.')[0],
1234 help='Hostname of the current machine, ' 938 help='Hostname of the current machine, '
1235 'used for determining whether or not to activate.') 939 'used for determining whether or not to activate.')
1236 parse.add_option('--build_dir', default=os.getcwd()) 940 parse.add_option('--build_dir', default=os.getcwd())
1237 parse.add_option('--flag_file', default=path.join(os.getcwd(), 941 parse.add_option('--flag_file', default=path.join(os.getcwd(),
1238 'update.flag')) 942 'update.flag'))
1239 parse.add_option('--shallow', action='store_true', 943 parse.add_option('--shallow', action='store_true',
1240 help='Use shallow clones for cache repositories.') 944 help='Use shallow clones for cache repositories.')
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1292 options.git_cache_dir = options.git_cache_dir.replace('\\', '\\\\') 996 options.git_cache_dir = options.git_cache_dir.replace('\\', '\\\\')
1293 997
1294 return options, args 998 return options, args
1295 999
1296 1000
1297 def prepare(options, git_slns, active): 1001 def prepare(options, git_slns, active):
1298 """Prepares the target folder before we checkout.""" 1002 """Prepares the target folder before we checkout."""
1299 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln] 1003 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln]
1300 # If we're active now, but the flag file doesn't exist (we weren't active 1004 # If we're active now, but the flag file doesn't exist (we weren't active
1301 # last run) or vice versa, blow away all checkouts. 1005 # last run) or vice versa, blow away all checkouts.
1302 if bool(active) != bool(check_flag(options.flag_file)): 1006 if options.clobber or (bool(active) != bool(check_flag(options.flag_file))):
1303 ensure_no_checkout(dir_names, '*') 1007 ensure_no_checkout(dir_names)
1304 if options.output_json: 1008 if options.output_json:
1305 # Make sure we tell recipes that we didn't run if the script exits here. 1009 # Make sure we tell recipes that we didn't run if the script exits here.
1306 emit_json(options.output_json, did_run=active) 1010 emit_json(options.output_json, did_run=active)
1307 if active: 1011 emit_flag(options.flag_file)
1308 if options.clobber:
1309 ensure_no_checkout(dir_names, '*')
1310 else:
1311 ensure_no_checkout(dir_names, '.svn')
1312 emit_flag(options.flag_file)
1313 else:
1314 delete_flag(options.flag_file)
1315 raise Inactive # This is caught in main() and we exit cleanly.
1316 1012
1317 # Do a shallow checkout if the disk is less than 100GB. 1013 # Do a shallow checkout if the disk is less than 100GB.
1318 total_disk_space, free_disk_space = get_total_disk_space() 1014 total_disk_space, free_disk_space = get_total_disk_space()
1319 total_disk_space_gb = int(total_disk_space / (1024 * 1024 * 1024)) 1015 total_disk_space_gb = int(total_disk_space / (1024 * 1024 * 1024))
1320 used_disk_space_gb = int((total_disk_space - free_disk_space) 1016 used_disk_space_gb = int((total_disk_space - free_disk_space)
1321 / (1024 * 1024 * 1024)) 1017 / (1024 * 1024 * 1024))
1322 percent_used = int(used_disk_space_gb * 100 / total_disk_space_gb) 1018 percent_used = int(used_disk_space_gb * 100 / total_disk_space_gb)
1323 step_text = '[%dGB/%dGB used (%d%%)]' % (used_disk_space_gb, 1019 step_text = '[%dGB/%dGB used (%d%%)]' % (used_disk_space_gb,
1324 total_disk_space_gb, 1020 total_disk_space_gb,
1325 percent_used) 1021 percent_used)
1326 if not options.output_json: 1022 if not options.output_json:
1327 print '@@@STEP_TEXT@%s@@@' % step_text 1023 print '@@@STEP_TEXT@%s@@@' % step_text
1328 if not options.shallow: 1024 if not options.shallow:
1329 options.shallow = (total_disk_space < SHALLOW_CLONE_THRESHOLD 1025 options.shallow = (total_disk_space < SHALLOW_CLONE_THRESHOLD
1330 and not options.no_shallow) 1026 and not options.no_shallow)
1331 1027
1332 # The first solution is where the primary DEPS file resides. 1028 # The first solution is where the primary DEPS file resides.
1333 first_sln = dir_names[0] 1029 first_sln = dir_names[0]
1334 1030
1335 # Split all the revision specifications into a nice dict. 1031 # Split all the revision specifications into a nice dict.
1336 print 'Revisions: %s' % options.revision 1032 print 'Revisions: %s' % options.revision
1337 revisions = parse_revisions(options.revision, first_sln) 1033 revisions = parse_revisions(options.revision, first_sln)
1338 print 'Fetching Git checkout at %s@%s' % (first_sln, revisions[first_sln]) 1034 print 'Fetching Git checkout at %s@%s' % (first_sln, revisions[first_sln])
1339 return revisions, step_text 1035 return revisions, step_text
1340 1036
1341 1037
1342 def checkout(options, git_slns, specs, buildspec, 1038 def checkout(options, git_slns, specs, revisions, step_text):
1343 svn_root, revisions, step_text):
1344 first_sln = git_slns[0]['name'] 1039 first_sln = git_slns[0]['name']
1345 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln] 1040 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln]
1346 try: 1041 try:
1347 # Outer try is for catching patch failures and exiting gracefully. 1042 # Outer try is for catching patch failures and exiting gracefully.
1348 # Inner try is for catching gclient failures and retrying gracefully. 1043 # Inner try is for catching gclient failures and retrying gracefully.
1349 try: 1044 try:
1350 checkout_parameters = dict( 1045 checkout_parameters = dict(
1351 # First, pass in the base of what we want to check out. 1046 # First, pass in the base of what we want to check out.
1352 solutions=git_slns, 1047 solutions=git_slns,
1353 revisions=revisions, 1048 revisions=revisions,
1354 first_sln=first_sln, 1049 first_sln=first_sln,
1355 1050
1356 # Also, target os variables for gclient. 1051 # Also, target os variables for gclient.
1357 target_os=specs.get('target_os', []), 1052 target_os=specs.get('target_os', []),
1358 target_os_only=specs.get('target_os_only', False), 1053 target_os_only=specs.get('target_os_only', False),
1359 1054
1360 # Then, pass in information about how to patch. 1055 # Then, pass in information about how to patch.
1361 patch_root=options.patch_root, 1056 patch_root=options.patch_root,
1362 issue=options.issue, 1057 issue=options.issue,
1363 patchset=options.patchset, 1058 patchset=options.patchset,
1364 rietveld_server=options.rietveld_server, 1059 rietveld_server=options.rietveld_server,
1365 gerrit_repo=options.gerrit_repo, 1060 gerrit_repo=options.gerrit_repo,
1366 gerrit_ref=options.gerrit_ref, 1061 gerrit_ref=options.gerrit_ref,
1367 gerrit_rebase_patch_ref=not options.gerrit_no_rebase_patch_ref, 1062 gerrit_rebase_patch_ref=not options.gerrit_no_rebase_patch_ref,
1368 revision_mapping=options.revision_mapping, 1063 revision_mapping=options.revision_mapping,
1369 apply_issue_email_file=options.apply_issue_email_file, 1064 apply_issue_email_file=options.apply_issue_email_file,
1370 apply_issue_key_file=options.apply_issue_key_file, 1065 apply_issue_key_file=options.apply_issue_key_file,
1371 1066
1372 # For official builders. 1067 # For official builders.
1373 buildspec=buildspec,
1374 gyp_env=options.gyp_env, 1068 gyp_env=options.gyp_env,
1375 runhooks=not options.no_runhooks, 1069 runhooks=not options.no_runhooks,
1376 1070
1377 # Finally, extra configurations such as shallowness of the clone. 1071 # Finally, extra configurations such as shallowness of the clone.
1378 shallow=options.shallow, 1072 shallow=options.shallow,
1379 refs=options.refs, 1073 refs=options.refs,
1380 git_cache_dir=options.git_cache_dir, 1074 git_cache_dir=options.git_cache_dir,
1381 gerrit_reset=not options.gerrit_no_reset) 1075 gerrit_reset=not options.gerrit_no_reset)
1382 gclient_output = ensure_checkout(**checkout_parameters) 1076 gclient_output = ensure_checkout(**checkout_parameters)
1383 except GclientSyncFailed: 1077 except GclientSyncFailed:
1384 print 'We failed gclient sync, lets delete the checkout and retry.' 1078 print 'We failed gclient sync, lets delete the checkout and retry.'
1385 ensure_no_checkout(dir_names, '*') 1079 ensure_no_checkout(dir_names)
1386 gclient_output = ensure_checkout(**checkout_parameters) 1080 gclient_output = ensure_checkout(**checkout_parameters)
1387 except PatchFailed as e: 1081 except PatchFailed as e:
1388 if options.output_json: 1082 if options.output_json:
1389 # Tell recipes information such as root, got_revision, etc. 1083 # Tell recipes information such as root, got_revision, etc.
1390 emit_json(options.output_json, 1084 emit_json(options.output_json,
1391 did_run=True, 1085 did_run=True,
1392 root=first_sln, 1086 root=first_sln,
1393 log_lines=[('patch error', e.output),], 1087 log_lines=[('patch error', e.output),],
1394 patch_apply_return_code=e.code, 1088 patch_apply_return_code=e.code,
1395 patch_root=options.patch_root, 1089 patch_root=options.patch_root,
1396 patch_failure=True, 1090 patch_failure=True,
1397 step_text='%s PATCH FAILED' % step_text, 1091 step_text='%s PATCH FAILED' % step_text,
1398 fixed_revisions=revisions) 1092 fixed_revisions=revisions)
1399 else: 1093 else:
1400 # If we're not on recipes, tell annotator about our got_revisions. 1094 # If we're not on recipes, tell annotator about our got_revisions.
1401 emit_log_lines('patch error', e.output) 1095 emit_log_lines('patch error', e.output)
1402 print '@@@STEP_TEXT@%s PATCH FAILED@@@' % step_text 1096 print '@@@STEP_TEXT@%s PATCH FAILED@@@' % step_text
1403 raise 1097 raise
1404 1098
1405 use_svn_rev = False
1406
1407 # Take care of got_revisions outputs. 1099 # Take care of got_revisions outputs.
1408 revision_mapping = dict(GOT_REVISION_MAPPINGS.get(svn_root, {})) 1100 revision_mapping = GOT_REVISION_MAPPINGS.get(git_slns[0]['url'], {})
1409 if options.revision_mapping: 1101 if options.revision_mapping:
1410 revision_mapping.update(options.revision_mapping) 1102 revision_mapping.update(options.revision_mapping)
1411 1103
1412 # If the repo is not in the default GOT_REVISION_MAPPINGS and no 1104 # If the repo is not in the default GOT_REVISION_MAPPINGS and no
1413 # revision_mapping were specified on the command line then 1105 # revision_mapping were specified on the command line then
1414 # default to setting 'got_revision' based on the first solution. 1106 # default to setting 'got_revision' based on the first solution.
1415 if not revision_mapping: 1107 if not revision_mapping:
1416 revision_mapping[first_sln] = 'got_revision' 1108 revision_mapping[first_sln] = 'got_revision'
1417 1109
1418 got_revisions = parse_got_revision(gclient_output, revision_mapping, 1110 got_revisions = parse_got_revision(gclient_output, revision_mapping)
1419 use_svn_rev)
1420 1111
1421 if not got_revisions: 1112 if not got_revisions:
1422 # TODO(hinoka): We should probably bail out here, but in the interest 1113 # TODO(hinoka): We should probably bail out here, but in the interest
1423 # of giving mis-configured bots some time to get fixed use a dummy 1114 # of giving mis-configured bots some time to get fixed use a dummy
1424 # revision here. 1115 # revision here.
1425 got_revisions = { 'got_revision': 'BOT_UPDATE_NO_REV_FOUND' } 1116 got_revisions = { 'got_revision': 'BOT_UPDATE_NO_REV_FOUND' }
1426 #raise Exception('No got_revision(s) found in gclient output') 1117 #raise Exception('No got_revision(s) found in gclient output')
1427 1118
1428 if options.output_json: 1119 if options.output_json:
1429 manifest = create_manifest() if options.output_manifest else None 1120 manifest = create_manifest() if options.output_manifest else None
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1467 1158
1468 # Check if this script should activate or not. 1159 # Check if this script should activate or not.
1469 active = True 1160 active = True
1470 1161
1471 # Print a helpful message to tell developers whats going on with this step. 1162 # Print a helpful message to tell developers whats going on with this step.
1472 print_debug_info() 1163 print_debug_info()
1473 1164
1474 # Parse, munipulate, and print the gclient solutions. 1165 # Parse, munipulate, and print the gclient solutions.
1475 specs = {} 1166 specs = {}
1476 exec(options.specs, specs) 1167 exec(options.specs, specs)
1477 svn_solutions = specs.get('solutions', []) 1168 orig_solutions = specs.get('solutions', [])
1478 git_slns, svn_root, buildspec = solutions_to_git(svn_solutions) 1169 git_slns = modify_solutions(orig_solutions)
1479 options.revision = maybe_ignore_revision(options.revision, buildspec)
1480 1170
1481 solutions_printer(git_slns) 1171 solutions_printer(git_slns)
1482 1172
1483 try: 1173 try:
1484 # Dun dun dun, the main part of bot_update. 1174 # Dun dun dun, the main part of bot_update.
1485 revisions, step_text = prepare(options, git_slns, active) 1175 revisions, step_text = prepare(options, git_slns, active)
1486 checkout(options, git_slns, specs, buildspec, svn_root, revisions, 1176 checkout(options, git_slns, specs, revisions, step_text)
1487 step_text)
1488 1177
1489 except Inactive:
1490 # Not active, should count as passing.
1491 pass
1492 except PatchFailed as e: 1178 except PatchFailed as e:
1493 emit_flag(options.flag_file) 1179 emit_flag(options.flag_file)
1494 # Return a specific non-zero exit code for patch failure (because it is 1180 # Return a specific non-zero exit code for patch failure (because it is
1495 # a failure), but make it different than other failures to distinguish 1181 # a failure), but make it different than other failures to distinguish
1496 # between infra failures (independent from patch author), and patch 1182 # between infra failures (independent from patch author), and patch
1497 # failures (that patch author can fix). However, PatchFailure due to 1183 # failures (that patch author can fix). However, PatchFailure due to
1498 # download patch failure is still an infra problem. 1184 # download patch failure is still an infra problem.
1499 if e.code == 3: 1185 if e.code == 3:
1500 # Patch download problem. 1186 # Patch download problem.
1501 return 87 1187 return 87
1502 # Genuine patch problem. 1188 # Genuine patch problem.
1503 return 88 1189 return 88
1504 except Exception: 1190 except Exception:
1505 # Unexpected failure. 1191 # Unexpected failure.
1506 emit_flag(options.flag_file) 1192 emit_flag(options.flag_file)
1507 raise 1193 raise
1508 else: 1194 else:
1509 emit_flag(options.flag_file) 1195 emit_flag(options.flag_file)
1510 1196
1511 1197
1512 if __name__ == '__main__': 1198 if __name__ == '__main__':
1513 sys.exit(main()) 1199 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tests/bot_update_coverage_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698