OLD | NEW |
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 | |
11 import copy | 10 import copy |
12 import ctypes | 11 import ctypes |
13 import json | 12 import json |
14 import optparse | 13 import optparse |
15 import os | 14 import os |
16 import pprint | 15 import pprint |
17 import random | 16 import random |
18 import re | 17 import re |
19 import socket | |
20 import subprocess | 18 import subprocess |
21 import sys | 19 import sys |
22 import tempfile | 20 import tempfile |
23 import threading | 21 import threading |
24 import time | 22 import time |
25 import urllib2 | 23 import urllib2 |
26 import urlparse | 24 import urlparse |
27 import uuid | 25 import uuid |
28 | 26 |
29 import os.path as path | 27 import os.path as path |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 del solution['safesync_url'] | 290 del solution['safesync_url'] |
293 | 291 |
294 return solutions | 292 return solutions |
295 | 293 |
296 | 294 |
297 def remove(target): | 295 def remove(target): |
298 """Remove a target by moving it into build.dead.""" | 296 """Remove a target by moving it into build.dead.""" |
299 dead_folder = path.join(BUILDER_DIR, 'build.dead') | 297 dead_folder = path.join(BUILDER_DIR, 'build.dead') |
300 if not path.exists(dead_folder): | 298 if not path.exists(dead_folder): |
301 os.makedirs(dead_folder) | 299 os.makedirs(dead_folder) |
302 os.rename(target, path.join(dead_folder, uuid.uuid4().hex)) | 300 dest = path.join(dead_folder, uuid.uuid4().hex) |
| 301 print 'Marking for removal %s => %s' % (target, dest) |
| 302 os.rename(target, dest) |
303 | 303 |
304 | 304 |
305 def ensure_no_checkout(dir_names): | 305 def ensure_no_checkout(dir_names): |
306 """Ensure that there is no undesired checkout under build/.""" | 306 """Ensure that there is no undesired checkout under build/.""" |
307 build_dir = os.getcwd() | 307 build_dir = os.getcwd() |
308 has_checkout = any(path.exists(path.join(build_dir, dir_name, '.git')) | 308 has_checkout = any(path.exists(path.join(build_dir, dir_name, '.git')) |
309 for dir_name in dir_names) | 309 for dir_name in dir_names) |
310 if has_checkout: | 310 if has_checkout: |
311 for filename in os.listdir(build_dir): | 311 for filename in os.listdir(build_dir): |
312 deletion_target = path.join(build_dir, filename) | 312 deletion_target = path.join(build_dir, filename) |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 # Support for "branch:revision" syntax. | 451 # Support for "branch:revision" syntax. |
452 branch, revision = split_revision | 452 branch, revision = split_revision |
453 | 453 |
454 if revision and revision.upper() != 'HEAD': | 454 if revision and revision.upper() != 'HEAD': |
455 git('checkout', '--force', revision, cwd=folder_name) | 455 git('checkout', '--force', revision, cwd=folder_name) |
456 else: | 456 else: |
457 ref = branch if branch.startswith('refs/') else 'origin/%s' % branch | 457 ref = branch if branch.startswith('refs/') else 'origin/%s' % branch |
458 git('checkout', '--force', ref, cwd=folder_name) | 458 git('checkout', '--force', ref, cwd=folder_name) |
459 | 459 |
460 | 460 |
| 461 def is_broken_repo_dir(repo_dir): |
| 462 # Treat absence of 'config' as a signal of a partially deleted repo. |
| 463 return not path.exists(os.path.join(repo_dir, '.git', 'config')) |
| 464 |
| 465 |
461 def git_checkout(solutions, revisions, shallow, refs, git_cache_dir): | 466 def git_checkout(solutions, revisions, shallow, refs, git_cache_dir): |
462 build_dir = os.getcwd() | 467 build_dir = os.getcwd() |
463 # Before we do anything, break all git_cache locks. | 468 # Before we do anything, break all git_cache locks. |
464 if path.isdir(git_cache_dir): | 469 if path.isdir(git_cache_dir): |
465 git('cache', 'unlock', '-vv', '--force', '--all', | 470 git('cache', 'unlock', '-vv', '--force', '--all', |
466 '--cache-dir', git_cache_dir) | 471 '--cache-dir', git_cache_dir) |
467 for item in os.listdir(git_cache_dir): | 472 for item in os.listdir(git_cache_dir): |
468 filename = os.path.join(git_cache_dir, item) | 473 filename = os.path.join(git_cache_dir, item) |
469 if item.endswith('.lock'): | 474 if item.endswith('.lock'): |
470 raise Exception('%s exists after cache unlock' % filename) | 475 raise Exception('%s exists after cache unlock' % filename) |
(...skipping 18 matching lines...) Expand all Loading... |
489 for ref in refs: | 494 for ref in refs: |
490 populate_cmd.extend(['--ref', ref]) | 495 populate_cmd.extend(['--ref', ref]) |
491 git(*populate_cmd) | 496 git(*populate_cmd) |
492 mirror_dir = git( | 497 mirror_dir = git( |
493 'cache', 'exists', '--quiet', | 498 'cache', 'exists', '--quiet', |
494 '--cache-dir', git_cache_dir, url).strip() | 499 '--cache-dir', git_cache_dir, url).strip() |
495 clone_cmd = ( | 500 clone_cmd = ( |
496 'clone', '--no-checkout', '--local', '--shared', mirror_dir, sln_dir) | 501 'clone', '--no-checkout', '--local', '--shared', mirror_dir, sln_dir) |
497 | 502 |
498 try: | 503 try: |
| 504 # If repo deletion was aborted midway, it may have left .git in broken |
| 505 # state. |
| 506 if path.exists(sln_dir) and is_broken_repo_dir(sln_dir): |
| 507 print 'Git repo %s appears to be broken, removing it' % sln_dir |
| 508 remove(sln_dir) |
| 509 |
499 if not path.isdir(sln_dir): | 510 if not path.isdir(sln_dir): |
500 git(*clone_cmd) | 511 git(*clone_cmd) |
501 else: | 512 else: |
502 git('remote', 'set-url', 'origin', mirror_dir, cwd=sln_dir) | 513 git('remote', 'set-url', 'origin', mirror_dir, cwd=sln_dir) |
503 git('fetch', 'origin', cwd=sln_dir) | 514 git('fetch', 'origin', cwd=sln_dir) |
504 for ref in refs: | 515 for ref in refs: |
505 refspec = '%s:%s' % (ref, ref.lstrip('+')) | 516 refspec = '%s:%s' % (ref, ref.lstrip('+')) |
506 git('fetch', 'origin', refspec, cwd=sln_dir) | 517 git('fetch', 'origin', refspec, cwd=sln_dir) |
507 | 518 |
508 revision = get_target_revision(name, url, revisions) or 'HEAD' | 519 revision = get_target_revision(name, url, revisions) or 'HEAD' |
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1037 def main(): | 1048 def main(): |
1038 # Get inputs. | 1049 # Get inputs. |
1039 options, _ = parse_args() | 1050 options, _ = parse_args() |
1040 | 1051 |
1041 # Check if this script should activate or not. | 1052 # Check if this script should activate or not. |
1042 active = True | 1053 active = True |
1043 | 1054 |
1044 # Print a helpful message to tell developers whats going on with this step. | 1055 # Print a helpful message to tell developers whats going on with this step. |
1045 print_debug_info() | 1056 print_debug_info() |
1046 | 1057 |
1047 # Parse, munipulate, and print the gclient solutions. | 1058 # Parse, manipulate, and print the gclient solutions. |
1048 specs = {} | 1059 specs = {} |
1049 exec(options.specs, specs) | 1060 exec(options.specs, specs) |
1050 orig_solutions = specs.get('solutions', []) | 1061 orig_solutions = specs.get('solutions', []) |
1051 git_slns = modify_solutions(orig_solutions) | 1062 git_slns = modify_solutions(orig_solutions) |
1052 | 1063 |
1053 solutions_printer(git_slns) | 1064 solutions_printer(git_slns) |
1054 | 1065 |
1055 try: | 1066 try: |
1056 # Dun dun dun, the main part of bot_update. | 1067 # Dun dun dun, the main part of bot_update. |
1057 revisions, step_text, shallow = prepare(options, git_slns, active) | 1068 revisions, step_text, shallow = prepare(options, git_slns, active) |
1058 checkout(options, git_slns, specs, revisions, step_text, shallow) | 1069 checkout(options, git_slns, specs, revisions, step_text, shallow) |
1059 | 1070 |
1060 except PatchFailed as e: | 1071 except PatchFailed as e: |
1061 # Return a specific non-zero exit code for patch failure (because it is | 1072 # Return a specific non-zero exit code for patch failure (because it is |
1062 # a failure), but make it different than other failures to distinguish | 1073 # a failure), but make it different than other failures to distinguish |
1063 # between infra failures (independent from patch author), and patch | 1074 # between infra failures (independent from patch author), and patch |
1064 # failures (that patch author can fix). However, PatchFailure due to | 1075 # failures (that patch author can fix). However, PatchFailure due to |
1065 # download patch failure is still an infra problem. | 1076 # download patch failure is still an infra problem. |
1066 if e.code == 3: | 1077 if e.code == 3: |
1067 # Patch download problem. | 1078 # Patch download problem. |
1068 return 87 | 1079 return 87 |
1069 # Genuine patch problem. | 1080 # Genuine patch problem. |
1070 return 88 | 1081 return 88 |
1071 | 1082 |
1072 | 1083 |
1073 if __name__ == '__main__': | 1084 if __name__ == '__main__': |
1074 sys.exit(main()) | 1085 sys.exit(main()) |
OLD | NEW |