Commit 02056563 authored by scottmg's avatar scottmg Committed by Commit bot

drover win: Use --stdin so update-index doesn't fail on long cmdline

git update-index would fail on long command lines when setting up
a resolve. Instead of passing all the files names on the command line,
pass them through --stdin and a file handle.

BUG=598808

Review-Url: https://codereview.chromium.org/2067653002
parent f3c688bf
...@@ -265,8 +265,9 @@ class _Drover(object): ...@@ -265,8 +265,9 @@ class _Drover(object):
repo_status = self._run_git_command(['status', '--porcelain']).splitlines() repo_status = self._run_git_command(['status', '--porcelain']).splitlines()
extra_files = [f[3:] for f in repo_status if f[:2] == ' D'] extra_files = [f[3:] for f in repo_status if f[:2] == ' D']
if extra_files: if extra_files:
self._run_git_command(['update-index', '--skip-worktree', '--'] + self._run_git_command_with_stdin(
extra_files) ['update-index', '--skip-worktree', '--stdin'],
stdin='\n'.join(extra_files) + '\n')
def _upload_and_land(self): def _upload_and_land(self):
if self._dry_run: if self._dry_run:
...@@ -314,6 +315,32 @@ class _Drover(object): ...@@ -314,6 +315,32 @@ class _Drover(object):
else: else:
raise Error('Command %r failed: %s' % (' '.join(args), e)) raise Error('Command %r failed: %s' % (' '.join(args), e))
def _run_git_command_with_stdin(self, args, stdin):
"""Runs a git command with a provided stdin.
Args:
args: A list of strings containing the args to pass to git.
stdin: A string to provide on stdin.
Raises:
Error: The command failed to complete successfully.
"""
cwd = self._workdir if self._workdir else self._parent_repo
logging.debug('Running git %s (cwd %r)', ' '.join('%s' % arg
for arg in args), cwd)
# Discard stderr unless verbose is enabled.
stderr = None if self._verbose else _DEV_NULL_FILE
try:
popen = subprocess.Popen(['git'] + args, shell=False, cwd=cwd,
stderr=stderr, stdin=subprocess.PIPE)
popen.communicate(stdin)
if popen.returncode != 0:
raise Error('Command %r failed' % ' '.join(args))
except OSError as e:
raise Error('Command %r failed: %s' % (' '.join(args), e))
def cherry_pick_change(branch, revision, parent_repo, dry_run, verbose=False): def cherry_pick_change(branch, revision, parent_repo, dry_run, verbose=False):
"""Cherry-picks a change into a branch. """Cherry-picks a change into a branch.
......
...@@ -37,6 +37,8 @@ class GitDroverTest(auto_stub.TestCase): ...@@ -37,6 +37,8 @@ class GitDroverTest(auto_stub.TestCase):
self.mock(__builtins__, 'raw_input', self._get_input) self.mock(__builtins__, 'raw_input', self._get_input)
self.mock(subprocess, 'check_call', self._check_call) self.mock(subprocess, 'check_call', self._check_call)
self.mock(subprocess, 'check_output', self._check_call) self.mock(subprocess, 'check_output', self._check_call)
self.real_popen = subprocess.Popen
self.mock(subprocess, 'Popen', self._Popen)
self._commands = [] self._commands = []
self._input = [] self._input = []
self._fail_on_command = None self._fail_on_command = None
...@@ -75,7 +77,7 @@ class GitDroverTest(auto_stub.TestCase): ...@@ -75,7 +77,7 @@ class GitDroverTest(auto_stub.TestCase):
] ]
self.MANUAL_RESOLVE_PREPARATION_COMMANDS = [ self.MANUAL_RESOLVE_PREPARATION_COMMANDS = [
(['git', 'status', '--porcelain'], self._target_repo), (['git', 'status', '--porcelain'], self._target_repo),
(['git', 'update-index', '--skip-worktree', '--', 'foo', 'bar'], (['git', 'update-index', '--skip-worktree', '--stdin'],
self._target_repo), self._target_repo),
] ]
self.FINISH_MANUAL_RESOLVE_COMMANDS = [ self.FINISH_MANUAL_RESOLVE_COMMANDS = [
...@@ -113,6 +115,25 @@ class GitDroverTest(auto_stub.TestCase): ...@@ -113,6 +115,25 @@ class GitDroverTest(auto_stub.TestCase):
return ' D foo\nUU baz\n D bar\n' return ' D foo\nUU baz\n D bar\n'
return '' return ''
def _Popen(self, args, shell=False, cwd=None, stdin=None, stdout=None,
stderr=None):
if args == ['git', 'update-index', '--skip-worktree', '--stdin']:
self._commands.append((args, cwd))
self.assertFalse(shell)
self.assertEqual(stdin, subprocess.PIPE)
class MockPopen(object):
def __init__(self, *args, **kwargs):
self.returncode = -999
def communicate(self, stdin):
if stdin == 'foo\nbar\n':
self.returncode = 0
else:
self.returncode = 1
return MockPopen()
else:
return self.real_popen(args, shell=shell, cwd=cwd, stdin=stdin,
stdout=stdout, stderr=stderr)
def testSuccess(self): def testSuccess(self):
self._input = ['y', 'y'] self._input = ['y', 'y']
git_drover.cherry_pick_change('branch', 'cl', self._parent_repo, False) git_drover.cherry_pick_change('branch', 'cl', self._parent_repo, False)
......
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