Commit 51919774 authored by maruel@chromium.org's avatar maruel@chromium.org

Make prepare() accept a revision argument.

R=dpranke@chromium.org
TEST=few
BUG=

Review URL: http://codereview.chromium.org/6995115

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@88779 0039d316-1c4b-4281-b951-d872f2087c98
parent 6ed8b50b
...@@ -80,11 +80,14 @@ class CheckoutBase(object): ...@@ -80,11 +80,14 @@ class CheckoutBase(object):
def get_settings(self, key): def get_settings(self, key):
return get_code_review_setting(self.project_path, key) return get_code_review_setting(self.project_path, key)
def prepare(self): def prepare(self, revision):
"""Checks out a clean copy of the tree and removes any local modification. """Checks out a clean copy of the tree and removes any local modification.
This function shouldn't throw unless the remote repository is inaccessible, This function shouldn't throw unless the remote repository is inaccessible,
there is no free disk space or hard issues like that. there is no free disk space or hard issues like that.
Args:
revision: The revision it should sync to, SCM specific.
""" """
raise NotImplementedError() raise NotImplementedError()
...@@ -109,7 +112,7 @@ class RawCheckout(CheckoutBase): ...@@ -109,7 +112,7 @@ class RawCheckout(CheckoutBase):
To be used by the try server. To be used by the try server.
""" """
def prepare(self): def prepare(self, revision):
"""Stubbed out.""" """Stubbed out."""
pass pass
...@@ -244,17 +247,13 @@ class SvnCheckout(CheckoutBase, SvnMixIn): ...@@ -244,17 +247,13 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
self.svn_url = svn_url self.svn_url = svn_url
assert bool(self.commit_user) >= bool(self.commit_pwd) assert bool(self.commit_user) >= bool(self.commit_pwd)
def prepare(self): def prepare(self, revision):
# Will checkout if the directory is not present. # Will checkout if the directory is not present.
assert self.svn_url assert self.svn_url
if not os.path.isdir(self.project_path): if not os.path.isdir(self.project_path):
logging.info('Checking out %s in %s' % logging.info('Checking out %s in %s' %
(self.project_name, self.project_path)) (self.project_name, self.project_path))
revision = self._revert() return self._revert(revision)
if revision != self._last_seen_revision:
logging.info('Updated at revision %d' % revision)
self._last_seen_revision = revision
return revision
def apply_patch(self, patches): def apply_patch(self, patches):
for p in patches: for p in patches:
...@@ -351,11 +350,13 @@ class SvnCheckout(CheckoutBase, SvnMixIn): ...@@ -351,11 +350,13 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
'Couldn\'t make sense out of svn commit message:\n' + out) 'Couldn\'t make sense out of svn commit message:\n' + out)
return int(match.group(1)) return int(match.group(1))
def _revert(self): def _revert(self, revision):
"""Reverts local modifications or checks out if the directory is not """Reverts local modifications or checks out if the directory is not
present. Use depot_tools's functionality to do this. present. Use depot_tools's functionality to do this.
""" """
flags = ['--ignore-externals'] flags = ['--ignore-externals']
if revision:
flags.extend(['--revision', str(revision)])
if not os.path.isdir(self.project_path): if not os.path.isdir(self.project_path):
logging.info( logging.info(
'Directory %s is not present, checking it out.' % self.project_path) 'Directory %s is not present, checking it out.' % self.project_path)
...@@ -365,9 +366,15 @@ class SvnCheckout(CheckoutBase, SvnMixIn): ...@@ -365,9 +366,15 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
scm.SVN.Revert(self.project_path) scm.SVN.Revert(self.project_path)
# Revive files that were deleted in scm.SVN.Revert(). # Revive files that were deleted in scm.SVN.Revert().
self._check_call_svn(['update', '--force'] + flags) self._check_call_svn(['update', '--force'] + flags)
return self._get_revision()
def _get_revision(self):
out = self._check_output_svn(['info', '.']) out = self._check_output_svn(['info', '.'])
return int(self._parse_svn_info(out, 'revision')) revision = int(self._parse_svn_info(out, 'revision'))
if revision != self._last_seen_revision:
logging.info('Updated to revision %d' % revision)
self._last_seen_revision = revision
return revision
class GitCheckoutBase(CheckoutBase): class GitCheckoutBase(CheckoutBase):
...@@ -381,7 +388,7 @@ class GitCheckoutBase(CheckoutBase): ...@@ -381,7 +388,7 @@ class GitCheckoutBase(CheckoutBase):
self.remote_branch = remote_branch self.remote_branch = remote_branch
self.working_branch = 'working_branch' self.working_branch = 'working_branch'
def prepare(self): def prepare(self, revision):
"""Resets the git repository in a clean state. """Resets the git repository in a clean state.
Checks it out if not present and deletes the working branch. Checks it out if not present and deletes the working branch.
...@@ -389,12 +396,21 @@ class GitCheckoutBase(CheckoutBase): ...@@ -389,12 +396,21 @@ class GitCheckoutBase(CheckoutBase):
assert self.remote_branch assert self.remote_branch
assert os.path.isdir(self.project_path) assert os.path.isdir(self.project_path)
self._check_call_git(['reset', '--hard', '--quiet']) self._check_call_git(['reset', '--hard', '--quiet'])
branches, active = self._branches() if revision:
if active != 'master': try:
self._check_call_git(['checkout', 'master', '--force', '--quiet']) revision = self._check_output_git(['rev-parse', revision])
self._check_call_git(['pull', self.remote, self.remote_branch, '--quiet']) except subprocess.CalledProcessError:
if self.working_branch in branches: self._check_call_git(
self._call_git(['branch', '-D', self.working_branch]) ['fetch', self.remote, self.remote_branch, '--quiet'])
revision = self._check_output_git(['rev-parse', revision])
self._check_call_git(['checkout', '--force', '--quiet', revision])
else:
branches, active = self._branches()
if active != 'master':
self._check_call_git(['checkout', '--force', '--quiet', 'master'])
self._check_call_git(['pull', self.remote, self.remote_branch, '--quiet'])
if self.working_branch in branches:
self._call_git(['branch', '-D', self.working_branch])
def apply_patch(self, patches): def apply_patch(self, patches):
"""Applies a patch on 'working_branch' and switch to it. """Applies a patch on 'working_branch' and switch to it.
...@@ -510,25 +526,37 @@ class GitSvnCheckoutBase(GitCheckoutBase, SvnMixIn): ...@@ -510,25 +526,37 @@ class GitSvnCheckoutBase(GitCheckoutBase, SvnMixIn):
assert self.trunk assert self.trunk
self._cache_svn_auth() self._cache_svn_auth()
def prepare(self): def prepare(self, revision):
"""Resets the git repository in a clean state.""" """Resets the git repository in a clean state."""
self._check_call_git(['reset', '--hard', '--quiet']) self._check_call_git(['reset', '--hard', '--quiet'])
branches, active = self._branches() if revision:
if active != 'master': try:
if not 'master' in branches: revision = self._check_output_git(
['svn', 'find-rev', 'r%d' % revision])
except subprocess.CalledProcessError:
self._check_call_git( self._check_call_git(
['checkout', '--quiet', '-b', 'master', ['fetch', self.remote, self.remote_branch, '--quiet'])
'%s/%s' % (self.remote, self.remote_branch)]) revision = self._check_output_git(
else: ['svn', 'find-rev', 'r%d' % revision])
self._check_call_git(['checkout', 'master', '--force', '--quiet']) super(GitSvnCheckoutBase, self).prepare(revision)
# git svn rebase --quiet --quiet doesn't work, use two steps to silence it. else:
self._check_call_git_svn(['fetch', '--quiet', '--quiet']) branches, active = self._branches()
self._check_call_git( if active != 'master':
['rebase', '--quiet', '--quiet', if not 'master' in branches:
'%s/%s' % (self.remote, self.remote_branch)]) self._check_call_git(
if self.working_branch in branches: ['checkout', '--quiet', '-b', 'master',
self._call_git(['branch', '-D', self.working_branch]) '%s/%s' % (self.remote, self.remote_branch)])
return int(self._git_svn_info('revision')) 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): def _git_svn_info(self, key):
"""Calls git svn info. This doesn't support nor need --config-dir.""" """Calls git svn info. This doesn't support nor need --config-dir."""
...@@ -573,7 +601,7 @@ class GitSvnCheckoutBase(GitCheckoutBase, SvnMixIn): ...@@ -573,7 +601,7 @@ class GitSvnCheckoutBase(GitCheckoutBase, SvnMixIn):
def _get_revision(self): def _get_revision(self):
revision = int(self._git_svn_info('revision')) revision = int(self._git_svn_info('revision'))
if revision != self._last_seen_revision: if revision != self._last_seen_revision:
logging.info('Updated at revision %d' % revision) logging.info('Updated to revision %d' % revision)
self._last_seen_revision = revision self._last_seen_revision = revision
return revision return revision
...@@ -595,7 +623,7 @@ class GitSvnPremadeCheckout(GitSvnCheckoutBase): ...@@ -595,7 +623,7 @@ class GitSvnPremadeCheckout(GitSvnCheckoutBase):
self.git_url = git_url self.git_url = git_url
assert self.git_url assert self.git_url
def prepare(self): def prepare(self, revision):
"""Creates the initial checkout for the repo.""" """Creates the initial checkout for the repo."""
if not os.path.isdir(self.project_path): if not os.path.isdir(self.project_path):
logging.info('Checking out %s in %s' % logging.info('Checking out %s in %s' %
...@@ -619,8 +647,7 @@ class GitSvnPremadeCheckout(GitSvnCheckoutBase): ...@@ -619,8 +647,7 @@ class GitSvnPremadeCheckout(GitSvnCheckoutBase):
'-T', self.trunk, '-T', self.trunk,
self.svn_url]) self.svn_url])
self._check_call_git_svn(['fetch']) self._check_call_git_svn(['fetch'])
super(GitSvnPremadeCheckout, self).prepare() return super(GitSvnPremadeCheckout, self).prepare(revision)
return self._get_revision()
class GitSvnCheckout(GitSvnCheckoutBase): class GitSvnCheckout(GitSvnCheckoutBase):
...@@ -637,8 +664,9 @@ class GitSvnCheckout(GitSvnCheckoutBase): ...@@ -637,8 +664,9 @@ class GitSvnCheckout(GitSvnCheckoutBase):
commit_user, commit_pwd, commit_user, commit_pwd,
svn_url, trunk, post_processors) svn_url, trunk, post_processors)
def prepare(self): def prepare(self, revision):
"""Creates the initial checkout for the repo.""" """Creates the initial checkout for the repo."""
assert not revision, 'Implement revision if necessary'
if not os.path.isdir(self.project_path): if not os.path.isdir(self.project_path):
logging.info('Checking out %s in %s' % logging.info('Checking out %s in %s' %
(self.project_name, self.project_path)) (self.project_name, self.project_path))
...@@ -652,8 +680,7 @@ class GitSvnCheckout(GitSvnCheckoutBase): ...@@ -652,8 +680,7 @@ class GitSvnCheckout(GitSvnCheckoutBase):
'--quiet'], '--quiet'],
cwd=self.root_dir, cwd=self.root_dir,
stderr=subprocess2.STDOUT) stderr=subprocess2.STDOUT)
super(GitSvnCheckout, self).prepare() return super(GitSvnCheckout, self).prepare(revision)
return self._get_revision()
class ReadOnlyCheckout(object): class ReadOnlyCheckout(object):
...@@ -661,8 +688,8 @@ class ReadOnlyCheckout(object): ...@@ -661,8 +688,8 @@ class ReadOnlyCheckout(object):
def __init__(self, checkout): def __init__(self, checkout):
self.checkout = checkout self.checkout = checkout
def prepare(self): def prepare(self, revision):
return self.checkout.prepare() return self.checkout.prepare(revision)
def get_settings(self, key): def get_settings(self, key):
return self.checkout.get_settings(key) return self.checkout.get_settings(key)
......
...@@ -181,7 +181,7 @@ class BaseTest(fake_repos.FakeReposTestBase): ...@@ -181,7 +181,7 @@ class BaseTest(fake_repos.FakeReposTestBase):
self.FAKE_REPOS.svn_dirty = True self.FAKE_REPOS.svn_dirty = True
self.assertEquals(root, co.project_path) self.assertEquals(root, co.project_path)
self.assertEquals(self.previous_log['revision'], co.prepare()) self.assertEquals(self.previous_log['revision'], co.prepare(None))
self.assertEquals('pouet', co.get_settings('bar')) self.assertEquals('pouet', co.get_settings('bar'))
self.assertTree(self.get_trunk(False), root) self.assertTree(self.get_trunk(False), root)
patches = self.get_patches() patches = self.get_patches()
...@@ -206,13 +206,13 @@ class BaseTest(fake_repos.FakeReposTestBase): ...@@ -206,13 +206,13 @@ class BaseTest(fake_repos.FakeReposTestBase):
if read_only: if read_only:
self.assertEquals('FAKE', revision) self.assertEquals('FAKE', revision)
self.assertEquals(self.previous_log['revision'], co.prepare()) self.assertEquals(self.previous_log['revision'], co.prepare(None))
# Changes should be reverted now. # Changes should be reverted now.
self.assertTree(self.get_trunk(False), root) self.assertTree(self.get_trunk(False), root)
expected = self.previous_log expected = self.previous_log
else: else:
self.assertEquals(self.previous_log['revision'] + 1, revision) self.assertEquals(self.previous_log['revision'] + 1, revision)
self.assertEquals(self.previous_log['revision'] + 1, co.prepare()) self.assertEquals(self.previous_log['revision'] + 1, co.prepare(None))
self.assertTree(self.get_trunk(True), root) self.assertTree(self.get_trunk(True), root)
expected = expected.copy() expected = expected.copy()
expected['msg'] = 'msg' expected['msg'] = 'msg'
...@@ -223,7 +223,7 @@ class BaseTest(fake_repos.FakeReposTestBase): ...@@ -223,7 +223,7 @@ class BaseTest(fake_repos.FakeReposTestBase):
self.assertEquals(expected, actual) self.assertEquals(expected, actual)
def _check_exception(self, co, err_msg): def _check_exception(self, co, err_msg):
co.prepare() co.prepare(None)
try: try:
co.apply_patch([patch.FilePatchDiff('svn_utils_test.txt', BAD_PATCH, [])]) co.apply_patch([patch.FilePatchDiff('svn_utils_test.txt', BAD_PATCH, [])])
self.fail() self.fail()
...@@ -237,7 +237,7 @@ class BaseTest(fake_repos.FakeReposTestBase): ...@@ -237,7 +237,7 @@ class BaseTest(fake_repos.FakeReposTestBase):
def _test_process(self, co): def _test_process(self, co):
"""Makes sure the process lambda is called correctly.""" """Makes sure the process lambda is called correctly."""
co.post_processors = [lambda *args: results.append(args)] co.post_processors = [lambda *args: results.append(args)]
co.prepare() co.prepare(None)
ps = self.get_patches() ps = self.get_patches()
results = [] results = []
co.apply_patch(ps) co.apply_patch(ps)
...@@ -281,6 +281,9 @@ class SvnBaseTest(BaseTest): ...@@ -281,6 +281,9 @@ class SvnBaseTest(BaseTest):
data['revprops'].append((prop.attrib['name'], prop.text)) data['revprops'].append((prop.attrib['name'], prop.text))
return data return data
def _test_prepare(self, co):
self.assertEquals(1, co.prepare(1))
class SvnCheckout(SvnBaseTest): class SvnCheckout(SvnBaseTest):
def _get_co(self, read_only): def _get_co(self, read_only):
...@@ -317,7 +320,7 @@ class SvnCheckout(SvnBaseTest): ...@@ -317,7 +320,7 @@ class SvnCheckout(SvnBaseTest):
def testSvnProps(self): def testSvnProps(self):
co = self._get_co(False) co = self._get_co(False)
co.prepare() co.prepare(None)
try: try:
# svn:ignore can only be applied to directories. # svn:ignore can only be applied to directories.
svn_props = [('svn:ignore', 'foo')] svn_props = [('svn:ignore', 'foo')]
...@@ -332,7 +335,7 @@ class SvnCheckout(SvnBaseTest): ...@@ -332,7 +335,7 @@ class SvnCheckout(SvnBaseTest):
'--non-interactive;\n' '--non-interactive;\n'
'patching file svn_utils_test.txt\n' 'patching file svn_utils_test.txt\n'
'svn: Cannot set \'svn:ignore\' on a file (\'svn_utils_test.txt\')\n') 'svn: Cannot set \'svn:ignore\' on a file (\'svn_utils_test.txt\')\n')
co.prepare() co.prepare(None)
svn_props = [('svn:eol-style', 'LF'), ('foo', 'bar')] svn_props = [('svn:eol-style', 'LF'), ('foo', 'bar')]
co.apply_patch( co.apply_patch(
[patch.FilePatchDiff('svn_utils_test.txt', NAKED_PATCH, svn_props)]) [patch.FilePatchDiff('svn_utils_test.txt', NAKED_PATCH, svn_props)])
...@@ -379,7 +382,7 @@ class SvnCheckout(SvnBaseTest): ...@@ -379,7 +382,7 @@ class SvnCheckout(SvnBaseTest):
co = self._get_co(False) co = self._get_co(False)
co.svn_config = checkout.SvnConfig( co.svn_config = checkout.SvnConfig(
os.path.join(ROOT_DIR, 'subversion_config')) os.path.join(ROOT_DIR, 'subversion_config'))
co.prepare() co.prepare(None)
patches = self.get_patches() patches = self.get_patches()
co.apply_patch(patches) co.apply_patch(patches)
self.assertEquals( self.assertEquals(
...@@ -398,6 +401,13 @@ class SvnCheckout(SvnBaseTest): ...@@ -398,6 +401,13 @@ class SvnCheckout(SvnBaseTest):
self.svn_url) self.svn_url)
self._test_process(co) self._test_process(co)
def testPrepare(self):
co = checkout.SvnCheckout(
self.root_dir, self.name,
None, None,
self.svn_url)
self._test_prepare(co)
class GitSvnCheckout(SvnBaseTest): class GitSvnCheckout(SvnBaseTest):
name = 'foo.git' name = 'foo.git'
...@@ -430,7 +440,7 @@ class GitSvnCheckout(SvnBaseTest): ...@@ -430,7 +440,7 @@ class GitSvnCheckout(SvnBaseTest):
def testGitSvnPremade(self): def testGitSvnPremade(self):
# Test premade git-svn clone. First make a git-svn clone. # Test premade git-svn clone. First make a git-svn clone.
git_svn_co = self._get_co(True) git_svn_co = self._get_co(True)
revision = git_svn_co.prepare() revision = git_svn_co.prepare(None)
self.assertEquals(self.previous_log['revision'], revision) self.assertEquals(self.previous_log['revision'], revision)
# Then use GitSvnClone to clone it to lose the git-svn connection and verify # Then use GitSvnClone to clone it to lose the git-svn connection and verify
# git svn init / git svn fetch works. # git svn init / git svn fetch works.
...@@ -438,7 +448,8 @@ class GitSvnCheckout(SvnBaseTest): ...@@ -438,7 +448,8 @@ class GitSvnCheckout(SvnBaseTest):
self.root_dir, self.name[:-4] + '2', 'trunk', self.root_dir, self.name[:-4] + '2', 'trunk',
self.usr, self.pwd, self.usr, self.pwd,
self.svn_base, self.svn_trunk, git_svn_co.project_path) self.svn_base, self.svn_trunk, git_svn_co.project_path)
self.assertEquals(self.previous_log['revision'], git_svn_clone.prepare()) self.assertEquals(
self.previous_log['revision'], git_svn_clone.prepare(None))
def testException(self): def testException(self):
self._check_exception( self._check_exception(
...@@ -446,7 +457,7 @@ class GitSvnCheckout(SvnBaseTest): ...@@ -446,7 +457,7 @@ class GitSvnCheckout(SvnBaseTest):
def testSvnProps(self): def testSvnProps(self):
co = self._get_co(False) co = self._get_co(False)
co.prepare() co.prepare(None)
try: try:
svn_props = [('foo', 'bar')] svn_props = [('foo', 'bar')]
co.apply_patch( co.apply_patch(
...@@ -457,7 +468,7 @@ class GitSvnCheckout(SvnBaseTest): ...@@ -457,7 +468,7 @@ class GitSvnCheckout(SvnBaseTest):
self.assertEquals( self.assertEquals(
e.status, e.status,
'Cannot apply svn property foo to file svn_utils_test.txt.') 'Cannot apply svn property foo to file svn_utils_test.txt.')
co.prepare() co.prepare(None)
# svn:eol-style is ignored. # svn:eol-style is ignored.
svn_props = [('svn:eol-style', 'LF')] svn_props = [('svn:eol-style', 'LF')]
co.apply_patch( co.apply_patch(
...@@ -470,6 +481,13 @@ class GitSvnCheckout(SvnBaseTest): ...@@ -470,6 +481,13 @@ class GitSvnCheckout(SvnBaseTest):
self.svn_url) self.svn_url)
self._test_process(co) self._test_process(co)
def testPrepare(self):
co = checkout.SvnCheckout(
self.root_dir, self.name,
None, None,
self.svn_url)
self._test_prepare(co)
class RawCheckout(SvnBaseTest): class RawCheckout(SvnBaseTest):
def setUp(self): def setUp(self):
...@@ -477,7 +495,7 @@ class RawCheckout(SvnBaseTest): ...@@ -477,7 +495,7 @@ class RawCheckout(SvnBaseTest):
# Use a svn checkout as the base. # Use a svn checkout as the base.
self.base_co = checkout.SvnCheckout( self.base_co = checkout.SvnCheckout(
self.root_dir, self.name, None, None, self.svn_url) self.root_dir, self.name, None, None, self.svn_url)
self.base_co.prepare() self.base_co.prepare(None)
def _get_co(self, read_only): def _get_co(self, read_only):
co = checkout.RawCheckout(self.root_dir, self.name, None) co = checkout.RawCheckout(self.root_dir, self.name, None)
...@@ -491,7 +509,7 @@ class RawCheckout(SvnBaseTest): ...@@ -491,7 +509,7 @@ class RawCheckout(SvnBaseTest):
# A copy of BaseTest._check_base() # A copy of BaseTest._check_base()
self.assertEquals(root, co.project_path) self.assertEquals(root, co.project_path)
self.assertEquals(None, co.prepare()) self.assertEquals(None, co.prepare(None))
self.assertEquals('pouet', co.get_settings('bar')) self.assertEquals('pouet', co.get_settings('bar'))
self.assertTree(self.get_trunk(False), root) self.assertTree(self.get_trunk(False), root)
patches = self.get_patches() patches = self.get_patches()
...@@ -513,7 +531,7 @@ class RawCheckout(SvnBaseTest): ...@@ -513,7 +531,7 @@ class RawCheckout(SvnBaseTest):
pass pass
self.assertTree(self.get_trunk(True), root) self.assertTree(self.get_trunk(True), root)
# Verify that prepare() is a no-op. # Verify that prepare() is a no-op.
self.assertEquals(None, co.prepare()) self.assertEquals(None, co.prepare(None))
self.assertTree(self.get_trunk(True), root) self.assertTree(self.get_trunk(True), root)
def testAllRW(self): def testAllRW(self):
...@@ -537,6 +555,13 @@ class RawCheckout(SvnBaseTest): ...@@ -537,6 +555,13 @@ class RawCheckout(SvnBaseTest):
self.svn_url) self.svn_url)
self._test_process(co) self._test_process(co)
def testPrepare(self):
co = checkout.SvnCheckout(
self.root_dir, self.name,
None, None,
self.svn_url)
self._test_prepare(co)
if __name__ == '__main__': if __name__ == '__main__':
if '-v' in sys.argv: if '-v' in sys.argv:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment