Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 """git drover: A tool for merging changes to release branches.""" | 5 """git drover: A tool for merging changes to release branches.""" |
| 6 | 6 |
| 7 import argparse | 7 import argparse |
| 8 import cPickle | 8 import cPickle |
| 9 import functools | 9 import functools |
| 10 import logging | 10 import logging |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 258 cPickle.dump(self, f) | 258 cPickle.dump(self, f) |
| 259 | 259 |
| 260 def _prepare_manual_resolve(self): | 260 def _prepare_manual_resolve(self): |
| 261 """Prepare the workdir for the user to manually resolve the cherry-pick.""" | 261 """Prepare the workdir for the user to manually resolve the cherry-pick.""" |
| 262 # Files that have been deleted between branch and cherry-pick will not have | 262 # Files that have been deleted between branch and cherry-pick will not have |
| 263 # their skip-worktree bit set so set it manually for those files to avoid | 263 # their skip-worktree bit set so set it manually for those files to avoid |
| 264 # git status incorrectly listing them as unstaged deletes. | 264 # git status incorrectly listing them as unstaged deletes. |
| 265 repo_status = self._run_git_command(['status', '--porcelain']).splitlines() | 265 repo_status = self._run_git_command(['status', '--porcelain']).splitlines() |
| 266 extra_files = [f[3:] for f in repo_status if f[:2] == ' D'] | 266 extra_files = [f[3:] for f in repo_status if f[:2] == ' D'] |
| 267 if extra_files: | 267 if extra_files: |
| 268 self._run_git_command(['update-index', '--skip-worktree', '--'] + | 268 extra_files_on_stdin = '\n'.join(extra_files) + '\n' |
| 269 extra_files) | 269 self._run_git_command_with_stdin( |
| 270 ['update-index', '--skip-worktree', '--stdin'], | |
| 271 stdin=extra_files_on_stdin) | |
|
iannucci
2016/06/14 00:03:38
I would inline extra_files_on_stdin, but that's ju
scottmg
2016/06/14 00:13:16
Done.
| |
| 270 | 272 |
| 271 def _upload_and_land(self): | 273 def _upload_and_land(self): |
| 272 if self._dry_run: | 274 if self._dry_run: |
| 273 logging.info('--dry_run enabled; not landing.') | 275 logging.info('--dry_run enabled; not landing.') |
| 274 return True | 276 return True |
| 275 | 277 |
| 276 self._run_git_command(['reset', '--hard']) | 278 self._run_git_command(['reset', '--hard']) |
| 277 self._run_git_command(['cl', 'upload'], | 279 self._run_git_command(['cl', 'upload'], |
| 278 error_message='Upload failed', | 280 error_message='Upload failed', |
| 279 interactive=True) | 281 interactive=True) |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 307 stderr = None if self._verbose else _DEV_NULL_FILE | 309 stderr = None if self._verbose else _DEV_NULL_FILE |
| 308 | 310 |
| 309 try: | 311 try: |
| 310 return run(['git'] + args, shell=False, cwd=cwd, stderr=stderr) | 312 return run(['git'] + args, shell=False, cwd=cwd, stderr=stderr) |
| 311 except (OSError, subprocess.CalledProcessError) as e: | 313 except (OSError, subprocess.CalledProcessError) as e: |
| 312 if error_message: | 314 if error_message: |
| 313 raise Error(error_message) | 315 raise Error(error_message) |
| 314 else: | 316 else: |
| 315 raise Error('Command %r failed: %s' % (' '.join(args), e)) | 317 raise Error('Command %r failed: %s' % (' '.join(args), e)) |
| 316 | 318 |
| 319 def _run_git_command_with_stdin(self, args, stdin): | |
| 320 """Runs a git command with a provided stdin. | |
| 321 | |
| 322 Args: | |
| 323 args: A list of strings containing the args to pass to git. | |
| 324 stdin: A string to provide on stdin. | |
| 325 | |
| 326 Raises: | |
| 327 Error: The command failed to complete successfully. | |
| 328 """ | |
| 329 cwd = self._workdir if self._workdir else self._parent_repo | |
| 330 logging.debug('Running git %s (cwd %r)', ' '.join('%s' % arg | |
| 331 for arg in args), cwd) | |
| 332 | |
| 333 # Discard stderr unless verbose is enabled. | |
| 334 stderr = None if self._verbose else _DEV_NULL_FILE | |
| 335 | |
| 336 try: | |
| 337 popen = subprocess.Popen(['git'] + args, shell=False, cwd=cwd, | |
| 338 stderr=stderr, stdin=subprocess.PIPE) | |
| 339 popen.communicate(stdin) | |
| 340 popen.wait() | |
|
iannucci
2016/06/14 00:03:38
communicate implies wait
scottmg
2016/06/14 00:13:16
Done.
| |
| 341 if popen.returncode != 0: | |
| 342 raise Error('Command %r failed' % ' '.join(args)) | |
| 343 except OSError as e: | |
| 344 raise Error('Command %r failed: %s' % (' '.join(args), e)) | |
| 345 | |
| 317 | 346 |
| 318 def cherry_pick_change(branch, revision, parent_repo, dry_run, verbose=False): | 347 def cherry_pick_change(branch, revision, parent_repo, dry_run, verbose=False): |
| 319 """Cherry-picks a change into a branch. | 348 """Cherry-picks a change into a branch. |
| 320 | 349 |
| 321 Args: | 350 Args: |
| 322 branch: A string containing the release branch number to which to | 351 branch: A string containing the release branch number to which to |
| 323 cherry-pick. | 352 cherry-pick. |
| 324 revision: A string containing the revision to cherry-pick. It can be any | 353 revision: A string containing the revision to cherry-pick. It can be any |
| 325 string that git-rev-parse can identify as referring to a single | 354 string that git-rev-parse can identify as referring to a single |
| 326 revision. | 355 revision. |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 cherry_pick_change(options.branch, options.cherry_pick, | 444 cherry_pick_change(options.branch, options.cherry_pick, |
| 416 options.parent_checkout, options.dry_run, | 445 options.parent_checkout, options.dry_run, |
| 417 options.verbose) | 446 options.verbose) |
| 418 except Error as e: | 447 except Error as e: |
| 419 print 'Error:', e.message | 448 print 'Error:', e.message |
| 420 sys.exit(128) | 449 sys.exit(128) |
| 421 | 450 |
| 422 | 451 |
| 423 if __name__ == '__main__': | 452 if __name__ == '__main__': |
| 424 main() | 453 main() |
| OLD | NEW |