Add automatic git-mergetool invocation to the new infrastructure
[stgit] / stgit / commands / edit.py
CommitLineData
ed60fdae
CM
1"""Patch editing command
2"""
3
4__copyright__ = """
5Copyright (C) 2007, Catalin Marinas <catalin.marinas@gmail.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License version 2 as
9published by the Free Software Foundation.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19"""
20
575bbdae 21from stgit.argparse import opt
20a52e06 22from stgit import argparse, git, utils
4491d19b 23from stgit.commands import common
ef954fe6 24from stgit.lib import git as gitlib, transaction, edit
ed60fdae 25from stgit.out import *
ed60fdae
CM
26
27help = 'edit a patch description or diff'
33ff9cdd 28kind = 'patch'
575bbdae
KH
29usage = ['[options] [<patch>]']
30description = """
b52f3780
KH
31Edit the description and author information of the given patch (or the
32current patch if no patch name was given). With --diff, also edit the
33diff.
ed60fdae 34
b52f3780 35The editor is invoked with the following contents:
ed60fdae 36
b52f3780 37 From: A U Thor <author@example.com>
ed60fdae
CM
38 Date: creation date
39
7e301a73 40 Patch description
b52f3780
KH
41
42If --diff was specified, the diff appears at the bottom, after a
43separator:
44
45 ---
ed60fdae 46
b52f3780 47 Diff text
ed60fdae
CM
48
49Command-line options can be used to modify specific information
4491d19b
KH
50without invoking the editor. (With the --edit option, the editor is
51invoked even if such command-line options are given.)
ed60fdae 52
4491d19b
KH
53If the patch diff is edited but does not apply, no changes are made to
54the patch at all. The edited patch is saved to a file which you can
55feed to "stg edit --file", once you have made sure it does apply."""
ed60fdae 56
6c8a90e1
KH
57args = [argparse.applied_patches, argparse.unapplied_patches,
58 argparse.hidden_patches]
575bbdae
KH
59options = [
60 opt('-d', '--diff', action = 'store_true',
61 short = 'Edit the patch diff'),
62 opt('-e', '--edit', action = 'store_true',
63 short = 'Invoke interactive editor'),
f9d69fc4
KH
64 ] + (argparse.sign_options() +
65 argparse.message_options(save_template = True) +
53388a71 66 argparse.author_options() + argparse.diff_opts_option())
575bbdae 67
4491d19b 68directory = common.DirectoryHasRepositoryLib()
ed60fdae 69
ed60fdae
CM
70def func(parser, options, args):
71 """Edit the given patch or the current one.
72 """
4491d19b 73 stack = directory.repository.current_stack
ed60fdae 74
4491d19b
KH
75 if len(args) == 0:
76 if not stack.patchorder.applied:
77 raise common.CmdException(
78 'Cannot edit top patch, because no patches are applied')
79 patchname = stack.patchorder.applied[-1]
ed60fdae 80 elif len(args) == 1:
4491d19b
KH
81 [patchname] = args
82 if not stack.patches.exists(patchname):
83 raise common.CmdException('%s: no such patch' % patchname)
ed60fdae 84 else:
4491d19b
KH
85 parser.error('Cannot edit more than one patch')
86
87 cd = orig_cd = stack.patches.get(patchname).commit.data
ed60fdae 88
ef954fe6
KH
89 cd, failed_diff = edit.auto_edit_patch(
90 stack.repository, cd, msg = options.message, contains_diff = True,
53388a71 91 author = options.author, committer = lambda p: p,
ef954fe6 92 sign_str = options.sign_str)
4491d19b
KH
93
94 if options.save_template:
95 options.save_template(
ef954fe6
KH
96 edit.patch_desc(stack.repository, cd,
97 options.diff, options.diff_flags, failed_diff))
4491d19b
KH
98 return utils.STGIT_SUCCESS
99
4491d19b 100 if cd == orig_cd or options.edit:
ef954fe6
KH
101 cd, failed_diff = edit.interactive_edit_patch(
102 stack.repository, cd, options.diff, options.diff_flags, failed_diff)
4491d19b
KH
103
104 def failed():
105 fn = '.stgit-failed.patch'
106 f = file(fn, 'w')
ef954fe6
KH
107 f.write(edit.patch_desc(stack.repository, cd,
108 options.diff, options.diff_flags, failed_diff))
4491d19b
KH
109 f.close()
110 out.error('Edited patch did not apply.',
111 'It has been saved to "%s".' % fn)
112 return utils.STGIT_COMMAND_ERROR
113
114 # If we couldn't apply the patch, fail without even trying to
115 # effect any of the changes.
116 if failed_diff:
117 return failed()
118
119 # The patch applied, so now we have to rewrite the StGit patch
120 # (and any patches on top of it).
121 iw = stack.repository.default_iw
781e549a 122 trans = transaction.StackTransaction(stack, 'edit', allow_conflicts = True)
4491d19b
KH
123 if patchname in trans.applied:
124 popped = trans.applied[trans.applied.index(patchname)+1:]
125 assert not trans.pop_patches(lambda pn: pn in popped)
126 else:
127 popped = []
128 trans.patches[patchname] = stack.repository.commit(cd)
129 try:
130 for pn in popped:
1de97e5f 131 trans.push_patch(pn, iw, allow_interactive = True)
4491d19b
KH
132 except transaction.TransactionHalted:
133 pass
134 try:
135 # Either a complete success, or a conflict during push. But in
136 # either case, we've successfully effected the edits the user
137 # asked us for.
138 return trans.run(iw)
139 except transaction.TransactionException:
140 # Transaction aborted -- we couldn't check out files due to
141 # dirty index/worktree. The edits were not carried out.
142 return failed()