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

Side by Side Diff: git_cache.py

Issue 1320383004: Allow 'git cache fetch' to re-bootstrap. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 5 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 | 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
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 140
141 class Mirror(object): 141 class Mirror(object):
142 142
143 git_exe = 'git.bat' if sys.platform.startswith('win') else 'git' 143 git_exe = 'git.bat' if sys.platform.startswith('win') else 'git'
144 gsutil_exe = os.path.join( 144 gsutil_exe = os.path.join(
145 os.path.dirname(os.path.abspath(__file__)), 'gsutil.py') 145 os.path.dirname(os.path.abspath(__file__)), 'gsutil.py')
146 cachepath_lock = threading.Lock() 146 cachepath_lock = threading.Lock()
147 147
148 def __init__(self, url, refs=None, print_func=None): 148 def __init__(self, url, refs=None, print_func=None):
149 self.url = url 149 self.url = url
150 self.refs = refs or [] 150 self.refs = set([ref.lstrip('+').rstrip('/') for ref in (refs or [])])
iannucci 2015/09/22 20:35:26 can we have a 'parse_fetch_spec' function so the n
szager1 2015/09/22 22:48:27 Done.
151 self.basedir = self.UrlToCacheDir(url) 151 self.basedir = self.UrlToCacheDir(url)
152 self.mirror_path = os.path.join(self.GetCachePath(), self.basedir) 152 self.mirror_path = os.path.join(self.GetCachePath(), self.basedir)
153 if print_func: 153 if print_func:
154 self.print = self.print_without_file 154 self.print = self.print_without_file
155 self.print_func = print_func 155 self.print_func = print_func
156 else: 156 else:
157 self.print = print 157 self.print = print
158 158
159 def print_without_file(self, message, **kwargs): 159 def print_without_file(self, message, **kwargs):
160 self.print_func(message) 160 self.print_func(message)
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 230
231 # Allocate more RAM for cache-ing delta chains, for better performance 231 # Allocate more RAM for cache-ing delta chains, for better performance
232 # of "Resolving deltas". 232 # of "Resolving deltas".
233 self.RunGit(['config', 'core.deltaBaseCacheLimit', 233 self.RunGit(['config', 'core.deltaBaseCacheLimit',
234 gclient_utils.DefaultDeltaBaseCacheLimit()], cwd=cwd) 234 gclient_utils.DefaultDeltaBaseCacheLimit()], cwd=cwd)
235 235
236 self.RunGit(['config', 'remote.origin.url', self.url], cwd=cwd) 236 self.RunGit(['config', 'remote.origin.url', self.url], cwd=cwd)
237 self.RunGit(['config', '--replace-all', 'remote.origin.fetch', 237 self.RunGit(['config', '--replace-all', 'remote.origin.fetch',
238 '+refs/heads/*:refs/heads/*', r'\+refs/heads/\*:.*'], cwd=cwd) 238 '+refs/heads/*:refs/heads/*', r'\+refs/heads/\*:.*'], cwd=cwd)
239 for ref in self.refs: 239 for ref in self.refs:
240 ref = ref.lstrip('+').rstrip('/')
241 if ref.startswith('refs/'): 240 if ref.startswith('refs/'):
242 refspec = '+%s:%s' % (ref, ref) 241 refspec = '+%s:%s' % (ref, ref)
243 regex = r'\+%s:.*' % ref.replace('*', r'\*') 242 regex = r'\+%s:.*' % ref.replace('*', r'\*')
244 else: 243 else:
245 refspec = '+refs/%s/*:refs/%s/*' % (ref, ref) 244 refspec = '+refs/%s/*:refs/%s/*' % (ref, ref)
246 regex = r'\+refs/heads/%s:.*' % ref.replace('*', r'\*') 245 regex = r'\+refs/heads/%s:.*' % ref.replace('*', r'\*')
247 self.RunGit( 246 self.RunGit(
248 ['config', '--replace-all', 'remote.origin.fetch', refspec, regex], 247 ['config', '--replace-all', 'remote.origin.fetch', refspec, regex],
249 cwd=cwd) 248 cwd=cwd)
250 249
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 if retcode: 306 if retcode:
308 self.print( 307 self.print(
309 'Extracting bootstrap zipfile %s failed.\n' 308 'Extracting bootstrap zipfile %s failed.\n'
310 'Resuming normal operations.' % filename) 309 'Resuming normal operations.' % filename)
311 return False 310 return False
312 return True 311 return True
313 312
314 def exists(self): 313 def exists(self):
315 return os.path.isfile(os.path.join(self.mirror_path, 'config')) 314 return os.path.isfile(os.path.join(self.mirror_path, 'config'))
316 315
316 def _preserve_fetchspec(self):
317 """Read and preserve remote.origin.fetch from an existing mirror."""
318 if not self.exists():
319 return
320 try:
321 config_fetchspecs = subprocess.check_output(
322 [self.git_exe, 'config', '--get-all', 'remote.origin.fetch'],
323 cwd=self.mirror_path)
324 for fetchspec in config_fetchspecs.splitlines():
325 self.refs.add(fetchspec.split(':')[0].lstrip('+').rstrip('/'))
iannucci 2015/09/22 20:35:26 and here too
szager1 2015/09/22 22:48:27 Done.
326 except subprocess.CalledProcessError:
327 pass
328
317 def _ensure_bootstrapped(self, depth, bootstrap, force=False): 329 def _ensure_bootstrapped(self, depth, bootstrap, force=False):
318 tempdir = None 330 tempdir = None
319 config_file = os.path.join(self.mirror_path, 'config')
320 pack_dir = os.path.join(self.mirror_path, 'objects', 'pack') 331 pack_dir = os.path.join(self.mirror_path, 'objects', 'pack')
321 pack_files = [] 332 pack_files = []
322 333
323 if os.path.isdir(pack_dir): 334 if os.path.isdir(pack_dir):
324 pack_files = [f for f in os.listdir(pack_dir) if f.endswith('.pack')] 335 pack_files = [f for f in os.listdir(pack_dir) if f.endswith('.pack')]
325 336
326 should_bootstrap = (force or 337 should_bootstrap = (force or
327 not os.path.exists(config_file) or 338 not self.exists() or
328 len(pack_files) > GC_AUTOPACKLIMIT) 339 len(pack_files) > GC_AUTOPACKLIMIT)
329 if should_bootstrap: 340 if should_bootstrap:
341 if self.exists():
342 # Re-bootstrapping an existing mirror; preserve existing fetch spec.
343 self._preserve_fetchspec()
330 tempdir = tempfile.mkdtemp( 344 tempdir = tempfile.mkdtemp(
331 prefix='_cache_tmp', suffix=self.basedir, dir=self.GetCachePath()) 345 prefix='_cache_tmp', suffix=self.basedir, dir=self.GetCachePath())
332 bootstrapped = not depth and bootstrap and self.bootstrap_repo(tempdir) 346 bootstrapped = not depth and bootstrap and self.bootstrap_repo(tempdir)
333 if bootstrapped: 347 if bootstrapped:
334 # Bootstrap succeeded; delete previous cache, if any. 348 # Bootstrap succeeded; delete previous cache, if any.
335 gclient_utils.rmtree(self.mirror_path) 349 gclient_utils.rmtree(self.mirror_path)
336 elif not os.path.exists(config_file): 350 elif not self.exists():
337 # Bootstrap failed, no previous cache; start with a bare git dir. 351 # Bootstrap failed, no previous cache; start with a bare git dir.
338 self.RunGit(['init', '--bare'], cwd=tempdir) 352 self.RunGit(['init', '--bare'], cwd=tempdir)
339 else: 353 else:
340 # Bootstrap failed, previous cache exists; warn and continue. 354 # Bootstrap failed, previous cache exists; warn and continue.
341 logging.warn( 355 logging.warn(
342 'Git cache has a lot of pack files (%d). Tried to re-bootstrap ' 356 'Git cache has a lot of pack files (%d). Tried to re-bootstrap '
343 'but failed. Continuing with non-optimized repository.' 357 'but failed. Continuing with non-optimized repository.'
344 % len(pack_files)) 358 % len(pack_files))
345 gclient_utils.rmtree(tempdir) 359 gclient_utils.rmtree(tempdir)
346 tempdir = None 360 tempdir = None
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 } 570 }
557 if options.depth: 571 if options.depth:
558 kwargs['depth'] = options.depth 572 kwargs['depth'] = options.depth
559 mirror.populate(**kwargs) 573 mirror.populate(**kwargs)
560 574
561 575
562 @subcommand.usage('Fetch new commits into cache and current checkout') 576 @subcommand.usage('Fetch new commits into cache and current checkout')
563 def CMDfetch(parser, args): 577 def CMDfetch(parser, args):
564 """Update mirror, and fetch in cwd.""" 578 """Update mirror, and fetch in cwd."""
565 parser.add_option('--all', action='store_true', help='Fetch all remotes') 579 parser.add_option('--all', action='store_true', help='Fetch all remotes')
580 parser.add_option('--no_bootstrap', '--no-bootstrap',
581 action='store_true',
582 help='Don\'t (re)bootstrap from Google Storage')
566 options, args = parser.parse_args(args) 583 options, args = parser.parse_args(args)
567 584
568 # Figure out which remotes to fetch. This mimics the behavior of regular 585 # Figure out which remotes to fetch. This mimics the behavior of regular
569 # 'git fetch'. Note that in the case of "stacked" or "pipelined" branches, 586 # 'git fetch'. Note that in the case of "stacked" or "pipelined" branches,
570 # this will NOT try to traverse up the branching structure to find the 587 # this will NOT try to traverse up the branching structure to find the
571 # ultimate remote to update. 588 # ultimate remote to update.
572 remotes = [] 589 remotes = []
573 if options.all: 590 if options.all:
574 assert not args, 'fatal: fetch --all does not take a repository argument' 591 assert not args, 'fatal: fetch --all does not take a repository argument'
575 remotes = subprocess.check_output([Mirror.git_exe, 'remote']).splitlines() 592 remotes = subprocess.check_output([Mirror.git_exe, 'remote']).splitlines()
(...skipping 10 matching lines...) Expand all
586 remotes = [upstream] 603 remotes = [upstream]
587 if not remotes: 604 if not remotes:
588 remotes = ['origin'] 605 remotes = ['origin']
589 606
590 cachepath = Mirror.GetCachePath() 607 cachepath = Mirror.GetCachePath()
591 git_dir = os.path.abspath(subprocess.check_output( 608 git_dir = os.path.abspath(subprocess.check_output(
592 [Mirror.git_exe, 'rev-parse', '--git-dir'])) 609 [Mirror.git_exe, 'rev-parse', '--git-dir']))
593 git_dir = os.path.abspath(git_dir) 610 git_dir = os.path.abspath(git_dir)
594 if git_dir.startswith(cachepath): 611 if git_dir.startswith(cachepath):
595 mirror = Mirror.FromPath(git_dir) 612 mirror = Mirror.FromPath(git_dir)
596 mirror.populate() 613 mirror.populate(bootstrap=not options.no_bootstrap)
597 return 0 614 return 0
598 for remote in remotes: 615 for remote in remotes:
599 remote_url = subprocess.check_output( 616 remote_url = subprocess.check_output(
600 [Mirror.git_exe, 'config', 'remote.%s.url' % remote]).strip() 617 [Mirror.git_exe, 'config', 'remote.%s.url' % remote]).strip()
601 if remote_url.startswith(cachepath): 618 if remote_url.startswith(cachepath):
602 mirror = Mirror.FromPath(remote_url) 619 mirror = Mirror.FromPath(remote_url)
603 mirror.print = lambda *args: None 620 mirror.print = lambda *args: None
604 print('Updating git cache...') 621 print('Updating git cache...')
605 mirror.populate() 622 mirror.populate(bootstrap=not options.no_bootstrap)
606 subprocess.check_call([Mirror.git_exe, 'fetch', remote]) 623 subprocess.check_call([Mirror.git_exe, 'fetch', remote])
607 return 0 624 return 0
608 625
609 626
610 @subcommand.usage('[url of repo to unlock, or -a|--all]') 627 @subcommand.usage('[url of repo to unlock, or -a|--all]')
611 def CMDunlock(parser, args): 628 def CMDunlock(parser, args):
612 """Unlock one or all repos if their lock files are still around.""" 629 """Unlock one or all repos if their lock files are still around."""
613 parser.add_option('--force', '-f', action='store_true', 630 parser.add_option('--force', '-f', action='store_true',
614 help='Actually perform the action') 631 help='Actually perform the action')
615 parser.add_option('--all', '-a', action='store_true', 632 parser.add_option('--all', '-a', action='store_true',
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 dispatcher = subcommand.CommandDispatcher(__name__) 695 dispatcher = subcommand.CommandDispatcher(__name__)
679 return dispatcher.execute(OptionParser(), argv) 696 return dispatcher.execute(OptionParser(), argv)
680 697
681 698
682 if __name__ == '__main__': 699 if __name__ == '__main__':
683 try: 700 try:
684 sys.exit(main(sys.argv[1:])) 701 sys.exit(main(sys.argv[1:]))
685 except KeyboardInterrupt: 702 except KeyboardInterrupt:
686 sys.stderr.write('interrupted\n') 703 sys.stderr.write('interrupted\n')
687 sys.exit(1) 704 sys.exit(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