|
|
|
@ -566,183 +566,6 @@ class GitCheckoutBase(CheckoutBase):
|
|
|
|
|
return branches, active
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GitSvnCheckoutBase(GitCheckoutBase, SvnMixIn):
|
|
|
|
|
"""Base class for git-svn checkout. Not to be used as-is."""
|
|
|
|
|
def __init__(self,
|
|
|
|
|
root_dir, project_name, remote_branch,
|
|
|
|
|
commit_user, commit_pwd,
|
|
|
|
|
svn_url, trunk, post_processors=None):
|
|
|
|
|
"""trunk is optional."""
|
|
|
|
|
GitCheckoutBase.__init__(
|
|
|
|
|
self, root_dir, project_name + '.git', remote_branch, post_processors)
|
|
|
|
|
SvnMixIn.__init__(self)
|
|
|
|
|
self.commit_user = commit_user
|
|
|
|
|
self.commit_pwd = commit_pwd
|
|
|
|
|
# svn_url in this case is the root of the svn repository.
|
|
|
|
|
self.svn_url = svn_url
|
|
|
|
|
self.trunk = trunk
|
|
|
|
|
assert bool(self.commit_user) >= bool(self.commit_pwd)
|
|
|
|
|
assert self.svn_url
|
|
|
|
|
assert self.trunk
|
|
|
|
|
self._cache_svn_auth()
|
|
|
|
|
|
|
|
|
|
def prepare(self, revision):
|
|
|
|
|
"""Resets the git repository in a clean state."""
|
|
|
|
|
self._check_call_git(['reset', '--hard', '--quiet'])
|
|
|
|
|
if revision:
|
|
|
|
|
try:
|
|
|
|
|
revision = self._check_output_git(
|
|
|
|
|
['svn', 'find-rev', 'r%d' % revision])
|
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
|
self._check_call_git(
|
|
|
|
|
['fetch', self.remote, self.remote_branch, '--quiet'])
|
|
|
|
|
revision = self._check_output_git(
|
|
|
|
|
['svn', 'find-rev', 'r%d' % revision])
|
|
|
|
|
super(GitSvnCheckoutBase, self).prepare(revision)
|
|
|
|
|
else:
|
|
|
|
|
branches, active = self._branches()
|
|
|
|
|
if active != 'master':
|
|
|
|
|
if not 'master' in branches:
|
|
|
|
|
self._check_call_git(
|
|
|
|
|
['checkout', '--quiet', '-b', 'master',
|
|
|
|
|
'%s/%s' % (self.remote, self.remote_branch)])
|
|
|
|
|
else:
|
|
|
|
|
self._check_call_git(['checkout', 'master', '--force', '--quiet'])
|
|
|
|
|
# git svn rebase --quiet --quiet doesn't work, use two steps to silence
|
|
|
|
|
# it.
|
|
|
|
|
self._check_call_git_svn(['fetch', '--quiet', '--quiet'])
|
|
|
|
|
self._check_call_git(
|
|
|
|
|
['rebase', '--quiet', '--quiet',
|
|
|
|
|
'%s/%s' % (self.remote, self.remote_branch)])
|
|
|
|
|
if self.working_branch in branches:
|
|
|
|
|
self._call_git(['branch', '-D', self.working_branch])
|
|
|
|
|
return self._get_revision()
|
|
|
|
|
|
|
|
|
|
def _git_svn_info(self, key):
|
|
|
|
|
"""Calls git svn info. This doesn't support nor need --config-dir."""
|
|
|
|
|
return self._parse_svn_info(self._check_output_git(['svn', 'info']), key)
|
|
|
|
|
|
|
|
|
|
def commit(self, commit_message, user):
|
|
|
|
|
"""Commits a patch."""
|
|
|
|
|
logging.info('Committing patch for %s' % user)
|
|
|
|
|
# Fix the commit message and author. It returns the git hash, which we
|
|
|
|
|
# ignore unless it's None.
|
|
|
|
|
if not super(GitSvnCheckoutBase, self).commit(commit_message, user):
|
|
|
|
|
return None
|
|
|
|
|
# TODO(maruel): git-svn ignores --config-dir as of git-svn version 1.7.4 and
|
|
|
|
|
# doesn't support --with-revprop.
|
|
|
|
|
# Either learn perl and upstream or suck it.
|
|
|
|
|
kwargs = {}
|
|
|
|
|
if self.commit_pwd:
|
|
|
|
|
kwargs['stdin'] = self.commit_pwd + '\n'
|
|
|
|
|
kwargs['stderr'] = subprocess2.STDOUT
|
|
|
|
|
self._check_call_git_svn(
|
|
|
|
|
['dcommit', '--rmdir', '--find-copies-harder',
|
|
|
|
|
'--username', self.commit_user],
|
|
|
|
|
**kwargs)
|
|
|
|
|
revision = int(self._git_svn_info('revision'))
|
|
|
|
|
return revision
|
|
|
|
|
|
|
|
|
|
def _cache_svn_auth(self):
|
|
|
|
|
"""Caches the svn credentials. It is necessary since git-svn doesn't prompt
|
|
|
|
|
for it."""
|
|
|
|
|
if not self.commit_user or not self.commit_pwd:
|
|
|
|
|
return
|
|
|
|
|
# Use capture to lower noise in logs.
|
|
|
|
|
self._check_output_svn(['ls', self.svn_url], cwd=None)
|
|
|
|
|
|
|
|
|
|
def _check_call_git_svn(self, args, **kwargs):
|
|
|
|
|
"""Handles svn authentication while calling git svn."""
|
|
|
|
|
args = ['svn'] + args
|
|
|
|
|
if not self.svn_config.default:
|
|
|
|
|
args.extend(['--config-dir', self.svn_config.svn_config_dir])
|
|
|
|
|
return self._check_call_git(args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def _get_revision(self):
|
|
|
|
|
revision = int(self._git_svn_info('revision'))
|
|
|
|
|
if revision != self._last_seen_revision:
|
|
|
|
|
logging.info('Updated to revision %d' % revision)
|
|
|
|
|
self._last_seen_revision = revision
|
|
|
|
|
return revision
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GitSvnPremadeCheckout(GitSvnCheckoutBase):
|
|
|
|
|
"""Manages a git-svn clone made out from an initial git-svn seed.
|
|
|
|
|
|
|
|
|
|
This class is very similar to GitSvnCheckout but is faster to bootstrap
|
|
|
|
|
because it starts right off with an existing git-svn clone.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self,
|
|
|
|
|
root_dir, project_name, remote_branch,
|
|
|
|
|
commit_user, commit_pwd,
|
|
|
|
|
svn_url, trunk, git_url, post_processors=None):
|
|
|
|
|
super(GitSvnPremadeCheckout, self).__init__(
|
|
|
|
|
root_dir, project_name, remote_branch,
|
|
|
|
|
commit_user, commit_pwd,
|
|
|
|
|
svn_url, trunk, post_processors)
|
|
|
|
|
self.git_url = git_url
|
|
|
|
|
assert self.git_url
|
|
|
|
|
|
|
|
|
|
def prepare(self, revision):
|
|
|
|
|
"""Creates the initial checkout for the repo."""
|
|
|
|
|
if not os.path.isdir(self.project_path):
|
|
|
|
|
logging.info('Checking out %s in %s' %
|
|
|
|
|
(self.project_name, self.project_path))
|
|
|
|
|
assert self.remote == 'origin'
|
|
|
|
|
# self.project_path doesn't exist yet.
|
|
|
|
|
self._check_call_git(
|
|
|
|
|
['clone', self.git_url, self.project_name, '--quiet'],
|
|
|
|
|
cwd=self.root_dir,
|
|
|
|
|
stderr=subprocess2.STDOUT)
|
|
|
|
|
try:
|
|
|
|
|
configured_svn_url = self._check_output_git(
|
|
|
|
|
['config', 'svn-remote.svn.url']).strip()
|
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
|
configured_svn_url = ''
|
|
|
|
|
|
|
|
|
|
if configured_svn_url.strip() != self.svn_url:
|
|
|
|
|
self._check_call_git_svn(
|
|
|
|
|
['init',
|
|
|
|
|
'--prefix', self.remote + '/',
|
|
|
|
|
'-T', self.trunk,
|
|
|
|
|
self.svn_url])
|
|
|
|
|
self._check_call_git_svn(['fetch'])
|
|
|
|
|
return super(GitSvnPremadeCheckout, self).prepare(revision)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GitSvnCheckout(GitSvnCheckoutBase):
|
|
|
|
|
"""Manages a git-svn clone.
|
|
|
|
|
|
|
|
|
|
Using git-svn hides some of the complexity of using a svn checkout.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self,
|
|
|
|
|
root_dir, project_name,
|
|
|
|
|
commit_user, commit_pwd,
|
|
|
|
|
svn_url, trunk, post_processors=None):
|
|
|
|
|
super(GitSvnCheckout, self).__init__(
|
|
|
|
|
root_dir, project_name, 'trunk',
|
|
|
|
|
commit_user, commit_pwd,
|
|
|
|
|
svn_url, trunk, post_processors)
|
|
|
|
|
|
|
|
|
|
def prepare(self, revision):
|
|
|
|
|
"""Creates the initial checkout for the repo."""
|
|
|
|
|
assert not revision, 'Implement revision if necessary'
|
|
|
|
|
if not os.path.isdir(self.project_path):
|
|
|
|
|
logging.info('Checking out %s in %s' %
|
|
|
|
|
(self.project_name, self.project_path))
|
|
|
|
|
# TODO: Create a shallow clone.
|
|
|
|
|
# self.project_path doesn't exist yet.
|
|
|
|
|
self._check_call_git_svn(
|
|
|
|
|
['clone',
|
|
|
|
|
'--prefix', self.remote + '/',
|
|
|
|
|
'-T', self.trunk,
|
|
|
|
|
self.svn_url, self.project_path,
|
|
|
|
|
'--quiet'],
|
|
|
|
|
cwd=self.root_dir,
|
|
|
|
|
stderr=subprocess2.STDOUT)
|
|
|
|
|
return super(GitSvnCheckout, self).prepare(revision)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReadOnlyCheckout(object):
|
|
|
|
|
"""Converts a checkout into a read-only one."""
|
|
|
|
|
def __init__(self, checkout, post_processors=None):
|
|
|
|
|