Chromium Code Reviews| 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 and Gerrit.""" | 8 """A git-command for integrating reviews on Rietveld and Gerrit.""" |
| 9 | 9 |
| 10 from __future__ import print_function | 10 from __future__ import print_function |
| (...skipping 3740 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3751 | 3751 |
| 3752 | 3752 |
| 3753 def IsSubmoduleMergeCommit(ref): | 3753 def IsSubmoduleMergeCommit(ref): |
| 3754 # When submodules are added to the repo, we expect there to be a single | 3754 # When submodules are added to the repo, we expect there to be a single |
| 3755 # non-git-svn merge commit at remote HEAD with a signature comment. | 3755 # non-git-svn merge commit at remote HEAD with a signature comment. |
| 3756 pattern = '^SVN changes up to revision [0-9]*$' | 3756 pattern = '^SVN changes up to revision [0-9]*$' |
| 3757 cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref] | 3757 cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref] |
| 3758 return RunGit(cmd) != '' | 3758 return RunGit(cmd) != '' |
| 3759 | 3759 |
| 3760 | 3760 |
| 3761 def SendUpstream(parser, args, cmd): | 3761 def SendUpstream(parser, args): |
| 3762 """Common code for CMDland and CmdDCommit | 3762 """Common code for CMDland |
| 3763 | 3763 |
| 3764 In case of Gerrit, uses Gerrit REST api to "submit" the issue, which pushes | 3764 In case of Gerrit, uses Gerrit REST api to "submit" the issue, which pushes |
| 3765 upstream and closes the issue automatically and atomically. | 3765 upstream and closes the issue automatically and atomically. |
| 3766 | 3766 |
| 3767 Otherwise (in case of Rietveld): | 3767 Otherwise (in case of Rietveld): |
| 3768 Squashes branch into a single commit. | 3768 Squashes branch into a single commit. |
| 3769 Updates changelog with metadata (e.g. pointer to review). | 3769 Updates changelog with metadata (e.g. pointer to review). |
| 3770 Pushes/dcommits the code upstream. | 3770 Pushes the code upstream. |
| 3771 Updates review and closes. | 3771 Updates review and closes. |
| 3772 """ | 3772 """ |
| 3773 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', | 3773 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', |
| 3774 help='bypass upload presubmit hook') | 3774 help='bypass upload presubmit hook') |
| 3775 parser.add_option('-m', dest='message', | 3775 parser.add_option('-m', dest='message', |
| 3776 help="override review description") | 3776 help="override review description") |
| 3777 parser.add_option('-f', action='store_true', dest='force', | 3777 parser.add_option('-f', action='store_true', dest='force', |
| 3778 help="force yes to questions (don't prompt)") | 3778 help="force yes to questions (don't prompt)") |
| 3779 parser.add_option('-c', dest='contributor', | 3779 parser.add_option('-c', dest='contributor', |
| 3780 help="external contributor for patch (appended to " + | 3780 help="external contributor for patch (appended to " + |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3813 print() | 3813 print() |
| 3814 print('Either reparent this branch on top of origin/master:') | 3814 print('Either reparent this branch on top of origin/master:') |
| 3815 print(' git reparent-branch --root') | 3815 print(' git reparent-branch --root') |
| 3816 print() | 3816 print() |
| 3817 print('OR run `git rebase-update` if you think the parent branch is ') | 3817 print('OR run `git rebase-update` if you think the parent branch is ') |
| 3818 print('already committed.') | 3818 print('already committed.') |
| 3819 print() | 3819 print() |
| 3820 print(' Current parent: %r' % upstream_branch) | 3820 print(' Current parent: %r' % upstream_branch) |
| 3821 return 1 | 3821 return 1 |
| 3822 | 3822 |
| 3823 if not args or cmd == 'land': | 3823 if not args: |
| 3824 # Default to merging against our best guess of the upstream branch. | 3824 # Default to merging against our best guess of the upstream branch. |
| 3825 args = [cl.GetUpstreamBranch()] | 3825 args = [cl.GetUpstreamBranch()] |
| 3826 | 3826 |
| 3827 if options.contributor: | 3827 if options.contributor: |
| 3828 if not re.match('^.*\s<\S+@\S+>$', options.contributor): | 3828 if not re.match('^.*\s<\S+@\S+>$', options.contributor): |
| 3829 print("Please provide contibutor as 'First Last <email@example.com>'") | 3829 print("Please provide contibutor as 'First Last <email@example.com>'") |
| 3830 return 1 | 3830 return 1 |
| 3831 | 3831 |
| 3832 base_branch = args[0] | 3832 base_branch = args[0] |
| 3833 base_has_submodules = IsSubmoduleMergeCommit(base_branch) | 3833 base_has_submodules = IsSubmoduleMergeCommit(base_branch) |
| 3834 | 3834 |
| 3835 if git_common.is_dirty_git_tree(cmd): | 3835 if git_common.is_dirty_git_tree(cmd='land'): |
| 3836 return 1 | 3836 return 1 |
| 3837 | 3837 |
| 3838 # This rev-list syntax means "show all commits not in my branch that | 3838 # This rev-list syntax means "show all commits not in my branch that |
| 3839 # are in base_branch". | 3839 # are in base_branch". |
| 3840 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), | 3840 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), |
| 3841 base_branch]).splitlines() | 3841 base_branch]).splitlines() |
| 3842 if upstream_commits: | 3842 if upstream_commits: |
| 3843 print('Base branch "%s" has %d commits ' | 3843 print('Base branch "%s" has %d commits ' |
| 3844 'not in this branch.' % (base_branch, len(upstream_commits))) | 3844 'not in this branch.' % (base_branch, len(upstream_commits))) |
| 3845 print('Run "git merge %s" before attempting to %s.' % (base_branch, cmd)) | 3845 print('Run "git merge %s" before attempting to land.' % (base_branch,)) |
| 3846 return 1 | 3846 return 1 |
| 3847 | 3847 |
| 3848 # This is the revision `svn dcommit` will commit on top of. | 3848 # This is the revision `svn dcommit` will commit on top of. |
| 3849 svn_head = None | 3849 svn_head = None |
| 3850 if cmd == 'dcommit' or base_has_submodules: | 3850 if base_has_submodules: |
| 3851 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', | 3851 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', |
| 3852 '--pretty=format:%H']) | 3852 '--pretty=format:%H']) |
| 3853 | 3853 |
| 3854 if cmd == 'dcommit': | |
| 3855 # If the base_head is a submodule merge commit, the first parent of the | |
| 3856 # base_head should be a git-svn commit, which is what we're interested in. | |
| 3857 base_svn_head = base_branch | |
| 3858 if base_has_submodules: | |
| 3859 base_svn_head += '^1' | |
| 3860 | |
| 3861 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head]) | |
| 3862 if extra_commits: | |
| 3863 print('This branch has %d additional commits not upstreamed yet.' | |
| 3864 % len(extra_commits.splitlines())) | |
| 3865 print('Upstream "%s" or rebase this branch on top of the upstream trunk ' | |
| 3866 'before attempting to %s.' % (base_branch, cmd)) | |
| 3867 return 1 | |
| 3868 | |
| 3869 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() | 3854 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() |
| 3870 if not options.bypass_hooks: | 3855 if not options.bypass_hooks: |
| 3871 author = None | 3856 author = None |
| 3872 if options.contributor: | 3857 if options.contributor: |
| 3873 author = re.search(r'\<(.*)\>', options.contributor).group(1) | 3858 author = re.search(r'\<(.*)\>', options.contributor).group(1) |
| 3874 hook_results = cl.RunHook( | 3859 hook_results = cl.RunHook( |
| 3875 committing=True, | 3860 committing=True, |
| 3876 may_prompt=not options.force, | 3861 may_prompt=not options.force, |
| 3877 verbose=options.verbose, | 3862 verbose=options.verbose, |
| 3878 change=cl.GetChange(merge_base, author)) | 3863 change=cl.GetChange(merge_base, author)) |
| 3879 if not hook_results.should_continue(): | 3864 if not hook_results.should_continue(): |
| 3880 return 1 | 3865 return 1 |
| 3881 | 3866 |
| 3882 # Check the tree status if the tree status URL is set. | 3867 # Check the tree status if the tree status URL is set. |
| 3883 status = GetTreeStatus() | 3868 status = GetTreeStatus() |
| 3884 if 'closed' == status: | 3869 if 'closed' == status: |
| 3885 print('The tree is closed. Please wait for it to reopen. Use ' | 3870 print('The tree is closed. Please wait for it to reopen. Use ' |
| 3886 '"git cl %s --bypass-hooks" to commit on a closed tree.' % cmd) | 3871 '"git cl land --bypass-hooks" to commit on a closed tree.') |
| 3887 return 1 | 3872 return 1 |
| 3888 elif 'unknown' == status: | 3873 elif 'unknown' == status: |
| 3889 print('Unable to determine tree status. Please verify manually and ' | 3874 print('Unable to determine tree status. Please verify manually and ' |
| 3890 'use "git cl %s --bypass-hooks" to commit on a closed tree.' % cmd) | 3875 'use "git cl land --bypass-hooks" to commit on a closed tree.') |
| 3891 return 1 | 3876 return 1 |
| 3892 | 3877 |
| 3893 change_desc = ChangeDescription(options.message) | 3878 change_desc = ChangeDescription(options.message) |
| 3894 if not change_desc.description and cl.GetIssue(): | 3879 if not change_desc.description and cl.GetIssue(): |
| 3895 change_desc = ChangeDescription(cl.GetDescription()) | 3880 change_desc = ChangeDescription(cl.GetDescription()) |
| 3896 | 3881 |
| 3897 if not change_desc.description: | 3882 if not change_desc.description: |
| 3898 if not cl.GetIssue() and options.bypass_hooks: | 3883 if not cl.GetIssue() and options.bypass_hooks: |
| 3899 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base])) | 3884 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base])) |
| 3900 else: | 3885 else: |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3963 'commit', '--author', options.contributor, | 3948 'commit', '--author', options.contributor, |
| 3964 '-m', commit_desc.description, | 3949 '-m', commit_desc.description, |
| 3965 ]) | 3950 ]) |
| 3966 else: | 3951 else: |
| 3967 RunGit(['commit', '-m', commit_desc.description]) | 3952 RunGit(['commit', '-m', commit_desc.description]) |
| 3968 if base_has_submodules: | 3953 if base_has_submodules: |
| 3969 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() | 3954 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() |
| 3970 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) | 3955 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) |
| 3971 RunGit(['checkout', CHERRY_PICK_BRANCH]) | 3956 RunGit(['checkout', CHERRY_PICK_BRANCH]) |
| 3972 RunGit(['cherry-pick', cherry_pick_commit]) | 3957 RunGit(['cherry-pick', cherry_pick_commit]) |
| 3973 if cmd == 'land': | 3958 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
| 3974 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 3959 mirror = settings.GetGitMirror(remote) |
| 3975 mirror = settings.GetGitMirror(remote) | 3960 pushurl = mirror.url if mirror else remote |
| 3976 pushurl = mirror.url if mirror else remote | 3961 pending_prefix = settings.GetPendingRefPrefix() |
| 3977 pending_prefix = settings.GetPendingRefPrefix() | 3962 if not pending_prefix or branch.startswith(pending_prefix): |
| 3978 if not pending_prefix or branch.startswith(pending_prefix): | 3963 # If not using refs/pending/heads/* at all, or target ref is already set |
| 3979 # If not using refs/pending/heads/* at all, or target ref is already set | 3964 # to pending, then push to the target ref directly. |
| 3980 # to pending, then push to the target ref directly. | 3965 retcode, output = RunGitWithCode( |
| 3981 retcode, output = RunGitWithCode( | 3966 ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) |
| 3982 ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) | 3967 pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) |
| 3983 pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) | |
| 3984 else: | |
| 3985 # Cherry-pick the change on top of pending ref and then push it. | |
| 3986 assert branch.startswith('refs/'), branch | |
| 3987 assert pending_prefix[-1] == '/', pending_prefix | |
| 3988 pending_ref = pending_prefix + branch[len('refs/'):] | |
| 3989 retcode, output = PushToGitPending(pushurl, pending_ref, branch) | |
| 3990 pushed_to_pending = (retcode == 0) | |
| 3991 if retcode == 0: | |
| 3992 revision = RunGit(['rev-parse', 'HEAD']).strip() | |
| 3993 else: | 3968 else: |
| 3994 # dcommit the merge branch. | 3969 # Cherry-pick the change on top of pending ref and then push it. |
| 3995 cmd_args = [ | 3970 assert branch.startswith('refs/'), branch |
| 3996 'svn', 'dcommit', | 3971 assert pending_prefix[-1] == '/', pending_prefix |
| 3997 '-C%s' % options.similarity, | 3972 pending_ref = pending_prefix + branch[len('refs/'):] |
| 3998 '--no-rebase', '--rmdir', | 3973 retcode, output = PushToGitPending(pushurl, pending_ref, branch) |
| 3999 ] | 3974 pushed_to_pending = (retcode == 0) |
| 4000 if settings.GetForceHttpsCommitUrl(): | 3975 if retcode == 0: |
| 4001 # Allow forcing https commit URLs for some projects that don't allow | 3976 revision = RunGit(['rev-parse', 'HEAD']).strip() |
| 4002 # committing to http URLs (like Google Code). | |
| 4003 remote_url = cl.GetGitSvnRemoteUrl() | |
| 4004 if urlparse.urlparse(remote_url).scheme == 'http': | |
| 4005 remote_url = remote_url.replace('http://', 'https://') | |
| 4006 cmd_args.append('--commit-url=%s' % remote_url) | |
| 4007 _, output = RunGitWithCode(cmd_args) | |
| 4008 if 'Committed r' in output: | |
| 4009 revision = re.match( | |
| 4010 '.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1) | |
| 4011 logging.debug(output) | 3977 logging.debug(output) |
| 4012 finally: | 3978 finally: |
| 4013 # And then swap back to the original branch and clean up. | 3979 # And then swap back to the original branch and clean up. |
| 4014 RunGit(['checkout', '-q', cl.GetBranch()]) | 3980 RunGit(['checkout', '-q', cl.GetBranch()]) |
| 4015 RunGit(['branch', '-D', MERGE_BRANCH]) | 3981 RunGit(['branch', '-D', MERGE_BRANCH]) |
| 4016 if base_has_submodules: | 3982 if base_has_submodules: |
| 4017 RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) | 3983 RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) |
| 4018 | 3984 |
| 4019 if not revision: | 3985 if not revision: |
| 4020 print('Failed to push. If this persists, please file a bug.') | 3986 print('Failed to push. If this persists, please file a bug.') |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4053 comment += ' (presubmit successful).' | 4019 comment += ' (presubmit successful).' |
| 4054 cl.RpcServer().add_comment(cl.GetIssue(), comment) | 4020 cl.RpcServer().add_comment(cl.GetIssue(), comment) |
| 4055 cl.SetIssue(None) | 4021 cl.SetIssue(None) |
| 4056 | 4022 |
| 4057 if pushed_to_pending: | 4023 if pushed_to_pending: |
| 4058 _, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 4024 _, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
| 4059 print('The commit is in the pending queue (%s).' % pending_ref) | 4025 print('The commit is in the pending queue (%s).' % pending_ref) |
| 4060 print('It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' | 4026 print('It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' |
| 4061 'footer.' % branch) | 4027 'footer.' % branch) |
| 4062 | 4028 |
| 4063 hook = POSTUPSTREAM_HOOK_PATTERN % cmd | 4029 hook = POSTUPSTREAM_HOOK_PATTERN % 'land' |
| 4064 if os.path.isfile(hook): | 4030 if os.path.isfile(hook): |
| 4065 RunCommand([hook, merge_base], error_ok=True) | 4031 RunCommand([hook, merge_base], error_ok=True) |
| 4066 | 4032 |
| 4067 return 1 if killed else 0 | 4033 return 1 if killed else 0 |
| 4068 | 4034 |
| 4069 | 4035 |
| 4070 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref): | 4036 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref): |
| 4071 print() | 4037 print() |
| 4072 print('Waiting for commit to be landed on %s...' % real_ref) | 4038 print('Waiting for commit to be landed on %s...' % real_ref) |
| 4073 print('(If you are impatient, you may Ctrl-C once without harm)') | 4039 print('(If you are impatient, you may Ctrl-C once without harm)') |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4154 print('All attempts to push to pending ref failed.') | 4120 print('All attempts to push to pending ref failed.') |
| 4155 return code, out | 4121 return code, out |
| 4156 | 4122 |
| 4157 | 4123 |
| 4158 def IsFatalPushFailure(push_stdout): | 4124 def IsFatalPushFailure(push_stdout): |
| 4159 """True if retrying push won't help.""" | 4125 """True if retrying push won't help.""" |
| 4160 return '(prohibited by Gerrit)' in push_stdout | 4126 return '(prohibited by Gerrit)' in push_stdout |
| 4161 | 4127 |
| 4162 | 4128 |
| 4163 @subcommand.usage('[upstream branch to apply against]') | 4129 @subcommand.usage('[upstream branch to apply against]') |
| 4164 def CMDdcommit(parser, args): | |
| 4165 """Commits the current changelist via git-svn.""" | |
| 4166 if not settings.GetIsGitSvn(): | |
| 4167 if git_footers.get_footer_svn_id(): | |
| 4168 # If it looks like previous commits were mirrored with git-svn. | |
| 4169 message = """This repository appears to be a git-svn mirror, but no | |
| 4170 upstream SVN master is set. You probably need to run 'git auto-svn' once.""" | |
| 4171 else: | |
| 4172 message = """This doesn't appear to be an SVN repository. | |
| 4173 If your project has a true, writeable git repository, you probably want to run | |
| 4174 'git cl land' instead. | |
| 4175 If your project has a git mirror of an upstream SVN master, you probably need | |
| 4176 to run 'git svn init'. | |
| 4177 | |
| 4178 Using the wrong command might cause your commit to appear to succeed, and the | |
| 4179 review to be closed, without actually landing upstream. If you choose to | |
| 4180 proceed, please verify that the commit lands upstream as expected.""" | |
| 4181 print(message) | |
| 4182 ask_for_data('[Press enter to dcommit or ctrl-C to quit]') | |
| 4183 # TODO(tandrii): kill this post SVN migration with | |
| 4184 # https://codereview.chromium.org/2076683002 | |
| 4185 print('WARNING: chrome infrastructure is migrating SVN repos to Git.\n' | |
| 4186 'Please let us know of this project you are committing to:' | |
| 4187 ' http://crbug.com/600451') | |
| 4188 return SendUpstream(parser, args, 'dcommit') | |
| 4189 | |
| 4190 | |
| 4191 @subcommand.usage('[upstream branch to apply against]') | |
| 4192 def CMDland(parser, args): | 4130 def CMDland(parser, args): |
| 4193 """Commits the current changelist via git.""" | 4131 """Commits the current changelist via git.""" |
| 4194 if settings.GetIsGitSvn() or git_footers.get_footer_svn_id(): | 4132 if settings.GetIsGitSvn() or git_footers.get_footer_svn_id(): |
| 4195 print('This appears to be an SVN repository.') | 4133 print('This appears to be an SVN repository.') |
| 4196 print('Are you sure you didn\'t mean \'git cl dcommit\'?') | 4134 print('Are you sure you didn\'t mean \'git cl dcommit\'?') |
|
Michael Moss
2016/08/15 15:26:32
Change this too, maybe remove the get_footer_svn_i
| |
| 4197 print('(Ignore if this is the first commit after migrating from svn->git)') | 4135 print('(Ignore if this is the first commit after migrating from svn->git)') |
| 4198 ask_for_data('[Press enter to push or ctrl-C to quit]') | 4136 ask_for_data('[Press enter to push or ctrl-C to quit]') |
| 4199 return SendUpstream(parser, args, 'land') | 4137 return SendUpstream(parser, args) |
| 4200 | 4138 |
| 4201 | 4139 |
| 4202 @subcommand.usage('<patch url or issue id or issue url>') | 4140 @subcommand.usage('<patch url or issue id or issue url>') |
| 4203 def CMDpatch(parser, args): | 4141 def CMDpatch(parser, args): |
| 4204 """Patches in a code review.""" | 4142 """Patches in a code review.""" |
| 4205 parser.add_option('-b', dest='newbranch', | 4143 parser.add_option('-b', dest='newbranch', |
| 4206 help='create a new branch off trunk for the patch') | 4144 help='create a new branch off trunk for the patch') |
| 4207 parser.add_option('-f', '--force', action='store_true', | 4145 parser.add_option('-f', '--force', action='store_true', |
| 4208 help='with -b, clobber any existing branch') | 4146 help='with -b, clobber any existing branch') |
| 4209 parser.add_option('-d', '--directory', action='store', metavar='DIR', | 4147 parser.add_option('-d', '--directory', action='store', metavar='DIR', |
| (...skipping 824 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5034 if __name__ == '__main__': | 4972 if __name__ == '__main__': |
| 5035 # These affect sys.stdout so do it outside of main() to simplify mocks in | 4973 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 5036 # unit testing. | 4974 # unit testing. |
| 5037 fix_encoding.fix_encoding() | 4975 fix_encoding.fix_encoding() |
| 5038 setup_color.init() | 4976 setup_color.init() |
| 5039 try: | 4977 try: |
| 5040 sys.exit(main(sys.argv[1:])) | 4978 sys.exit(main(sys.argv[1:])) |
| 5041 except KeyboardInterrupt: | 4979 except KeyboardInterrupt: |
| 5042 sys.stderr.write('interrupted\n') | 4980 sys.stderr.write('interrupted\n') |
| 5043 sys.exit(1) | 4981 sys.exit(1) |
| OLD | NEW |