Index: deps2git.py |
diff --git a/deps2git.py b/deps2git.py |
index f29e67c989715d640c65a38bb97abe9fcceba76a..2f64ba62fcb0fe1f4bdd33bf170bf95685abbfc6 100755 |
--- a/deps2git.py |
+++ b/deps2git.py |
@@ -6,6 +6,7 @@ |
"""Convert SVN based DEPS into .DEPS.git for use with NewGit.""" |
import collections |
+from cStringIO import StringIO |
import json |
import optparse |
import os |
@@ -13,14 +14,29 @@ import Queue |
import shutil |
import subprocess |
import sys |
+import threading |
import time |
-from multiprocessing.pool import ThreadPool |
- |
import deps_utils |
import git_tools |
import svn_to_git_public |
+try: |
+ import git_cache |
+except ImportError: |
+ for p in os.environ['PATH'].split(os.pathsep): |
+ if (os.path.basename(p) == 'depot_tools' and |
+ os.path.exists(os.path.join(p, 'git_cache.py'))): |
+ sys.path.append(p) |
+ import git_cache |
+ |
+Job = collections.namedtuple( |
+ 'Job', |
+ ['dep', 'git_url', 'dep_url', 'path', 'git_host', 'dep_rev', 'svn_branch']) |
+ |
+ConversionResults = collections.namedtuple( |
+ 'ConversionResults', |
+ ['new_deps', 'deps_vars', 'bad_git_urls', 'bad_dep_urls', 'bad_git_hash']) |
# This is copied from depot_tools/gclient.py |
DEPS_OS_CHOICES = { |
@@ -36,6 +52,7 @@ DEPS_OS_CHOICES = { |
"android": "android", |
} |
+ |
def SplitScmUrl(url): |
"""Given a repository, return a set containing the URL and the revision.""" |
url_split = url.split('@') |
@@ -46,14 +63,15 @@ def SplitScmUrl(url): |
return (scm_url, scm_rev) |
-def SvnRevToGitHash(svn_rev, git_url, repos_path, workspace, dep_path, |
- git_host, svn_branch_name=None, cache_dir=None): |
+def SvnRevToGitHash( |
+ svn_rev, git_url, repos_path, workspace, dep_path, git_host, |
+ svn_branch_name=None, cache_dir=None, outbuf=None, shallow=None): |
"""Convert a SVN revision to a Git commit id.""" |
git_repo = None |
if git_url.startswith(git_host): |
git_repo = git_url.replace(git_host, '') |
else: |
- raise Exception('Unknown git server %s, host %s' % (git_url, git_host)) |
+ raise RuntimeError('Unknown git server %s, host %s' % (git_url, git_host)) |
if repos_path is None and workspace is None and cache_dir is None: |
# We're running without a repository directory (i.e. no -r option). |
# We cannot actually find the commit id, but this mode is useful |
@@ -64,11 +82,10 @@ def SvnRevToGitHash(svn_rev, git_url, repos_path, workspace, dep_path, |
mirror = True |
git_repo_path = os.path.join(repos_path, git_repo) |
if not os.path.exists(git_repo_path) or not os.listdir(git_repo_path): |
- git_tools.Clone(git_url, git_repo_path, mirror) |
+ git_tools.Clone(git_url, git_repo_path, mirror, outbuf) |
elif cache_dir: |
- mirror = 'bare' |
- git_tools.Clone(git_url, None, mirror, cache_dir=cache_dir) |
- git_repo_path = git_tools.GetCacheRepoDir(git_url, cache_dir) |
+ mirror = True |
+ git_repo_path = git_tools.PopulateCache(git_url, shallow) |
else: |
mirror = False |
git_repo_path = os.path.join(workspace, dep_path) |
@@ -84,7 +101,7 @@ def SvnRevToGitHash(svn_rev, git_url, repos_path, workspace, dep_path, |
else: |
shutil.rmtree(git_repo_path) |
if not os.path.exists(git_repo_path): |
- git_tools.Clone(git_url, git_repo_path, mirror) |
+ git_tools.Clone(git_url, git_repo_path, mirror, outbuf) |
if svn_branch_name: |
# svn branches are mirrored with: |
@@ -102,110 +119,59 @@ def SvnRevToGitHash(svn_rev, git_url, repos_path, workspace, dep_path, |
# Work-around for: |
# http://code.google.com/p/chromium/issues/detail?id=362222 |
if (git_url.startswith('https://chromium.googlesource.com/external/pefile') |
- and int(svn_rev) == 63): |
+ and int(svn_rev) in (63, 141)): |
return '1ceaa279daa62b71e3431e58f68be6a96dd1519a' |
- try: |
- return git_tools.Search(git_repo_path, svn_rev, mirror, refspec, git_url) |
- except Exception: |
- print >> sys.stderr, '%s <-> ERROR' % git_repo_path |
- raise |
+ return git_tools.Search(git_repo_path, svn_rev, mirror, refspec, git_url) |
-def ConvertDepsToGit(deps, options, deps_vars, svn_to_git_objs): |
- """Convert a 'deps' section in a DEPS file from SVN to Git.""" |
- new_deps = {} |
- bad_git_urls = set([]) |
- bad_dep_urls = [] |
- bad_override = [] |
- bad_git_hash = [] |
- # Populate our deps list. |
- deps_to_process = {} |
- for dep, dep_url in deps.iteritems(): |
- if not dep_url: # dep is 'None' and emitted to exclude the dep |
- new_deps[dep] = None |
+def MessageMain(message_q, threads): |
+ while True: |
+ try: |
+ msg = message_q.get(True, 10) |
+ except Queue.Empty: |
+ print >> sys.stderr, 'Still working on:' |
+ for s in sorted([th.working_on for th in threads if th.working_on]): |
+ print >> sys.stderr, ' %s' % s |
continue |
+ if msg is Queue.Empty: |
+ return |
+ if msg: |
+ print >> sys.stderr, msg |
- # Get the URL and the revision/hash for this dependency. |
- dep_url, dep_rev = SplitScmUrl(deps[dep]) |
- |
- path = dep |
- git_url = dep_url |
- svn_branch = None |
- git_host = dep_url |
- |
- if not dep_url.endswith('.git'): |
- # Convert this SVN URL to a Git URL. |
- for svn_git_converter in svn_to_git_objs: |
- converted_data = svn_git_converter.SvnUrlToGitUrl(dep, dep_url) |
- if converted_data: |
- path, git_url, git_host = converted_data[:3] |
- if len(converted_data) > 3: |
- svn_branch = converted_data[3] |
- break |
- else: |
- # Make all match failures fatal to catch errors early. When a match is |
- # found, we break out of the loop so the exception is not thrown. |
- if options.no_fail_fast: |
- bad_dep_urls.append(dep_url) |
- continue |
- raise Exception('No match found for %s' % dep_url) |
- |
- Job = collections.namedtuple('Job', ['git_url', 'dep_url', 'path', |
- 'git_host', 'dep_rev', 'svn_branch']) |
- deps_to_process[dep] = Job( |
- git_url, dep_url, path, git_host, dep_rev, svn_branch) |
- # Lets pre-cache all of the git repos now if we have cache_dir turned on. |
- if options.cache_dir: |
- if not os.path.isdir(options.cache_dir): |
- os.makedirs(options.cache_dir) |
- pool = ThreadPool(processes=len(deps_to_process)) |
- output_queue = Queue.Queue() |
- num_threads = 0 |
- for git_url, _, _, _, _, _ in deps_to_process.itervalues(): |
- print 'Populating cache for %s' % git_url |
- num_threads += 1 |
- pool.apply_async(git_tools.Clone, (git_url, None, 'bare', |
- output_queue, options.cache_dir, |
- options.shallow)) |
- pool.close() |
- |
- # Stream stdout line by line. |
- sec_since = 0 |
- while num_threads > 0: |
- try: |
- line = output_queue.get(block=True, timeout=1) |
- sec_since = 0 |
- except Queue.Empty: |
- sec_since += 1 |
- line = ('Main> Heartbeat ping. We are still alive!! ' |
- 'Seconds since last output: %d sec' % sec_since) |
- if line is None: |
- num_threads -= 1 |
- else: |
- print line |
- pool.join() |
+def ConvertDepMain(dep_q, message_q, options, results): |
+ cur_thread = threading.current_thread() |
+ while True: |
+ try: |
+ job = dep_q.get(False) |
+ dep, git_url, dep_url, path, git_host, dep_rev, svn_branch = job |
+ cur_thread.working_on = dep |
+ except Queue.Empty: |
+ cur_thread.working_on = None |
+ return |
+ |
+ outbuf = StringIO() |
+ def _print(s): |
+ for l in s.splitlines(): |
+ outbuf.write('[%s] %s\n' % (dep, l)) |
- for dep, items in deps_to_process.iteritems(): |
- git_url, dep_url, path, git_host, dep_rev, svn_branch = items |
if options.verify: |
delay = 0.5 |
success = False |
for try_index in range(1, 6): |
- print >> sys.stderr, 'checking %s (try #%d) ...' % (git_url, try_index), |
+ _print('checking %s (try #%d) ...' % (git_url, try_index)) |
if git_tools.Ping(git_url, verbose=True): |
- print >> sys.stderr, ' success' |
+ _print(' success') |
success = True |
break |
- |
- print >> sys.stderr, ' failure' |
- print >> sys.stderr, 'sleeping for %.01f seconds ...' % delay |
+ _print(' failure') |
+ _print('sleeping for %.01f seconds ...' % delay) |
time.sleep(delay) |
delay *= 2 |
if not success: |
- bad_git_urls.update([git_url]) |
+ results.bad_git_urls.add(git_url) |
# Get the Git hash based off the SVN rev. |
git_hash = '' |
@@ -221,13 +187,13 @@ def ConvertDepsToGit(deps, options, deps_vars, svn_to_git_objs): |
git_host, svn_branch, options.cache_dir) |
except Exception as e: |
if options.no_fail_fast: |
- bad_git_hash.append(e) |
+ results.bad_git_hash.append(e) |
continue |
raise |
# If this is webkit, we need to add the var for the hash. |
if dep == 'src/third_party/WebKit' and dep_rev: |
- deps_vars['webkit_rev'] = git_hash |
+ results.deps_vars['webkit_rev'] = git_hash |
git_hash = 'VAR_WEBKIT_REV' |
# Hack to preserve the angle_revision variable in .DEPS.git. |
@@ -235,13 +201,78 @@ def ConvertDepsToGit(deps, options, deps_vars, svn_to_git_objs): |
if dep == 'src/third_party/angle' and git_hash: |
# Cut the leading '@' so this variable has the same semantics in |
# DEPS and .DEPS.git. |
- deps_vars['angle_revision'] = git_hash[1:] |
+ results.deps_vars['angle_revision'] = git_hash[1:] |
git_hash = 'VAR_ANGLE_REVISION' |
# Add this Git dep to the new deps. |
- new_deps[path] = '%s%s' % (git_url, git_hash) |
+ results.new_deps[path] = '%s%s' % (git_url, git_hash) |
- return new_deps, bad_git_urls, bad_dep_urls, bad_override, bad_git_hash |
+ message_q.put(outbuf.getvalue()) |
+ |
+ |
+def ConvertDepsToGit(deps, options, deps_vars, svn_to_git_objs): |
+ """Convert a 'deps' section in a DEPS file from SVN to Git.""" |
+ results = ConversionResults( |
+ new_deps={}, |
+ deps_vars=deps_vars, |
+ bad_git_urls=set([]), |
+ bad_dep_urls=[], |
+ bad_git_hash=[] |
+ ) |
+ |
+ # Populate our deps list. |
+ deps_to_process = Queue.Queue() |
+ for dep, dep_url in deps.iteritems(): |
+ if not dep_url: # dep is 'None' and emitted to exclude the dep |
+ results.new_deps[dep] = None |
+ continue |
+ |
+ # Get the URL and the revision/hash for this dependency. |
+ dep_url, dep_rev = SplitScmUrl(deps[dep]) |
+ |
+ path = dep |
+ git_url = dep_url |
+ svn_branch = None |
+ git_host = dep_url |
+ |
+ if not dep_url.endswith('.git'): |
+ # Convert this SVN URL to a Git URL. |
+ for svn_git_converter in svn_to_git_objs: |
+ converted_data = svn_git_converter.SvnUrlToGitUrl(dep, dep_url) |
+ if converted_data: |
+ path, git_url, git_host = converted_data[:3] |
+ if len(converted_data) > 3: |
+ svn_branch = converted_data[3] |
+ break |
+ else: |
+ # Make all match failures fatal to catch errors early. When a match is |
+ # found, we break out of the loop so the exception is not thrown. |
+ if options.no_fail_fast: |
+ results.bad_dep_urls.append(dep_url) |
+ continue |
+ raise RuntimeError('No match found for %s' % dep_url) |
+ |
+ deps_to_process.put( |
+ Job(dep, git_url, dep_url, path, git_host, dep_rev, svn_branch)) |
+ |
+ threads = [] |
+ message_q = Queue.Queue() |
+ thread_args = (deps_to_process, message_q, options, results) |
+ num_threads = options.num_threads or deps_to_process.qsize() |
+ for _ in xrange(num_threads): |
+ th = threading.Thread(target=ConvertDepMain, args=thread_args) |
+ th.working_on = None |
+ th.start() |
+ threads.append(th) |
+ message_th = threading.Thread(target=MessageMain, args=(message_q, threads)) |
+ message_th.start() |
+ |
+ for th in threads: |
+ th.join() |
+ message_q.put(Queue.Empty) |
+ message_th.join() |
+ |
+ return results |
def main(): |
@@ -250,6 +281,8 @@ def main(): |
help='path to the DEPS file to convert') |
parser.add_option('-o', '--out', |
help='path to the converted DEPS file (default: stdout)') |
+ parser.add_option('-j', '--num-threads', type='int', default=4, |
+ help='Maximum number of threads') |
parser.add_option('-t', '--type', |
help='[DEPRECATED] type of DEPS file (public, etc)') |
parser.add_option('-x', '--extra-rules', |
@@ -290,7 +323,7 @@ def main(): |
options.cache_dir = os.path.abspath(options.cache_dir) |
if options.extra_rules and not os.path.exists(options.extra_rules): |
- raise Exception('Can\'t locate rules file "%s".' % options.extra_rules) |
+ raise RuntimeError('Can\'t locate rules file "%s".' % options.extra_rules) |
# Create a var containing the Git and Webkit URL, this will make it easy for |
# people to use a mirror instead. |
@@ -332,6 +365,14 @@ def main(): |
if not options.cache_dir and 'cache_dir' in gclient_dict: |
options.cache_dir = os.path.abspath(gclient_dict['cache_dir']) |
+ if options.cache_dir: |
+ git_cache.Mirror.SetCachePath(options.cache_dir) |
+ else: |
+ try: |
+ options.cache_dir = git_cache.Mirror.GetCachePath() |
+ except RuntimeError: |
+ pass |
+ |
# Do general pre-processing of the DEPS data. |
for svn_git_converter in svn_to_git_objs: |
if hasattr(svn_git_converter, 'CleanDeps'): |
@@ -339,44 +380,39 @@ def main(): |
skip_child_includes, hooks) |
# Convert the DEPS file to Git. |
- deps, baddeps, badmaps, badvars, badhashes = ConvertDepsToGit( |
+ results = ConvertDepsToGit( |
deps, options, deps_vars, svn_to_git_objs) |
for os_dep in deps_os: |
- result = ConvertDepsToGit(deps_os[os_dep], options, deps_vars, |
- svn_to_git_objs) |
- deps_os[os_dep] = result[0] |
- baddeps = baddeps.union(result[1]) |
- badmaps.extend(result[2]) |
- badvars.extend(result[3]) |
- badhashes.extend(result[4]) |
+ os_results = ConvertDepsToGit(deps_os[os_dep], options, deps_vars, |
+ svn_to_git_objs) |
+ deps_os[os_dep] = os_results.new_deps |
+ results.bad_git_urls.update(os_results.bad_git_urls) |
+ results.bad_dep_urls.extend(os_results.bad_dep_urls) |
+ results.bad_git_hash.extend(os_results.bad_git_hash) |
if options.json: |
with open(options.json, 'w') as f: |
- json.dump(list(baddeps), f, sort_keys=True, indent=2) |
+ json.dump(list(results.bad_git_urls), f, sort_keys=True, indent=2) |
- if baddeps: |
+ if results.bad_git_urls: |
print >> sys.stderr, ('\nUnable to resolve the following repositories. ' |
'Please make sure\nthat any svn URLs have a git mirror associated with ' |
'them.\nTo see the exact error, run `git ls-remote [repository]` where' |
'\n[repository] is the URL ending in .git (strip off the @revision\n' |
'number.) For more information, visit http://code.google.com\n' |
'/p/chromium/wiki/UsingGit#Adding_new_repositories_to_DEPS.\n') |
- for dep in baddeps: |
+ for dep in results.bad_git_urls: |
print >> sys.stderr, ' ' + dep |
- if badmaps: |
+ if results.bad_dep_urls: |
print >> sys.stderr, '\nNo mappings found for the following urls:\n' |
- for bad in badmaps: |
- print >> sys.stderr, ' ' + bad |
- if badvars: |
- print >> sys.stderr, '\nMissing DEPS variables for overrides:\n' |
- for bad in badvars: |
+ for bad in results.bad_dep_urls: |
print >> sys.stderr, ' ' + bad |
- if badhashes: |
+ if results.bad_git_hash: |
print >> sys.stderr, '\nsvn rev to git hash failures:\n' |
- for bad in badhashes: |
+ for bad in results.bad_git_hash: |
print >> sys.stderr, ' ' + str(bad) |
- if baddeps or badmaps or badvars or badhashes: |
+ if (results.bad_git_urls or results.bad_dep_urls or results.bad_git_hash): |
return 2 |
if options.verify: |
@@ -385,8 +421,8 @@ def main(): |
return 0 |
# Write the DEPS file to disk. |
- deps_utils.WriteDeps(options.out, deps_vars, deps, deps_os, include_rules, |
- skip_child_includes, hooks) |
+ deps_utils.WriteDeps(options.out, deps_vars, results.new_deps, deps_os, |
+ include_rules, skip_child_includes, hooks) |
return 0 |