Add post_processors override to apply_patch() and add more testing.

Move ReadOnlyCheckout tests into its own fixture.

R=dpranke@chromium.org
BUG=
TEST=


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

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@103272 0039d316-1c4b-4281-b951-d872f2087c98
experimental/szager/collated-output
maruel@chromium.org 14 years ago
parent bda0503b54
commit b1d1a78c8d

@ -92,7 +92,7 @@ class CheckoutBase(object):
""" """
raise NotImplementedError() raise NotImplementedError()
def apply_patch(self, patches): def apply_patch(self, patches, post_processors=None):
"""Applies a patch and returns the list of modified files. """Applies a patch and returns the list of modified files.
This function should throw patch.UnsupportedPatchFormat or This function should throw patch.UnsupportedPatchFormat or
@ -117,8 +117,9 @@ class RawCheckout(CheckoutBase):
"""Stubbed out.""" """Stubbed out."""
pass pass
def apply_patch(self, patches): def apply_patch(self, patches, post_processors=None):
"""Ignores svn properties.""" """Ignores svn properties."""
post_processors = post_processors or self.post_processors or []
for p in patches: for p in patches:
try: try:
stdout = '' stdout = ''
@ -145,7 +146,7 @@ class RawCheckout(CheckoutBase):
elif p.is_new and not os.path.exists(filepath): elif p.is_new and not os.path.exists(filepath):
# There is only a header. Just create the file. # There is only a header. Just create the file.
open(filepath, 'w').close() open(filepath, 'w').close()
for post in (self.post_processors or []): for post in post_processors:
post(self, p) post(self, p)
except OSError, e: except OSError, e:
raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e))
@ -261,7 +262,8 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
(self.project_name, self.project_path)) (self.project_name, self.project_path))
return self._revert(revision) return self._revert(revision)
def apply_patch(self, patches): def apply_patch(self, patches, post_processors=None):
post_processors = post_processors or self.post_processors or []
for p in patches: for p in patches:
try: try:
# It is important to use credentials=False otherwise credentials could # It is important to use credentials=False otherwise credentials could
@ -314,7 +316,7 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
params = value.split('=', 1) params = value.split('=', 1)
stdout += self._check_output_svn( stdout += self._check_output_svn(
['propset'] + params + [p.filename], credentials=False) ['propset'] + params + [p.filename], credentials=False)
for post in (self.post_processors or []): for post in post_processors:
post(self, p) post(self, p)
except OSError, e: except OSError, e:
raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e))
@ -418,13 +420,14 @@ class GitCheckoutBase(CheckoutBase):
if self.working_branch in branches: if self.working_branch in branches:
self._call_git(['branch', '-D', self.working_branch]) self._call_git(['branch', '-D', self.working_branch])
def apply_patch(self, patches): def apply_patch(self, patches, post_processors=None):
"""Applies a patch on 'working_branch' and switch to it. """Applies a patch on 'working_branch' and switch to it.
Also commits the changes on the local branch. Also commits the changes on the local branch.
Ignores svn properties and raise an exception on unexpected ones. Ignores svn properties and raise an exception on unexpected ones.
""" """
post_processors = post_processors or self.post_processors or []
# It this throws, the checkout is corrupted. Maybe worth deleting it and # It this throws, the checkout is corrupted. Maybe worth deleting it and
# trying again? # trying again?
if self.remote_branch: if self.remote_branch:
@ -461,7 +464,7 @@ class GitCheckoutBase(CheckoutBase):
p.filename, p.filename,
'Cannot apply svn property %s to file %s.' % ( 'Cannot apply svn property %s to file %s.' % (
prop[0], p.filename)) prop[0], p.filename))
for post in (self.post_processors or []): for post in post_processors:
post(self, p) post(self, p)
except OSError, e: except OSError, e:
raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e))
@ -693,9 +696,11 @@ class GitSvnCheckout(GitSvnCheckoutBase):
class ReadOnlyCheckout(object): class ReadOnlyCheckout(object):
"""Converts a checkout into a read-only one.""" """Converts a checkout into a read-only one."""
def __init__(self, checkout): def __init__(self, checkout, post_processors=None):
super(ReadOnlyCheckout, self).__init__() super(ReadOnlyCheckout, self).__init__()
self.checkout = checkout self.checkout = checkout
self.post_processors = (post_processors or []) + (
self.checkout.post_processors or [])
def prepare(self, revision): def prepare(self, revision):
return self.checkout.prepare(revision) return self.checkout.prepare(revision)
@ -703,8 +708,9 @@ class ReadOnlyCheckout(object):
def get_settings(self, key): def get_settings(self, key):
return self.checkout.get_settings(key) return self.checkout.get_settings(key)
def apply_patch(self, patches): def apply_patch(self, patches, post_processors=None):
return self.checkout.apply_patch(patches) return self.checkout.apply_patch(
patches, post_processors or self.post_processors)
def commit(self, message, user): # pylint: disable=R0201 def commit(self, message, user): # pylint: disable=R0201
logging.info('Would have committed for %s with message: %s' % ( logging.info('Would have committed for %s with message: %s' % (

@ -77,6 +77,7 @@ class FakeRepos(fake_repos.FakeReposBase):
class BaseTest(fake_repos.FakeReposTestBase): class BaseTest(fake_repos.FakeReposTestBase):
name = 'foo' name = 'foo'
FAKE_REPOS_CLASS = FakeRepos FAKE_REPOS_CLASS = FakeRepos
is_read_only = False
def setUp(self): def setUp(self):
# Need to enforce subversion_config first. # Need to enforce subversion_config first.
@ -126,7 +127,8 @@ class BaseTest(fake_repos.FakeReposTestBase):
def _check_base(self, co, root, git, expected): def _check_base(self, co, root, git, expected):
read_only = isinstance(co, checkout.ReadOnlyCheckout) read_only = isinstance(co, checkout.ReadOnlyCheckout)
assert not read_only == bool(expected) self.assertEquals(not read_only, bool(expected))
self.assertEquals(read_only, self.is_read_only)
if not read_only: if not read_only:
self.FAKE_REPOS.svn_dirty = True self.FAKE_REPOS.svn_dirty = True
@ -145,7 +147,7 @@ class BaseTest(fake_repos.FakeReposTestBase):
# pylint: disable=W0212 # pylint: disable=W0212
self.assertEquals( self.assertEquals(
(['master', 'working_branch'], 'working_branch'), (['master', 'working_branch'], 'working_branch'),
co.checkout._branches()) co._branches())
# Verify that the patch is applied even for read only checkout. # Verify that the patch is applied even for read only checkout.
self.assertTree(self.get_trunk(True), root) self.assertTree(self.get_trunk(True), root)
@ -193,7 +195,10 @@ class BaseTest(fake_repos.FakeReposTestBase):
ps = self.get_patches() ps = self.get_patches()
results = [] results = []
co.apply_patch(ps) co.apply_patch(ps)
expected = [(co, p) for p in ps.patches] expected_co = getattr(co, 'checkout', co)
# Because of ReadOnlyCheckout.
expected = [(expected_co, p) for p in ps.patches]
self.assertEquals(len(expected), len(results))
self.assertEquals(expected, results) self.assertEquals(expected, results)
@ -238,32 +243,23 @@ class SvnBaseTest(BaseTest):
class SvnCheckout(SvnBaseTest): class SvnCheckout(SvnBaseTest):
def _get_co(self, read_only): def _get_co(self, post_processors):
if read_only: self.assertNotEqual(False, post_processors)
return checkout.ReadOnlyCheckout( return checkout.SvnCheckout(
checkout.SvnCheckout( self.root_dir, self.name, self.usr, self.pwd, self.svn_url,
self.root_dir, self.name, None, None, self.svn_url)) post_processors)
else:
return checkout.SvnCheckout(
self.root_dir, self.name, self.usr, self.pwd, self.svn_url)
def _check(self, read_only, expected):
root = os.path.join(self.root_dir, self.name)
self._check_base(self._get_co(read_only), root, False, expected)
def testAllRW(self): def testAll(self):
expected = { expected = {
'author': self.FAKE_REPOS.USERS[0][0], 'author': self.FAKE_REPOS.USERS[0][0],
'revprops': [('realauthor', self.FAKE_REPOS.USERS[1][0])] 'revprops': [('realauthor', self.FAKE_REPOS.USERS[1][0])]
} }
self._check(False, expected) root = os.path.join(self.root_dir, self.name)
self._check_base(self._get_co(None), root, False, expected)
def testAllRO(self):
self._check(True, None)
def testException(self): def testException(self):
self._check_exception( self._check_exception(
self._get_co(True), self._get_co(None),
'While running patch -p1 --forward --force;\n' 'While running patch -p1 --forward --force;\n'
'patching file chrome/file.cc\n' 'patching file chrome/file.cc\n'
'Hunk #1 FAILED at 3.\n' 'Hunk #1 FAILED at 3.\n'
@ -271,7 +267,7 @@ class SvnCheckout(SvnBaseTest):
'chrome/file.cc.rej\n') 'chrome/file.cc.rej\n')
def testSvnProps(self): def testSvnProps(self):
co = self._get_co(False) co = self._get_co(None)
co.prepare(None) co.prepare(None)
try: try:
# svn:ignore can only be applied to directories. # svn:ignore can only be applied to directories.
@ -313,7 +309,8 @@ class SvnCheckout(SvnBaseTest):
expected = { expected = {
'revprops': [('commit-bot', 'user1@example.com')], 'revprops': [('commit-bot', 'user1@example.com')],
} }
self._check(False, expected) root = os.path.join(self.root_dir, self.name)
self._check_base(self._get_co(None), root, False, expected)
def testWithRevPropsSupportNotCommitBot(self): def testWithRevPropsSupportNotCommitBot(self):
# Add the hook that will commit in a way that removes the race condition. # Add the hook that will commit in a way that removes the race condition.
@ -331,7 +328,7 @@ class SvnCheckout(SvnBaseTest):
self._check_base(co, root, False, expected) self._check_base(co, root, False, expected)
def testAutoProps(self): def testAutoProps(self):
co = self._get_co(False) co = self._get_co(None)
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(None) co.prepare(None)
@ -347,52 +344,32 @@ class SvnCheckout(SvnBaseTest):
self.assertEquals('LF\n', out) self.assertEquals('LF\n', out)
def testProcess(self): def testProcess(self):
co = lambda x: checkout.SvnCheckout( self._test_process(self._get_co)
self.root_dir, self.name,
None, None,
self.svn_url,
x)
self._test_process(co)
def testPrepare(self): def testPrepare(self):
co = checkout.SvnCheckout( self._test_prepare(self._get_co(None))
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'
def _get_co(self, read_only): def _get_co(self, post_processors):
co = checkout.GitSvnCheckout( self.assertNotEqual(False, post_processors)
return checkout.GitSvnCheckout(
self.root_dir, self.name[:-4], self.root_dir, self.name[:-4],
self.usr, self.pwd, self.usr, self.pwd,
self.svn_base, self.svn_trunk) self.svn_base, self.svn_trunk, post_processors)
if read_only:
co = checkout.ReadOnlyCheckout(co)
else:
# Hack to simplify testing.
co.checkout = co
return co
def _check(self, read_only, expected):
root = os.path.join(self.root_dir, self.name)
self._check_base(self._get_co(read_only), root, True, expected)
def testAllRO(self): def testAll(self):
self._check(True, None)
def testAllRW(self):
expected = { expected = {
'author': self.FAKE_REPOS.USERS[0][0], 'author': self.FAKE_REPOS.USERS[0][0],
} }
self._check(False, expected) root = os.path.join(self.root_dir, self.name)
self._check_base(self._get_co(None), root, True, expected)
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(None)
revision = git_svn_co.prepare(None) 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
@ -406,10 +383,10 @@ class GitSvnCheckout(SvnBaseTest):
def testException(self): def testException(self):
self._check_exception( self._check_exception(
self._get_co(True), 'fatal: corrupt patch at line 12\n') self._get_co(None), 'fatal: corrupt patch at line 12\n')
def testSvnProps(self): def testSvnProps(self):
co = self._get_co(False) co = self._get_co(None)
co.prepare(None) co.prepare(None)
try: try:
svn_props = [('foo', 'bar')] svn_props = [('foo', 'bar')]
@ -428,17 +405,18 @@ class GitSvnCheckout(SvnBaseTest):
[patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, svn_props)]) [patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, svn_props)])
def testProcess(self): def testProcess(self):
co = lambda x: checkout.SvnCheckout( self._test_process(self._get_co)
self.root_dir, self.name,
None, None,
self.svn_url, x)
self._test_process(co)
def testPrepare(self): def testPrepare(self):
co = checkout.SvnCheckout( co = self._get_co(None)
self.root_dir, self.name, # TODO(maruel): Cheat here until prepare(revision != None) implemented.
None, None, co.old_prepare = co.prepare
self.svn_url) def prepare(rev):
# Basically, test that it is broken.
self.assertEquals(1, rev)
self.assertEquals(2, co.old_prepare(None))
return 1
co.prepare = prepare
self._test_prepare(co) self._test_prepare(co)
@ -450,15 +428,14 @@ class RawCheckout(SvnBaseTest):
self.root_dir, self.name, None, None, self.svn_url) self.root_dir, self.name, None, None, self.svn_url)
self.base_co.prepare(None) self.base_co.prepare(None)
def _get_co(self, read_only): def _get_co(self, post_processors):
co = checkout.RawCheckout(self.root_dir, self.name, None) self.assertNotEqual(False, post_processors)
if read_only: return checkout.RawCheckout(self.root_dir, self.name, post_processors)
return checkout.ReadOnlyCheckout(co)
return co
def _check(self, read_only): def testAll(self):
# Can't use self._check_base() since it's too different.
root = os.path.join(self.root_dir, self.name) root = os.path.join(self.root_dir, self.name)
co = self._get_co(read_only) co = self._get_co(None)
# A copy of BaseTest._check_base() # A copy of BaseTest._check_base()
self.assertEquals(root, co.project_path) self.assertEquals(root, co.project_path)
@ -473,47 +450,68 @@ class RawCheckout(SvnBaseTest):
# Verify that the patch is applied even for read only checkout. # Verify that the patch is applied even for read only checkout.
self.assertTree(self.get_trunk(True), root) self.assertTree(self.get_trunk(True), root)
if read_only: try:
revision = co.commit(u'msg', self.FAKE_REPOS.USERS[1][0]) co.commit(u'msg', self.FAKE_REPOS.USERS[1][0])
self.assertEquals('FAKE', revision) self.fail()
else: except NotImplementedError:
try: pass
co.commit(u'msg', self.FAKE_REPOS.USERS[1][0])
self.fail()
except NotImplementedError:
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(None)) self.assertEquals(None, co.prepare(None))
self.assertTree(self.get_trunk(True), root) self.assertTree(self.get_trunk(True), root)
def testAllRW(self): def testException(self):
self._check(False) self._check_exception(
self._get_co(None),
'patching file chrome/file.cc\n'
'Hunk #1 FAILED at 3.\n'
'1 out of 1 hunk FAILED -- saving rejects to file '
'chrome/file.cc.rej\n')
def testProcess(self):
self._test_process(self._get_co)
def testPrepare(self):
# RawCheckout doesn't support prepare() but emulate it.
co = self._get_co(None)
revs = [1]
def prepare(asked):
self.assertEquals(1, asked)
return revs.pop(0)
co.prepare = prepare
self._test_prepare(co)
self.assertEquals([], revs)
def testAllRO(self): class ReadOnlyCheckout(SvnBaseTest):
self._check(True) # Use SvnCheckout as the backed since it support read-only checkouts too.
is_read_only = True
def _get_co(self, post_processors):
self.assertNotEqual(False, post_processors)
return checkout.ReadOnlyCheckout(
checkout.SvnCheckout(
self.root_dir, self.name, None, None, self.svn_url, None),
post_processors)
def testAll(self):
root = os.path.join(self.root_dir, self.name)
self._check_base(self._get_co(None), root, False, None)
def testException(self): def testException(self):
self._check_exception( self._check_exception(
self._get_co(True), self._get_co(None),
'While running patch -p1 --forward --force;\n'
'patching file chrome/file.cc\n' 'patching file chrome/file.cc\n'
'Hunk #1 FAILED at 3.\n' 'Hunk #1 FAILED at 3.\n'
'1 out of 1 hunk FAILED -- saving rejects to file ' '1 out of 1 hunk FAILED -- saving rejects to file '
'chrome/file.cc.rej\n') 'chrome/file.cc.rej\n')
def testProcess(self): def testProcess(self):
co = lambda x: checkout.SvnCheckout( self._test_process(self._get_co)
self.root_dir, self.name,
None, None,
self.svn_url, x)
self._test_process(co)
def testPrepare(self): def testPrepare(self):
co = checkout.SvnCheckout( self._test_prepare(self._get_co(None))
self.root_dir, self.name,
None, None,
self.svn_url)
self._test_prepare(co)
if __name__ == '__main__': if __name__ == '__main__':

Loading…
Cancel
Save