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

Side by Side Diff: git_cache.py

Issue 278103002: Added Mirror.UnlockAll with logic fixes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 6 years, 7 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 | Annotate | Revision Log
« 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 """A git command for managing a local cache of git repositories.""" 6 """A git command for managing a local cache of git repositories."""
7 7
8 from __future__ import print_function 8 from __future__ import print_function
9 import errno 9 import errno
10 import logging 10 import logging
11 import optparse 11 import optparse
12 import os 12 import os
13 import re
13 import tempfile 14 import tempfile
14 import time 15 import time
15 import subprocess 16 import subprocess
16 import sys 17 import sys
17 import urlparse 18 import urlparse
18 import zipfile 19 import zipfile
19 20
20 from download_from_google_storage import Gsutil 21 from download_from_google_storage import Gsutil
21 import gclient_utils 22 import gclient_utils
22 import subcommand 23 import subcommand
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 'third_party', 'gsutil', 'gsutil') 145 'third_party', 'gsutil', 'gsutil')
145 bootstrap_bucket = 'chromium-git-cache' 146 bootstrap_bucket = 'chromium-git-cache'
146 147
147 def __init__(self, url, refs=None, print_func=None): 148 def __init__(self, url, refs=None, print_func=None):
148 self.url = url 149 self.url = url
149 self.refs = refs or [] 150 self.refs = refs or []
150 self.basedir = self.UrlToCacheDir(url) 151 self.basedir = self.UrlToCacheDir(url)
151 self.mirror_path = os.path.join(self.GetCachePath(), self.basedir) 152 self.mirror_path = os.path.join(self.GetCachePath(), self.basedir)
152 self.print = print_func or print 153 self.print = print_func or print
153 154
155 @classmethod
156 def FromPath(cls, path):
157 return cls(cls.CacheDirToUrl(path))
158
154 @staticmethod 159 @staticmethod
155 def UrlToCacheDir(url): 160 def UrlToCacheDir(url):
156 """Convert a git url to a normalized form for the cache dir path.""" 161 """Convert a git url to a normalized form for the cache dir path."""
157 parsed = urlparse.urlparse(url) 162 parsed = urlparse.urlparse(url)
158 norm_url = parsed.netloc + parsed.path 163 norm_url = parsed.netloc + parsed.path
159 if norm_url.endswith('.git'): 164 if norm_url.endswith('.git'):
160 norm_url = norm_url[:-len('.git')] 165 norm_url = norm_url[:-len('.git')]
161 return norm_url.replace('-', '--').replace('/', '-').lower() 166 return norm_url.replace('-', '--').replace('/', '-').lower()
162 167
163 @staticmethod 168 @staticmethod
169 def CacheDirToUrl(path):
170 """Convert a cache dir path to its corresponding url."""
171 netpath = re.sub(r'\b-\b', '/', os.path.basename(path)).replace('--', '-')
172 return 'https://%s' % netpath
173
174 @staticmethod
164 def FindExecutable(executable): 175 def FindExecutable(executable):
165 """This mimics the "which" utility.""" 176 """This mimics the "which" utility."""
166 path_folders = os.environ.get('PATH').split(os.pathsep) 177 path_folders = os.environ.get('PATH').split(os.pathsep)
167 178
168 for path_folder in path_folders: 179 for path_folder in path_folders:
169 target = os.path.join(path_folder, executable) 180 target = os.path.join(path_folder, executable)
170 # Just incase we have some ~/blah paths. 181 # Just incase we have some ~/blah paths.
171 target = os.path.abspath(os.path.expanduser(target)) 182 target = os.path.abspath(os.path.expanduser(target))
172 if os.path.isfile(target) and os.access(target, os.X_OK): 183 if os.path.isfile(target) and os.access(target, os.X_OK):
173 return target 184 return target
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 # Creating a temp file and then deleting it ensures we can use this name. 350 # Creating a temp file and then deleting it ensures we can use this name.
340 _, tmp_zipfile = tempfile.mkstemp(suffix='.zip') 351 _, tmp_zipfile = tempfile.mkstemp(suffix='.zip')
341 os.remove(tmp_zipfile) 352 os.remove(tmp_zipfile)
342 subprocess.call(['zip', '-r', tmp_zipfile, '.'], cwd=self.mirror_path) 353 subprocess.call(['zip', '-r', tmp_zipfile, '.'], cwd=self.mirror_path)
343 gsutil = Gsutil(path=self.gsutil_exe, boto_path=None) 354 gsutil = Gsutil(path=self.gsutil_exe, boto_path=None)
344 dest_name = 'gs://%s/%s/%s.zip' % ( 355 dest_name = 'gs://%s/%s/%s.zip' % (
345 self.bootstrap_bucket, self.basedir, gen_number) 356 self.bootstrap_bucket, self.basedir, gen_number)
346 gsutil.call('cp', tmp_zipfile, dest_name) 357 gsutil.call('cp', tmp_zipfile, dest_name)
347 os.remove(tmp_zipfile) 358 os.remove(tmp_zipfile)
348 359
360
361 @staticmethod
362 def BreakLocks(path):
363 did_unlock = False
364 lf = Lockfile(path)
365 if lf.break_lock():
366 did_unlock = True
367 # Look for lock files that might have been left behind by an interrupted
368 # git process.
369 lf = os.path.join(path, 'config.lock')
370 if os.path.exists(lf):
371 os.remove(lf)
372 did_unlock = True
373 return did_unlock
374
349 def unlock(self): 375 def unlock(self):
350 lf = Lockfile(self.mirror_path) 376 return self.BreakLocks(self.mirror_path)
351 config_lock = os.path.join(self.mirror_path, 'config.lock') 377
352 if os.path.exists(config_lock): 378 @classmethod
353 os.remove(config_lock) 379 def UnlockAll(cls):
354 lf.break_lock() 380 cachepath = cls.GetCachePath()
381 dirlist = os.listdir(cachepath)
382 repo_dirs = set([os.path.join(cachepath, path) for path in dirlist
383 if os.path.isdir(os.path.join(cachepath, path))])
384 for dirent in dirlist:
385 if (dirent.endswith('.lock') and
386 os.path.isfile(os.path.join(cachepath, dirent))):
387 repo_dirs.add(os.path.join(cachepath, dirent[:-5]))
388
389 unlocked_repos = []
390 for repo_dir in repo_dirs:
391 if cls.BreakLocks(repo_dir):
392 unlocked_repos.append(repo_dir)
393
394 return unlocked_repos
355 395
356 @subcommand.usage('[url of repo to check for caching]') 396 @subcommand.usage('[url of repo to check for caching]')
357 def CMDexists(parser, args): 397 def CMDexists(parser, args):
358 """Check to see if there already is a cache of the given repo.""" 398 """Check to see if there already is a cache of the given repo."""
359 _, args = parser.parse_args(args) 399 _, args = parser.parse_args(args)
360 if not len(args) == 1: 400 if not len(args) == 1:
361 parser.error('git cache exists only takes exactly one repo url.') 401 parser.error('git cache exists only takes exactly one repo url.')
362 url = args[0] 402 url = args[0]
363 mirror = Mirror(url) 403 mirror = Mirror(url)
364 if mirror.exists(): 404 if mirror.exists():
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 def CMDunlock(parser, args): 460 def CMDunlock(parser, args):
421 """Unlock one or all repos if their lock files are still around.""" 461 """Unlock one or all repos if their lock files are still around."""
422 parser.add_option('--force', '-f', action='store_true', 462 parser.add_option('--force', '-f', action='store_true',
423 help='Actually perform the action') 463 help='Actually perform the action')
424 parser.add_option('--all', '-a', action='store_true', 464 parser.add_option('--all', '-a', action='store_true',
425 help='Unlock all repository caches') 465 help='Unlock all repository caches')
426 options, args = parser.parse_args(args) 466 options, args = parser.parse_args(args)
427 if len(args) > 1 or (len(args) == 0 and not options.all): 467 if len(args) > 1 or (len(args) == 0 and not options.all):
428 parser.error('git cache unlock takes exactly one repo url, or --all') 468 parser.error('git cache unlock takes exactly one repo url, or --all')
429 469
430 repo_dirs = [] 470 if not options.force:
431 if not options.all:
432 url = args[0]
433 repo_dirs.append(Mirror(url).mirror_path)
434 else:
435 cachepath = Mirror.GetCachePath() 471 cachepath = Mirror.GetCachePath()
436 repo_dirs = [os.path.join(cachepath, path) 472 lockfiles = [os.path.join(cachepath, path)
437 for path in os.listdir(cachepath) 473 for path in os.listdir(cachepath)
438 if os.path.isdir(os.path.join(cachepath, path))] 474 if path.endswith('.lock') and os.path.isfile(path)]
439 repo_dirs.extend([os.path.join(cachepath,
440 lockfile.replace('.lock', ''))
441 for lockfile in os.listdir(cachepath)
442 if os.path.isfile(os.path.join(cachepath,
443 lockfile))
444 and lockfile.endswith('.lock')
445 and os.path.join(cachepath, lockfile)
446 not in repo_dirs])
447 lockfiles = [repo_dir + '.lock' for repo_dir in repo_dirs
448 if os.path.exists(repo_dir + '.lock')]
449
450 if not options.force:
451 parser.error('git cache unlock requires -f|--force to do anything. ' 475 parser.error('git cache unlock requires -f|--force to do anything. '
452 'Refusing to unlock the following repo caches: ' 476 'Refusing to unlock the following repo caches: '
453 ', '.join(lockfiles)) 477 ', '.join(lockfiles))
454 478
455 unlocked_repos = [] 479 unlocked_repos = []
456 untouched_repos = [] 480 if options.all:
457 for repo_dir in repo_dirs: 481 unlocked_repos.extend(Mirror.UnlockAll())
458 lf = Lockfile(repo_dir) 482 else:
459 config_lock = os.path.join(repo_dir, 'config.lock') 483 m = Mirror(args[0])
460 unlocked = False 484 if m.unlock():
461 if os.path.exists(config_lock): 485 unlocked_repos.append(m.mirror_path)
462 os.remove(config_lock)
463 unlocked = True
464 if lf.break_lock():
465 unlocked = True
466
467 if unlocked:
468 unlocked_repos.append(repo_dir)
469 else:
470 untouched_repos.append(repo_dir)
471 486
472 if unlocked_repos: 487 if unlocked_repos:
473 logging.info('Broke locks on these caches:\n %s' % '\n '.join( 488 logging.info('Broke locks on these caches:\n %s' % '\n '.join(
474 unlocked_repos)) 489 unlocked_repos))
475 if untouched_repos:
476 logging.debug('Did not touch these caches:\n %s' % '\n '.join(
477 untouched_repos))
478 490
479 491
480 class OptionParser(optparse.OptionParser): 492 class OptionParser(optparse.OptionParser):
481 """Wrapper class for OptionParser to handle global options.""" 493 """Wrapper class for OptionParser to handle global options."""
482 494
483 def __init__(self, *args, **kwargs): 495 def __init__(self, *args, **kwargs):
484 optparse.OptionParser.__init__(self, *args, prog='git cache', **kwargs) 496 optparse.OptionParser.__init__(self, *args, prog='git cache', **kwargs)
485 self.add_option('-c', '--cache-dir', 497 self.add_option('-c', '--cache-dir',
486 help='Path to the directory containing the cache') 498 help='Path to the directory containing the cache')
487 self.add_option('-v', '--verbose', action='count', default=0, 499 self.add_option('-v', '--verbose', action='count', default=0,
(...skipping 19 matching lines...) Expand all
507 return options, args 519 return options, args
508 520
509 521
510 def main(argv): 522 def main(argv):
511 dispatcher = subcommand.CommandDispatcher(__name__) 523 dispatcher = subcommand.CommandDispatcher(__name__)
512 return dispatcher.execute(OptionParser(), argv) 524 return dispatcher.execute(OptionParser(), argv)
513 525
514 526
515 if __name__ == '__main__': 527 if __name__ == '__main__':
516 sys.exit(main(sys.argv[1:])) 528 sys.exit(main(sys.argv[1:]))
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