| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 | 5 |
| 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
| 7 | 7 |
| 8 """A git-command for integrating reviews on Rietveld.""" | 8 """A git-command for integrating reviews on Rietveld.""" |
| 9 | 9 |
| 10 from distutils.version import LooseVersion | 10 from distutils.version import LooseVersion |
| (...skipping 3403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3414 | 3414 |
| 3415 change = cl.GetChange(base_branch, None) | 3415 change = cl.GetChange(base_branch, None) |
| 3416 return owners_finder.OwnersFinder( | 3416 return owners_finder.OwnersFinder( |
| 3417 [f.LocalPath() for f in | 3417 [f.LocalPath() for f in |
| 3418 cl.GetChange(base_branch, None).AffectedFiles()], | 3418 cl.GetChange(base_branch, None).AffectedFiles()], |
| 3419 change.RepositoryRoot(), author, | 3419 change.RepositoryRoot(), author, |
| 3420 fopen=file, os_path=os.path, glob=glob.glob, | 3420 fopen=file, os_path=os.path, glob=glob.glob, |
| 3421 disable_color=options.no_color).run() | 3421 disable_color=options.no_color).run() |
| 3422 | 3422 |
| 3423 | 3423 |
| 3424 def BuildGitDiffCmd(diff_type, upstream_commit, args, extensions): | 3424 def BuildGitDiffCmd(diff_type, upstream_commit, args): |
| 3425 """Generates a diff command.""" | 3425 """Generates a diff command.""" |
| 3426 # Generate diff for the current branch's changes. | 3426 # Generate diff for the current branch's changes. |
| 3427 diff_cmd = ['diff', '--no-ext-diff', '--no-prefix', diff_type, | 3427 diff_cmd = ['diff', '--no-ext-diff', '--no-prefix', diff_type, |
| 3428 upstream_commit, '--' ] | 3428 upstream_commit, '--' ] |
| 3429 | 3429 |
| 3430 if args: | 3430 if args: |
| 3431 for arg in args: | 3431 for arg in args: |
| 3432 if os.path.isdir(arg): | 3432 if os.path.isdir(arg) or os.path.isfile(arg): |
| 3433 diff_cmd.extend(os.path.join(arg, '*' + ext) for ext in extensions) | |
| 3434 elif os.path.isfile(arg): | |
| 3435 diff_cmd.append(arg) | 3433 diff_cmd.append(arg) |
| 3436 else: | 3434 else: |
| 3437 DieWithError('Argument "%s" is not a file or a directory' % arg) | 3435 DieWithError('Argument "%s" is not a file or a directory' % arg) |
| 3438 else: | |
| 3439 diff_cmd.extend('*' + ext for ext in extensions) | |
| 3440 | 3436 |
| 3441 return diff_cmd | 3437 return diff_cmd |
| 3442 | 3438 |
| 3439 def MatchingFileType(file_name, extensions): |
| 3440 """Returns true if the file name ends with one of the given extensions.""" |
| 3441 return bool([ext for ext in extensions if file_name.lower().endswith(ext)]) |
| 3443 | 3442 |
| 3444 @subcommand.usage('[files or directories to diff]') | 3443 @subcommand.usage('[files or directories to diff]') |
| 3445 def CMDformat(parser, args): | 3444 def CMDformat(parser, args): |
| 3446 """Runs auto-formatting tools (clang-format etc.) on the diff.""" | 3445 """Runs auto-formatting tools (clang-format etc.) on the diff.""" |
| 3447 CLANG_EXTS = ['.cc', '.cpp', '.h', '.mm', '.proto', '.java'] | 3446 CLANG_EXTS = ['.cc', '.cpp', '.h', '.mm', '.proto', '.java'] |
| 3448 parser.add_option('--full', action='store_true', | 3447 parser.add_option('--full', action='store_true', |
| 3449 help='Reformat the full content of all touched files') | 3448 help='Reformat the full content of all touched files') |
| 3450 parser.add_option('--dry-run', action='store_true', | 3449 parser.add_option('--dry-run', action='store_true', |
| 3451 help='Don\'t modify any file on disk.') | 3450 help='Don\'t modify any file on disk.') |
| 3452 parser.add_option('--python', action='store_true', | 3451 parser.add_option('--python', action='store_true', |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3469 cl = Changelist() | 3468 cl = Changelist() |
| 3470 upstream_branch = cl.GetUpstreamBranch() | 3469 upstream_branch = cl.GetUpstreamBranch() |
| 3471 if upstream_branch: | 3470 if upstream_branch: |
| 3472 upstream_commit = RunGit(['merge-base', 'HEAD', upstream_branch]) | 3471 upstream_commit = RunGit(['merge-base', 'HEAD', upstream_branch]) |
| 3473 upstream_commit = upstream_commit.strip() | 3472 upstream_commit = upstream_commit.strip() |
| 3474 | 3473 |
| 3475 if not upstream_commit: | 3474 if not upstream_commit: |
| 3476 DieWithError('Could not find base commit for this branch. ' | 3475 DieWithError('Could not find base commit for this branch. ' |
| 3477 'Are you in detached state?') | 3476 'Are you in detached state?') |
| 3478 | 3477 |
| 3479 if opts.full: | 3478 changed_files_cmd = BuildGitDiffCmd('--name-only', upstream_commit, args) |
| 3480 # Only list the names of modified files. | 3479 diff_output = RunGit(changed_files_cmd) |
| 3481 diff_type = '--name-only' | 3480 diff_files = diff_output.splitlines() |
| 3482 else: | |
| 3483 # Only generate context-less patches. | |
| 3484 diff_type = '-U0' | |
| 3485 | 3481 |
| 3486 diff_cmd = BuildGitDiffCmd(diff_type, upstream_commit, args, CLANG_EXTS) | 3482 clang_diff_files = [x for x in diff_files if MatchingFileType(x, CLANG_EXTS)] |
| 3487 diff_output = RunGit(diff_cmd) | 3483 python_diff_files = [x for x in diff_files if MatchingFileType(x, ['.py'])] |
| 3484 dart_diff_files = [x for x in diff_files if MatchingFileType(x, ['.dart'])] |
| 3488 | 3485 |
| 3489 top_dir = os.path.normpath( | 3486 top_dir = os.path.normpath( |
| 3490 RunGit(["rev-parse", "--show-toplevel"]).rstrip('\n')) | 3487 RunGit(["rev-parse", "--show-toplevel"]).rstrip('\n')) |
| 3491 | 3488 |
| 3492 # Locate the clang-format binary in the checkout | 3489 # Locate the clang-format binary in the checkout |
| 3493 try: | 3490 try: |
| 3494 clang_format_tool = clang_format.FindClangFormatToolInChromiumTree() | 3491 clang_format_tool = clang_format.FindClangFormatToolInChromiumTree() |
| 3495 except clang_format.NotFoundError, e: | 3492 except clang_format.NotFoundError, e: |
| 3496 DieWithError(e) | 3493 DieWithError(e) |
| 3497 | 3494 |
| 3498 # Set to 2 to signal to CheckPatchFormatted() that this patch isn't | 3495 # Set to 2 to signal to CheckPatchFormatted() that this patch isn't |
| 3499 # formatted. This is used to block during the presubmit. | 3496 # formatted. This is used to block during the presubmit. |
| 3500 return_value = 0 | 3497 return_value = 0 |
| 3501 | 3498 |
| 3502 if opts.full: | 3499 if opts.full: |
| 3503 # diff_output is a list of files to send to clang-format. | 3500 if clang_diff_files: |
| 3504 files = diff_output.splitlines() | |
| 3505 if files: | |
| 3506 cmd = [clang_format_tool] | 3501 cmd = [clang_format_tool] |
| 3507 if not opts.dry_run and not opts.diff: | 3502 if not opts.dry_run and not opts.diff: |
| 3508 cmd.append('-i') | 3503 cmd.append('-i') |
| 3509 stdout = RunCommand(cmd + files, cwd=top_dir) | 3504 stdout = RunCommand(cmd + clang_diff_files, cwd=top_dir) |
| 3510 if opts.diff: | 3505 if opts.diff: |
| 3511 sys.stdout.write(stdout) | 3506 sys.stdout.write(stdout) |
| 3512 else: | 3507 else: |
| 3513 env = os.environ.copy() | 3508 env = os.environ.copy() |
| 3514 env['PATH'] = str(os.path.dirname(clang_format_tool)) | 3509 env['PATH'] = str(os.path.dirname(clang_format_tool)) |
| 3515 # diff_output is a patch to send to clang-format-diff.py | |
| 3516 try: | 3510 try: |
| 3517 script = clang_format.FindClangFormatScriptInChromiumTree( | 3511 script = clang_format.FindClangFormatScriptInChromiumTree( |
| 3518 'clang-format-diff.py') | 3512 'clang-format-diff.py') |
| 3519 except clang_format.NotFoundError, e: | 3513 except clang_format.NotFoundError, e: |
| 3520 DieWithError(e) | 3514 DieWithError(e) |
| 3521 | 3515 |
| 3522 cmd = [sys.executable, script, '-p0'] | 3516 cmd = [sys.executable, script, '-p0'] |
| 3523 if not opts.dry_run and not opts.diff: | 3517 if not opts.dry_run and not opts.diff: |
| 3524 cmd.append('-i') | 3518 cmd.append('-i') |
| 3525 | 3519 |
| 3520 diff_cmd = BuildGitDiffCmd('-U0', upstream_commit, clang_diff_files) |
| 3521 diff_output = RunGit(diff_cmd) |
| 3522 |
| 3526 stdout = RunCommand(cmd, stdin=diff_output, cwd=top_dir, env=env) | 3523 stdout = RunCommand(cmd, stdin=diff_output, cwd=top_dir, env=env) |
| 3527 if opts.diff: | 3524 if opts.diff: |
| 3528 sys.stdout.write(stdout) | 3525 sys.stdout.write(stdout) |
| 3529 if opts.dry_run and len(stdout) > 0: | 3526 if opts.dry_run and len(stdout) > 0: |
| 3530 return_value = 2 | 3527 return_value = 2 |
| 3531 | 3528 |
| 3532 # Similar code to above, but using yapf on .py files rather than clang-format | 3529 # Similar code to above, but using yapf on .py files rather than clang-format |
| 3533 # on C/C++ files | 3530 # on C/C++ files |
| 3534 if opts.python: | 3531 if opts.python: |
| 3535 diff_cmd = BuildGitDiffCmd(diff_type, upstream_commit, args, ['.py']) | |
| 3536 diff_output = RunGit(diff_cmd) | |
| 3537 yapf_tool = gclient_utils.FindExecutable('yapf') | 3532 yapf_tool = gclient_utils.FindExecutable('yapf') |
| 3538 if yapf_tool is None: | 3533 if yapf_tool is None: |
| 3539 DieWithError('yapf not found in PATH') | 3534 DieWithError('yapf not found in PATH') |
| 3540 | 3535 |
| 3541 if opts.full: | 3536 if opts.full: |
| 3542 files = diff_output.splitlines() | 3537 if python_diff_files: |
| 3543 if files: | |
| 3544 cmd = [yapf_tool] | 3538 cmd = [yapf_tool] |
| 3545 if not opts.dry_run and not opts.diff: | 3539 if not opts.dry_run and not opts.diff: |
| 3546 cmd.append('-i') | 3540 cmd.append('-i') |
| 3547 stdout = RunCommand(cmd + files, cwd=top_dir) | 3541 stdout = RunCommand(cmd + python_diff_files, cwd=top_dir) |
| 3548 if opts.diff: | 3542 if opts.diff: |
| 3549 sys.stdout.write(stdout) | 3543 sys.stdout.write(stdout) |
| 3550 else: | 3544 else: |
| 3551 # TODO(sbc): yapf --lines mode still has some issues. | 3545 # TODO(sbc): yapf --lines mode still has some issues. |
| 3552 # https://github.com/google/yapf/issues/154 | 3546 # https://github.com/google/yapf/issues/154 |
| 3553 DieWithError('--python currently only works with --full') | 3547 DieWithError('--python currently only works with --full') |
| 3554 | 3548 |
| 3555 # Build a diff command that only operates on dart files. dart's formatter | 3549 # Dart's formatter does not have the nice property of only operating on |
| 3556 # does not have the nice property of only operating on modified chunks, so | 3550 # modified chunks, so hard code full. |
| 3557 # hard code full. | 3551 if dart_diff_files: |
| 3558 dart_diff_cmd = BuildGitDiffCmd('--name-only', upstream_commit, | |
| 3559 args, ['.dart']) | |
| 3560 dart_diff_output = RunGit(dart_diff_cmd) | |
| 3561 if dart_diff_output: | |
| 3562 try: | 3552 try: |
| 3563 command = [dart_format.FindDartFmtToolInChromiumTree()] | 3553 command = [dart_format.FindDartFmtToolInChromiumTree()] |
| 3564 if not opts.dry_run and not opts.diff: | 3554 if not opts.dry_run and not opts.diff: |
| 3565 command.append('-w') | 3555 command.append('-w') |
| 3566 command.extend(dart_diff_output.splitlines()) | 3556 command.extend(dart_diff_files) |
| 3567 | 3557 |
| 3568 stdout = RunCommand(command, cwd=top_dir, env=env) | 3558 stdout = RunCommand(command, cwd=top_dir, env=env) |
| 3569 if opts.dry_run and stdout: | 3559 if opts.dry_run and stdout: |
| 3570 return_value = 2 | 3560 return_value = 2 |
| 3571 except dart_format.NotFoundError as e: | 3561 except dart_format.NotFoundError as e: |
| 3572 print ('Warning: Unable to check Dart code formatting. Dart SDK not ' + | 3562 print ('Warning: Unable to check Dart code formatting. Dart SDK not ' + |
| 3573 'found in this checkout. Files in other languages are still ' + | 3563 'found in this checkout. Files in other languages are still ' + |
| 3574 'formatted.') | 3564 'formatted.') |
| 3575 | 3565 |
| 3576 return return_value | 3566 return return_value |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3672 if __name__ == '__main__': | 3662 if __name__ == '__main__': |
| 3673 # These affect sys.stdout so do it outside of main() to simplify mocks in | 3663 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 3674 # unit testing. | 3664 # unit testing. |
| 3675 fix_encoding.fix_encoding() | 3665 fix_encoding.fix_encoding() |
| 3676 colorama.init() | 3666 colorama.init() |
| 3677 try: | 3667 try: |
| 3678 sys.exit(main(sys.argv[1:])) | 3668 sys.exit(main(sys.argv[1:])) |
| 3679 except KeyboardInterrupt: | 3669 except KeyboardInterrupt: |
| 3680 sys.stderr.write('interrupted\n') | 3670 sys.stderr.write('interrupted\n') |
| 3681 sys.exit(1) | 3671 sys.exit(1) |
| OLD | NEW |