Add automatic git-mergetool invocation to the new infrastructure
[stgit] / stgit / commands / edit.py
... / ...
CommitLineData
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
21from stgit.argparse import opt
22from stgit import argparse, git, utils
23from stgit.commands import common
24from stgit.lib import git as gitlib, transaction, edit
25from stgit.out import *
26
27help = 'edit a patch description or diff'
28kind = 'patch'
29usage = ['[options] [<patch>]']
30description = """
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.
34
35The editor is invoked with the following contents:
36
37 From: A U Thor <author@example.com>
38 Date: creation date
39
40 Patch description
41
42If --diff was specified, the diff appears at the bottom, after a
43separator:
44
45 ---
46
47 Diff text
48
49Command-line options can be used to modify specific information
50without invoking the editor. (With the --edit option, the editor is
51invoked even if such command-line options are given.)
52
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."""
56
57args = [argparse.applied_patches, argparse.unapplied_patches,
58 argparse.hidden_patches]
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'),
64 ] + (argparse.sign_options() +
65 argparse.message_options(save_template = True) +
66 argparse.author_options() + argparse.diff_opts_option())
67
68directory = common.DirectoryHasRepositoryLib()
69
70def func(parser, options, args):
71 """Edit the given patch or the current one.
72 """
73 stack = directory.repository.current_stack
74
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]
80 elif len(args) == 1:
81 [patchname] = args
82 if not stack.patches.exists(patchname):
83 raise common.CmdException('%s: no such patch' % patchname)
84 else:
85 parser.error('Cannot edit more than one patch')
86
87 cd = orig_cd = stack.patches.get(patchname).commit.data
88
89 cd, failed_diff = edit.auto_edit_patch(
90 stack.repository, cd, msg = options.message, contains_diff = True,
91 author = options.author, committer = lambda p: p,
92 sign_str = options.sign_str)
93
94 if options.save_template:
95 options.save_template(
96 edit.patch_desc(stack.repository, cd,
97 options.diff, options.diff_flags, failed_diff))
98 return utils.STGIT_SUCCESS
99
100 if cd == orig_cd or options.edit:
101 cd, failed_diff = edit.interactive_edit_patch(
102 stack.repository, cd, options.diff, options.diff_flags, failed_diff)
103
104 def failed():
105 fn = '.stgit-failed.patch'
106 f = file(fn, 'w')
107 f.write(edit.patch_desc(stack.repository, cd,
108 options.diff, options.diff_flags, failed_diff))
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
122 trans = transaction.StackTransaction(stack, 'edit', allow_conflicts = True)
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:
131 trans.push_patch(pn, iw, allow_interactive = True)
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()