Selaa lähdekoodia

git-cache: Add option to fetch commits.

Add option to git cache to fetch commits.
And use it in bot_update and gclient sync to make sure
the needed commits are present on the checkout.

Change-Id: I9e90da9e3be6e7bacf714b22bf0b735463e655b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2829942
Reviewed-by: Gavin Mak <gavinmak@google.com>
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
Edward Lesmes 4 vuotta sitten
vanhempi
commit
4c67f856f0
3 muutettua tiedostoa jossa 33 lisäystä ja 27 poistoa
  1. 7 4
      gclient_scm.py
  2. 12 2
      git_cache.py
  3. 14 21
      recipes/recipe_modules/bot_update/resources/bot_update.py

+ 7 - 4
gclient_scm.py

@@ -399,7 +399,7 @@ class GitWrapper(SCMWrapper):
     elif not scm.GIT.IsValidRevision(self.checkout_path, target_rev):
     elif not scm.GIT.IsValidRevision(self.checkout_path, target_rev):
       # Fetch |target_rev| if it's not already available.
       # Fetch |target_rev| if it's not already available.
       url, _ = gclient_utils.SplitUrlRevision(self.url)
       url, _ = gclient_utils.SplitUrlRevision(self.url)
-      mirror = self._GetMirror(url, options, target_rev)
+      mirror = self._GetMirror(url, options, target_rev, target_rev)
       if mirror:
       if mirror:
         rev_type = 'branch' if target_rev.startswith('refs/') else 'hash'
         rev_type = 'branch' if target_rev.startswith('refs/') else 'hash'
         self._UpdateMirrorIfNotContains(mirror, options, rev_type, target_rev)
         self._UpdateMirrorIfNotContains(mirror, options, rev_type, target_rev)
@@ -506,7 +506,7 @@ class GitWrapper(SCMWrapper):
     if revision_ref.startswith('refs/branch-heads'):
     if revision_ref.startswith('refs/branch-heads'):
       options.with_branch_heads = True
       options.with_branch_heads = True
 
 
-    mirror = self._GetMirror(url, options, revision_ref)
+    mirror = self._GetMirror(url, options, revision, revision_ref)
     if mirror:
     if mirror:
       url = mirror.mirror_path
       url = mirror.mirror_path
 
 
@@ -946,13 +946,14 @@ class GitWrapper(SCMWrapper):
     return os.path.join(self._root_dir,
     return os.path.join(self._root_dir,
                         'old_' + self.relpath.replace(os.sep, '_')) + '.git'
                         'old_' + self.relpath.replace(os.sep, '_')) + '.git'
 
 
-  def _GetMirror(self, url, options, revision_ref=None):
+  def _GetMirror(self, url, options, revision=None, revision_ref=None):
     """Get a git_cache.Mirror object for the argument url."""
     """Get a git_cache.Mirror object for the argument url."""
     if not self.cache_dir:
     if not self.cache_dir:
       return None
       return None
     mirror_kwargs = {
     mirror_kwargs = {
         'print_func': self.filter,
         'print_func': self.filter,
-        'refs': []
+        'refs': [],
+        'commits': [],
     }
     }
     if hasattr(options, 'with_branch_heads') and options.with_branch_heads:
     if hasattr(options, 'with_branch_heads') and options.with_branch_heads:
       mirror_kwargs['refs'].append('refs/branch-heads/*')
       mirror_kwargs['refs'].append('refs/branch-heads/*')
@@ -962,6 +963,8 @@ class GitWrapper(SCMWrapper):
       mirror_kwargs['refs'].append('refs/tags/*')
       mirror_kwargs['refs'].append('refs/tags/*')
     elif revision_ref and revision_ref.startswith('refs/tags/'):
     elif revision_ref and revision_ref.startswith('refs/tags/'):
       mirror_kwargs['refs'].append(revision_ref)
       mirror_kwargs['refs'].append(revision_ref)
+    if revision and not revision.startswith('refs/'):
+      mirror_kwargs['commits'].append(revision)
     return git_cache.Mirror(url, **mirror_kwargs)
     return git_cache.Mirror(url, **mirror_kwargs)
 
 
   def _UpdateMirrorIfNotContains(self, mirror, options, rev_type, revision):
   def _UpdateMirrorIfNotContains(self, mirror, options, rev_type, revision):

+ 12 - 2
git_cache.py

@@ -107,9 +107,10 @@ class Mirror(object):
     regex = r'\+%s:.*' % src.replace('*', r'\*')
     regex = r'\+%s:.*' % src.replace('*', r'\*')
     return ('+%s:%s' % (src, dest), regex)
     return ('+%s:%s' % (src, dest), regex)
 
 
-  def __init__(self, url, refs=None, print_func=None):
+  def __init__(self, url, refs=None, commits=None, print_func=None):
     self.url = url
     self.url = url
     self.fetch_specs = set([self.parse_fetch_spec(ref) for ref in (refs or [])])
     self.fetch_specs = set([self.parse_fetch_spec(ref) for ref in (refs or [])])
+    self.fetch_commits = set(commits or [])
     self.basedir = self.UrlToCacheDir(url)
     self.basedir = self.UrlToCacheDir(url)
     self.mirror_path = os.path.join(self.GetCachePath(), self.basedir)
     self.mirror_path = os.path.join(self.GetCachePath(), self.basedir)
     if print_func:
     if print_func:
@@ -448,6 +449,13 @@ class Mirror(object):
         if spec == '+refs/heads/*:refs/heads/*':
         if spec == '+refs/heads/*:refs/heads/*':
           raise ClobberNeeded()  # Corrupted cache.
           raise ClobberNeeded()  # Corrupted cache.
         logging.warning('Fetch of %s failed' % spec)
         logging.warning('Fetch of %s failed' % spec)
+    for commit in self.fetch_commits:
+      self.print('Fetching %s' % commit)
+      try:
+        with self.print_duration_of('fetch %s' % commit):
+          self.RunGit(['fetch', 'origin', commit], cwd=rundir, retry=True)
+      except subprocess.CalledProcessError:
+        logging.warning('Fetch of %s failed' % commit)
 
 
   def populate(self,
   def populate(self,
                depth=None,
                depth=None,
@@ -635,6 +643,8 @@ def CMDpopulate(parser, args):
                     help='Only cache 10000 commits of history')
                     help='Only cache 10000 commits of history')
   parser.add_option('--ref', action='append',
   parser.add_option('--ref', action='append',
                     help='Specify additional refs to be fetched')
                     help='Specify additional refs to be fetched')
+  parser.add_option('--commit', action='append',
+                    help='Specify additional commits to be fetched')
   parser.add_option('--no_bootstrap', '--no-bootstrap',
   parser.add_option('--no_bootstrap', '--no-bootstrap',
                     action='store_true',
                     action='store_true',
                     help='Don\'t bootstrap from Google Storage')
                     help='Don\'t bootstrap from Google Storage')
@@ -657,7 +667,7 @@ def CMDpopulate(parser, args):
     print('break_locks is no longer used. Please remove its usage.')
     print('break_locks is no longer used. Please remove its usage.')
   url = args[0]
   url = args[0]
 
 
-  mirror = Mirror(url, refs=options.ref)
+  mirror = Mirror(url, refs=options.ref, commits=options.commit)
   kwargs = {
   kwargs = {
       'no_fetch_tags': options.no_fetch_tags,
       'no_fetch_tags': options.no_fetch_tags,
       'verbose': options.verbose,
       'verbose': options.verbose,

+ 14 - 21
recipes/recipe_modules/bot_update/resources/bot_update.py

@@ -708,10 +708,16 @@ def _git_checkout(sln, sln_dir, revisions, refs, no_fetch_tags, git_cache_dir,
                   cleanup_dir, enforce_fetch):
                   cleanup_dir, enforce_fetch):
   name = sln['name']
   name = sln['name']
   url = sln['url']
   url = sln['url']
+
+  branch, revision = get_target_branch_and_revision(name, url, revisions)
+  pin = revision if COMMIT_HASH_RE.match(revision) else None
+
   populate_cmd = (['cache', 'populate', '--ignore_locks', '-v',
   populate_cmd = (['cache', 'populate', '--ignore_locks', '-v',
                    '--cache-dir', git_cache_dir, url, '--reset-fetch-config'])
                    '--cache-dir', git_cache_dir, url, '--reset-fetch-config'])
   if no_fetch_tags:
   if no_fetch_tags:
     populate_cmd.extend(['--no-fetch-tags'])
     populate_cmd.extend(['--no-fetch-tags'])
+  if pin:
+    populate_cmd.extend(['--commit', pin])
   for ref in refs:
   for ref in refs:
     populate_cmd.extend(['--ref', ref])
     populate_cmd.extend(['--ref', ref])
 
 
@@ -726,34 +732,21 @@ def _git_checkout(sln, sln_dir, revisions, refs, no_fetch_tags, git_cache_dir,
         'GIT_REDACT_COOKIES': 'o,SSO,GSSO_UberProxy,__Secure-GSSO_UberProxy',
         'GIT_REDACT_COOKIES': 'o,SSO,GSSO_UberProxy,__Secure-GSSO_UberProxy',
     }
     }
 
 
-  branch, revision = get_target_branch_and_revision(name, url, revisions)
-  pin = revision if COMMIT_HASH_RE.match(revision) else None
-
   # Step 1: populate/refresh cache, if necessary.
   # Step 1: populate/refresh cache, if necessary.
-  if (enforce_fetch
-      or not pin
-      or not _has_in_git_cache(pin, refs, git_cache_dir, url)):
+  if enforce_fetch or not pin:
     git(*populate_cmd, env=env)
     git(*populate_cmd, env=env)
 
 
   # If cache still doesn't have required pin/refs, try again and fetch pin/refs
   # If cache still doesn't have required pin/refs, try again and fetch pin/refs
   # directly.
   # directly.
-  for attempt in range(3):
-    if _has_in_git_cache(pin, refs, git_cache_dir, url):
-      break
-    try:
-      mirror_dir = git(
-          'cache', 'exists', '--quiet', '--cache-dir', git_cache_dir, url).strip()
+  if not _has_in_git_cache(pin, refs, git_cache_dir, url):
+    for attempt in range(3):
       with git_config_if_not_set(
       with git_config_if_not_set(
           'http.extraheader', 'X-Return-Encrypted-Headers: all'):
           'http.extraheader', 'X-Return-Encrypted-Headers: all'):
-        if pin:
-          git('fetch', 'origin', pin, env=env, cwd=mirror_dir)
-        for ref in refs:
-          git('fetch', 'origin', '%s:%s' % (ref, ref),
-              env=env, cwd=mirror_dir)
-      break
-    except SubprocessFailed as e:
-      print('Failed to fetch required commits and refs: %s' % str(e))
-      print('Waiting 60s and trying again')
+        git(*populate_cmd, env=env)
+      if _has_in_git_cache(pin, refs, git_cache_dir, url):
+        break
+      print('Some required refs/commits are still not present.')
+      print('Waiting 60s and trying again.')
       time.sleep(60)
       time.sleep(60)
 
 
   # Step 2: populate a checkout from local cache. All operations are local.
   # Step 2: populate a checkout from local cache. All operations are local.