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

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

Issue 2342973002: Teach bot_update to remove partially deleted git repos. (Closed)
Patch Set: Teach bot_update to remove partially deleted git repos. 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 | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698