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