Commit 8a1396cd authored by maruel@chromium.org's avatar maruel@chromium.org

Add post_process argument to Checkout.apply_patch().

This enables doing late modifications like updating the copyright notice or fixing line endings.

Also silence the checkout operations a bit more when VOID=subprocess2.VOID.

Add corresponding unit tests.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@82587 0039d316-1c4b-4281-b951-d872f2087c98
parent cfbdd987
...@@ -80,11 +80,16 @@ class CheckoutBase(object): ...@@ -80,11 +80,16 @@ class CheckoutBase(object):
""" """
raise NotImplementedError() raise NotImplementedError()
def apply_patch(self, patches): def apply_patch(self, patches, post_processor=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
PatchApplicationFailed when relevant. PatchApplicationFailed when relevant.
Args:
patches: patch.PatchSet object.
post_processor: list of lambda(checkout, patches) to call on each of the
modified files.
""" """
raise NotImplementedError() raise NotImplementedError()
...@@ -102,7 +107,9 @@ class RawCheckout(CheckoutBase): ...@@ -102,7 +107,9 @@ class RawCheckout(CheckoutBase):
"""Stubbed out.""" """Stubbed out."""
pass pass
def apply_patch(self, patches): def apply_patch(self, patches, post_processor=None):
"""Ignores svn properties."""
post_processor = post_processor or []
for p in patches: for p in patches:
try: try:
stdout = '' stdout = ''
...@@ -122,7 +129,8 @@ class RawCheckout(CheckoutBase): ...@@ -122,7 +129,8 @@ class RawCheckout(CheckoutBase):
['patch', '-p%s' % p.patchlevel], ['patch', '-p%s' % p.patchlevel],
stdin=p.get(), stdin=p.get(),
cwd=self.project_path) cwd=self.project_path)
# Ignore p.svn_properties. for post in post_processor:
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))
except subprocess.CalledProcessError, e: except subprocess.CalledProcessError, e:
...@@ -223,7 +231,6 @@ class SvnCheckout(CheckoutBase, SvnMixIn): ...@@ -223,7 +231,6 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
assert self.svn_url assert self.svn_url
def prepare(self): def prepare(self):
"""Creates the initial checkouts for the repo."""
# Will checkout if the directory is not present. # Will checkout if the directory is not present.
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' %
...@@ -234,8 +241,8 @@ class SvnCheckout(CheckoutBase, SvnMixIn): ...@@ -234,8 +241,8 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
self._last_seen_revision = revision self._last_seen_revision = revision
return revision return revision
def apply_patch(self, patches): def apply_patch(self, patches, post_processor=None):
"""Applies a patch.""" post_processor = post_processor or []
for p in patches: for p in patches:
try: try:
stdout = '' stdout = ''
...@@ -274,6 +281,8 @@ class SvnCheckout(CheckoutBase, SvnMixIn): ...@@ -274,6 +281,8 @@ class SvnCheckout(CheckoutBase, SvnMixIn):
if fnmatch.fnmatch(p.filename, prop): if fnmatch.fnmatch(p.filename, prop):
stdout += self._check_output_svn( stdout += self._check_output_svn(
['propset'] + value.split('=', 1) + [p.filename]) ['propset'] + value.split('=', 1) + [p.filename])
for post in post_processor:
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))
except subprocess.CalledProcessError, e: except subprocess.CalledProcessError, e:
...@@ -352,13 +361,19 @@ class GitCheckoutBase(CheckoutBase): ...@@ -352,13 +361,19 @@ 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_processor=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.
Ignores svn properties and raise an exception on unexpected ones.
"""
post_processor = post_processor 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?
self._check_call_git( self._check_call_git(
['checkout', '-b', self.working_branch, ['checkout', '-b', self.working_branch,
'%s/%s' % (self.remote, self.remote_branch)]) '%s/%s' % (self.remote, self.remote_branch), '--quiet'])
for p in patches: for p in patches:
try: try:
stdout = '' stdout = ''
...@@ -387,6 +402,8 @@ class GitCheckoutBase(CheckoutBase): ...@@ -387,6 +402,8 @@ 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 post_processor:
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))
except subprocess.CalledProcessError, e: except subprocess.CalledProcessError, e:
...@@ -492,6 +509,7 @@ class GitSvnCheckoutBase(GitCheckoutBase, SvnMixIn): ...@@ -492,6 +509,7 @@ class GitSvnCheckoutBase(GitCheckoutBase, SvnMixIn):
kwargs = {} kwargs = {}
if self.commit_pwd: if self.commit_pwd:
kwargs['stdin'] = self.commit_pwd + '\n' kwargs['stdin'] = self.commit_pwd + '\n'
kwargs['stderr'] = subprocess2.STDOUT
self._check_call_git_svn( self._check_call_git_svn(
['dcommit', '--rmdir', '--find-copies-harder', ['dcommit', '--rmdir', '--find-copies-harder',
'--username', self.commit_user], '--username', self.commit_user],
...@@ -547,8 +565,9 @@ class GitSvnPremadeCheckout(GitSvnCheckoutBase): ...@@ -547,8 +565,9 @@ class GitSvnPremadeCheckout(GitSvnCheckoutBase):
assert self.remote == 'origin' assert self.remote == 'origin'
# self.project_path doesn't exist yet. # self.project_path doesn't exist yet.
self._check_call_git( self._check_call_git(
['clone', self.git_url, self.project_name], ['clone', self.git_url, self.project_name, '--quiet'],
cwd=self.root_dir) cwd=self.root_dir,
stderr=subprocess2.STDOUT)
try: try:
configured_svn_url = self._check_output_git( configured_svn_url = self._check_output_git(
['config', 'svn-remote.svn.url']).strip() ['config', 'svn-remote.svn.url']).strip()
...@@ -591,8 +610,10 @@ class GitSvnCheckout(GitSvnCheckoutBase): ...@@ -591,8 +610,10 @@ class GitSvnCheckout(GitSvnCheckoutBase):
['clone', ['clone',
'--prefix', self.remote + '/', '--prefix', self.remote + '/',
'-T', self.trunk, '-T', self.trunk,
self.svn_url, self.project_path], self.svn_url, self.project_path,
cwd=self.root_dir) '--quiet'],
cwd=self.root_dir,
stderr=subprocess2.STDOUT)
super(GitSvnCheckout, self).prepare() super(GitSvnCheckout, self).prepare()
return self._get_revision() return self._get_revision()
...@@ -608,8 +629,8 @@ class ReadOnlyCheckout(object): ...@@ -608,8 +629,8 @@ 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_processor=None):
return self.checkout.apply_patch(patches) return self.checkout.apply_patch(patches, post_processor)
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' % (
......
...@@ -273,6 +273,8 @@ class PatchSet(object): ...@@ -273,6 +273,8 @@ class PatchSet(object):
def __init__(self, patches): def __init__(self, patches):
self.patches = patches self.patches = patches
for p in self.patches:
assert isinstance(p, FilePatchBase)
def set_relpath(self, relpath): def set_relpath(self, relpath):
"""Used to offset the patch into a subdirectory.""" """Used to offset the patch into a subdirectory."""
......
...@@ -233,6 +233,15 @@ class BaseTest(fake_repos.FakeReposTestBase): ...@@ -233,6 +233,15 @@ class BaseTest(fake_repos.FakeReposTestBase):
def _log(self): def _log(self):
raise NotImplementedError() raise NotImplementedError()
def _test_process(self, co):
"""Makes sure the process lambda is called correctly."""
co.prepare()
ps = self.get_patches()
results = []
co.apply_patch(ps, [lambda *args: results.append(args)])
expected = [(co, p) for p in ps.patches]
self.assertEquals(expected, results)
class SvnBaseTest(BaseTest): class SvnBaseTest(BaseTest):
def setUp(self): def setUp(self):
...@@ -377,6 +386,13 @@ class SvnCheckout(SvnBaseTest): ...@@ -377,6 +386,13 @@ class SvnCheckout(SvnBaseTest):
cwd=co.project_path) cwd=co.project_path)
self.assertEquals('LF\n', out) self.assertEquals('LF\n', out)
def testProcess(self):
co = checkout.SvnCheckout(
self.root_dir, self.name,
None, None,
self.svn_url)
self._test_process(co)
class GitSvnCheckout(SvnBaseTest): class GitSvnCheckout(SvnBaseTest):
name = 'foo.git' name = 'foo.git'
...@@ -442,6 +458,13 @@ class GitSvnCheckout(SvnBaseTest): ...@@ -442,6 +458,13 @@ class GitSvnCheckout(SvnBaseTest):
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)])
def testProcess(self):
co = checkout.SvnCheckout(
self.root_dir, self.name,
None, None,
self.svn_url)
self._test_process(co)
class RawCheckout(SvnBaseTest): class RawCheckout(SvnBaseTest):
def setUp(self): def setUp(self):
...@@ -502,6 +525,13 @@ class RawCheckout(SvnBaseTest): ...@@ -502,6 +525,13 @@ class RawCheckout(SvnBaseTest):
'1 out of 1 hunk FAILED -- saving rejects to file ' '1 out of 1 hunk FAILED -- saving rejects to file '
'svn_utils_test.txt.rej\n') 'svn_utils_test.txt.rej\n')
def testProcess(self):
co = checkout.SvnCheckout(
self.root_dir, self.name,
None, None,
self.svn_url)
self._test_process(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