Implement "stg refresh --edit" again
[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
575bbdae
KH
57options = [
58 opt('-d', '--diff', action = 'store_true',
59 short = 'Edit the patch diff'),
60 opt('-e', '--edit', action = 'store_true',
61 short = 'Invoke interactive editor'),
f9d69fc4
KH
62 ] + (argparse.sign_options() +
63 argparse.message_options(save_template = True) +
575bbdae
KH
64 argparse.author_committer_options() + argparse.diff_opts_option())
65
4491d19b 66directory = common.DirectoryHasRepositoryLib()
ed60fdae 67
ed60fdae
CM
68def func(parser, options, args):
69 """Edit the given patch or the current one.
70 """
4491d19b 71 stack = directory.repository.current_stack
ed60fdae 72
4491d19b
KH
73 if len(args) == 0:
74 if not stack.patchorder.applied:
75 raise common.CmdException(
76 'Cannot edit top patch, because no patches are applied')
77 patchname = stack.patchorder.applied[-1]
ed60fdae 78 elif len(args) == 1:
4491d19b
KH
79 [patchname] = args
80 if not stack.patches.exists(patchname):
81 raise common.CmdException('%s: no such patch' % patchname)
ed60fdae 82 else:
4491d19b
KH
83 parser.error('Cannot edit more than one patch')
84
85 cd = orig_cd = stack.patches.get(patchname).commit.data
ed60fdae 86
ef954fe6
KH
87 cd, failed_diff = edit.auto_edit_patch(
88 stack.repository, cd, msg = options.message, contains_diff = True,
89 author = options.author, committer = options.committer,
90 sign_str = options.sign_str)
4491d19b
KH
91
92 if options.save_template:
93 options.save_template(
ef954fe6
KH
94 edit.patch_desc(stack.repository, cd,
95 options.diff, options.diff_flags, failed_diff))
4491d19b
KH
96 return utils.STGIT_SUCCESS
97
4491d19b 98 if cd == orig_cd or options.edit:
ef954fe6
KH
99 cd, failed_diff = edit.interactive_edit_patch(
100 stack.repository, cd, options.diff, options.diff_flags, failed_diff)
4491d19b
KH
101
102 def failed():
103 fn = '.stgit-failed.patch'
104 f = file(fn, 'w')
ef954fe6
KH
105 f.write(edit.patch_desc(stack.repository, cd,
106 options.diff, options.diff_flags, failed_diff))
4491d19b
KH
107 f.close()
108 out.error('Edited patch did not apply.',
109 'It has been saved to "%s".' % fn)
110 return utils.STGIT_COMMAND_ERROR
111
112 # If we couldn't apply the patch, fail without even trying to
113 # effect any of the changes.
114 if failed_diff:
115 return failed()
116
117 # The patch applied, so now we have to rewrite the StGit patch
118 # (and any patches on top of it).
119 iw = stack.repository.default_iw
781e549a 120 trans = transaction.StackTransaction(stack, 'edit', allow_conflicts = True)
4491d19b
KH
121 if patchname in trans.applied:
122 popped = trans.applied[trans.applied.index(patchname)+1:]
123 assert not trans.pop_patches(lambda pn: pn in popped)
124 else:
125 popped = []
126 trans.patches[patchname] = stack.repository.commit(cd)
127 try:
128 for pn in popped:
129 trans.push_patch(pn, iw)
130 except transaction.TransactionHalted:
131 pass
132 try:
133 # Either a complete success, or a conflict during push. But in
134 # either case, we've successfully effected the edits the user
135 # asked us for.
136 return trans.run(iw)
137 except transaction.TransactionException:
138 # Transaction aborted -- we couldn't check out files due to
139 # dirty index/worktree. The edits were not carried out.
140 return failed()