| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 | |
| 7 import cStringIO | 6 import cStringIO |
| 8 import os | 7 import os |
| 9 import re | 8 import re |
| 10 import subprocess | 9 import subprocess |
| 11 import sys | 10 import sys |
| 12 import threading | 11 import threading |
| 13 | 12 |
| 13 try: |
| 14 import git_cache |
| 15 except ImportError: |
| 16 for p in os.environ['PATH'].split(os.pathsep): |
| 17 if (os.path.basename(p) == 'depot_tools' and |
| 18 os.path.exists(os.path.join(p, 'git_cache.py'))): |
| 19 sys.path.append(p) |
| 20 import git_cache |
| 21 |
| 14 | 22 |
| 15 # Show more information about the commands being executed. | 23 # Show more information about the commands being executed. |
| 16 VERBOSE = False | 24 VERBOSE = False |
| 17 | 25 |
| 18 # The longest any single subprocess will be allowed to run. | 26 # The longest any single subprocess will be allowed to run. |
| 19 TIMEOUT = 40 * 60 | 27 TIMEOUT = 40 * 60 |
| 20 | 28 |
| 21 class AbnormalExit(Exception): | 29 class AbnormalExit(Exception): |
| 22 pass | 30 pass |
| 23 | 31 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 47 def close(self): | 55 def close(self): |
| 48 # Empty out the line buffer. | 56 # Empty out the line buffer. |
| 49 self.write('\n') | 57 self.write('\n') |
| 50 self.out_q.put(None) | 58 self.out_q.put(None) |
| 51 self.closed = True | 59 self.closed = True |
| 52 | 60 |
| 53 | 61 |
| 54 def GetStatusOutput(cmd, cwd=None, out_buffer=None): | 62 def GetStatusOutput(cmd, cwd=None, out_buffer=None): |
| 55 """Return (status, output) of executing cmd in a shell.""" | 63 """Return (status, output) of executing cmd in a shell.""" |
| 56 if VERBOSE: | 64 if VERBOSE: |
| 57 print '' | 65 print >> sys.stderr, '' |
| 58 print '[DEBUG] Running "%s"' % cmd | 66 print >> sys.stderr, '[DEBUG] Running "%s"' % cmd |
| 59 | 67 |
| 60 def _thread_main(): | 68 def _thread_main(): |
| 61 thr = threading.current_thread() | 69 thr = threading.current_thread() |
| 62 thr.status = -1 | 70 thr.status = -1 |
| 63 thr.stdout = '' | 71 thr.stdout = '' |
| 64 thr.stderr = '<timeout>' | 72 thr.stderr = '<timeout>' |
| 65 try: | 73 try: |
| 66 if out_buffer: | 74 if out_buffer: |
| 67 proc = subprocess.Popen(cmd, shell=True, | 75 proc = subprocess.Popen(cmd, shell=True, |
| 68 cwd=cwd, stdout=subprocess.PIPE, | 76 cwd=cwd, stdout=subprocess.PIPE, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 93 | 101 |
| 94 thr = threading.Thread(target=_thread_main) | 102 thr = threading.Thread(target=_thread_main) |
| 95 thr.daemon = True | 103 thr.daemon = True |
| 96 thr.start() | 104 thr.start() |
| 97 thr.join(TIMEOUT) | 105 thr.join(TIMEOUT) |
| 98 | 106 |
| 99 # pylint: disable=E1101 | 107 # pylint: disable=E1101 |
| 100 if VERBOSE: | 108 if VERBOSE: |
| 101 short_output = ' '.join(thr.stdout.splitlines()) | 109 short_output = ' '.join(thr.stdout.splitlines()) |
| 102 short_output = short_output.strip(' \t\n\r') | 110 short_output = short_output.strip(' \t\n\r') |
| 103 print '[DEBUG] Output: %d, %-60s' % (thr.status, short_output) | 111 print >> sys.stderr, ( |
| 112 '[DEBUG] Output: %d, %-60s' % (thr.status, short_output)) |
| 104 | 113 |
| 105 return (thr.status, thr.stdout) | 114 return (thr.status, thr.stdout) |
| 106 | 115 |
| 107 | 116 |
| 108 def Git(git_repo, command, is_mirror=False, out_buffer=None): | 117 def Git(git_repo, command, is_mirror=False, out_buffer=None): |
| 109 """Execute a git command within a local git repo.""" | 118 """Execute a git command within a local git repo.""" |
| 110 if is_mirror: | 119 if is_mirror: |
| 111 if git_repo: | 120 if git_repo: |
| 112 cmd = 'git --git-dir=%s %s' % (git_repo, command) | 121 cmd = 'git --git-dir=%s %s' % (git_repo, command) |
| 113 else: | 122 else: |
| 114 cmd = 'git %s' % command | 123 cmd = 'git %s' % command |
| 115 cwd = None | 124 cwd = None |
| 116 else: | 125 else: |
| 117 cmd = 'git %s' % command | 126 cmd = 'git %s' % command |
| 118 cwd = git_repo | 127 cwd = git_repo |
| 119 (status, output) = GetStatusOutput(cmd, cwd, out_buffer) | 128 (status, output) = GetStatusOutput(cmd, cwd, out_buffer) |
| 120 # For Abnormal Exit, Windows returns -1, Posix returns 128. | 129 # For Abnormal Exit, Windows returns -1, Posix returns 128. |
| 121 if status in [-1, 128]: | 130 if status in [-1, 128]: |
| 122 raise AbnormalExit('Failed to run %s. Exited Abnormally. output %s' % | 131 raise AbnormalExit('Failed to run %s. Exited Abnormally. output %s' % |
| 123 (cmd, output)) | 132 (cmd, output)) |
| 124 elif status != 0: | 133 elif status != 0: |
| 125 raise Exception('Failed to run %s. error %d. output %s' % (cmd, status, | 134 raise Exception('Failed to run %s. error %d. output %s' % (cmd, status, |
| 126 output)) | 135 output)) |
| 127 return (status, output) | 136 return (status, output) |
| 128 | 137 |
| 129 | 138 |
| 130 def GetCacheRepoDir(git_url, cache_dir): | 139 def Clone(git_url, git_repo, is_mirror, out_buffer=None): |
| 131 """Assuming we used git_cache to populate a cache, get the repo directory.""" | |
| 132 _, out = Git(None, 'cache exists --cache-dir=%s %s' % (cache_dir, git_url), | |
| 133 is_mirror=True) | |
| 134 return out.strip() | |
| 135 | |
| 136 | |
| 137 def Clone(git_url, git_repo, is_mirror, out_queue=None, cache_dir=None, | |
| 138 shallow=False): | |
| 139 """Clone a repository.""" | 140 """Clone a repository.""" |
| 140 repo_name = git_url.split('/')[-1] | |
| 141 if out_queue: | |
| 142 buf = StdioBuffer(repo_name, out_queue) | |
| 143 else: | |
| 144 buf = None | |
| 145 | |
| 146 if is_mirror == 'bare': | |
| 147 if shallow: | |
| 148 if 'adobe' in git_url: | |
| 149 # --shallow by default checks out 10000 revision, but for really large | |
| 150 # repos like adobe ones, we want significantly less than 10000. | |
| 151 shallow_arg = '--depth 10 ' | |
| 152 else: | |
| 153 shallow_arg = '--shallow ' | |
| 154 else: | |
| 155 shallow_arg = '' | |
| 156 cmd = 'cache populate -v --cache-dir %s %s%s' % (cache_dir, shallow_arg, | |
| 157 git_url) | |
| 158 return Git(None, cmd, is_mirror=True, out_buffer=buf) | |
| 159 | |
| 160 cmd = 'clone' | 141 cmd = 'clone' |
| 161 if is_mirror: | 142 if is_mirror: |
| 162 cmd += ' --mirror' | 143 cmd += ' --mirror' |
| 163 cmd += ' %s %s' % (git_url, git_repo) | 144 cmd += ' %s %s' % (git_url, git_repo) |
| 164 | 145 |
| 165 if not is_mirror and not os.path.exists(git_repo): | 146 if not is_mirror and not os.path.exists(git_repo): |
| 166 os.makedirs(git_repo) | 147 os.makedirs(git_repo) |
| 167 | 148 |
| 168 return Git(None, cmd, is_mirror, buf) | 149 return Git(None, cmd, is_mirror=is_mirror, out_buffer=out_buffer) |
| 150 |
| 151 |
| 152 def PopulateCache(git_url, shallow=False): |
| 153 # --shallow by default checks out 10000 revision, but for really large |
| 154 # repos like adobe ones, we want significantly less than 10000. |
| 155 depth = None |
| 156 if shallow and 'adobe' in git_url: |
| 157 depth = 10 |
| 158 mirror = git_cache.Mirror(git_url, print_func=lambda *args: None) |
| 159 mirror.populate(depth=depth, shallow=shallow) |
| 160 return mirror.mirror_path |
| 169 | 161 |
| 170 | 162 |
| 171 def Fetch(git_repo, git_url, is_mirror): | 163 def Fetch(git_repo, git_url, is_mirror): |
| 172 """Fetch the latest objects for a given git repository.""" | 164 """Fetch the latest objects for a given git repository.""" |
| 173 # Always update the upstream url | 165 # Always update the upstream url |
| 174 Git(git_repo, 'config remote.origin.url %s' % git_url) | 166 Git(git_repo, 'config remote.origin.url %s' % git_url) |
| 175 Git(git_repo, 'fetch origin', is_mirror) | 167 Git(git_repo, 'fetch origin', is_mirror) |
| 176 | 168 |
| 177 | 169 |
| 178 def Ping(git_repo, verbose=False): | 170 def Ping(git_repo, verbose=False): |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 | 260 |
| 269 # Check if svn_rev is newer than the current refspec revision. | 261 # Check if svn_rev is newer than the current refspec revision. |
| 270 try: | 262 try: |
| 271 found_rev = _FindRevForCommitish(git_repo, refspec, is_mirror) | 263 found_rev = _FindRevForCommitish(git_repo, refspec, is_mirror) |
| 272 # Sometimes this fails because it's looking in a branch that hasn't been | 264 # Sometimes this fails because it's looking in a branch that hasn't been |
| 273 # fetched from upstream yet. Let it fetch and try again. | 265 # fetched from upstream yet. Let it fetch and try again. |
| 274 except AbnormalExit: | 266 except AbnormalExit: |
| 275 found_rev = None | 267 found_rev = None |
| 276 if (not found_rev or found_rev < int(svn_rev)) and fetch_url: | 268 if (not found_rev or found_rev < int(svn_rev)) and fetch_url: |
| 277 if VERBOSE: | 269 if VERBOSE: |
| 278 print 'Fetching %s %s [%s < %s]' % (git_repo, refspec, found_rev, svn_rev) | 270 print >> sys.stderr, ( |
| 271 'Fetching %s %s [%s < %s]' % (git_repo, refspec, found_rev, svn_rev)) |
| 279 Fetch(git_repo, fetch_url, is_mirror) | 272 Fetch(git_repo, fetch_url, is_mirror) |
| 280 found_rev = _FindRevForCommitish(git_repo, refspec, is_mirror) | 273 found_rev = _FindRevForCommitish(git_repo, refspec, is_mirror) |
| 281 | 274 |
| 282 # Find the first commit matching the given git-svn-id regex. | 275 # Find the first commit matching the given git-svn-id regex. |
| 283 _, output = Git( | 276 _, output = Git( |
| 284 git_repo, | 277 git_repo, |
| 285 ('log -E --grep="^git-svn-id: [^@]*@%s [A-Za-z0-9-]*$" ' | 278 ('log -E --grep="^git-svn-id: [^@]*@%s [A-Za-z0-9-]*$" ' |
| 286 '-1 --format="%%H" %s') % (regex, refspec), | 279 '-1 --format="%%H" %s') % (regex, refspec), |
| 287 is_mirror) | 280 is_mirror) |
| 288 output = output.strip() | 281 output = output.strip() |
| 289 if not re.match('^[0-9a-fA-F]{40}$', output): | 282 if not re.match('^[0-9a-fA-F]{40}$', output): |
| 290 raise SearchError('Cannot find revision %s in %s:%s' % (svn_rev, git_repo, | 283 raise SearchError('Cannot find revision %s in %s:%s' % (svn_rev, git_repo, |
| 291 refspec)) | 284 refspec)) |
| 292 | 285 |
| 293 # Check if it actually matched the svn_rev that was requested. | 286 # Check if it actually matched the svn_rev that was requested. |
| 294 found_rev = _FindRevForCommitish(git_repo, output, is_mirror) | 287 found_rev = _FindRevForCommitish(git_repo, output, is_mirror) |
| 295 found_msg = svn_rev | 288 found_msg = svn_rev |
| 296 if found_rev != int(svn_rev): | 289 if found_rev != int(svn_rev): |
| 297 found_msg = '%s [actual: %s]' % (svn_rev, found_rev) | 290 found_msg = '%s [actual: %s]' % (svn_rev, found_rev) |
| 298 print '%s: %s <-> %s' % (git_repo, output, found_msg) | 291 print >> sys.stderr, '%s: %s <-> %s' % (git_repo, output, found_msg) |
| 299 return output | 292 return output |
| 300 | 293 |
| 301 | 294 |
| 302 def SearchExact(git_repo, svn_rev, is_mirror, refspec='FETCH_HEAD', | 295 def SearchExact(git_repo, svn_rev, is_mirror, refspec='FETCH_HEAD', |
| 303 fetch_url=None): | 296 fetch_url=None): |
| 304 """Return the Git commit id exactly matching the given SVN revision. | 297 """Return the Git commit id exactly matching the given SVN revision. |
| 305 | 298 |
| 306 If fetch_url is not None, will update repo if revision is newer.""" | 299 If fetch_url is not None, will update repo if revision is newer.""" |
| 307 regex = str(svn_rev) | 300 regex = str(svn_rev) |
| 308 return _SearchImpl(git_repo, svn_rev, is_mirror, refspec, fetch_url, regex) | 301 return _SearchImpl(git_repo, svn_rev, is_mirror, refspec, fetch_url, regex) |
| 309 | 302 |
| 310 | 303 |
| 311 def Search(git_repo, svn_rev, is_mirror, refspec='FETCH_HEAD', fetch_url=None): | 304 def Search(git_repo, svn_rev, is_mirror, refspec='FETCH_HEAD', fetch_url=None): |
| 312 """Return the Git commit id fuzzy matching the given SVN revision. | 305 """Return the Git commit id fuzzy matching the given SVN revision. |
| 313 | 306 |
| 314 If fetch_url is not None, will update repo if revision is newer.""" | 307 If fetch_url is not None, will update repo if revision is newer.""" |
| 315 regex = CreateLessThanOrEqualRegex(svn_rev) | 308 regex = CreateLessThanOrEqualRegex(svn_rev) |
| 316 return _SearchImpl(git_repo, svn_rev, is_mirror, refspec, fetch_url, regex) | 309 return _SearchImpl(git_repo, svn_rev, is_mirror, refspec, fetch_url, regex) |
| OLD | NEW |