chiark / gitweb /
4904f6807fcaed2aa4cdd1a8f3fac75fb2453e02
[stgit] / stgit / commands / edit.py
1 """Patch editing command
2 """
3
4 __copyright__ = """
5 Copyright (C) 2007, Catalin Marinas <catalin.marinas@gmail.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 """
20
21 from stgit.argparse import opt
22 from stgit import argparse, git, utils
23 from stgit.commands import common
24 from stgit.lib import git as gitlib, transaction, edit
25 from stgit.out import *
26
27 help = 'edit a patch description or diff'
28 kind = 'patch'
29 usage = ['[options] [<patch>]']
30 description = """
31 Edit the description and author information of the given patch (or the
32 current patch if no patch name was given). With --diff, also edit the
33 diff.
34
35 The 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
42 If --diff was specified, the diff appears at the bottom, after a
43 separator:
44
45   ---
46
47   Diff text
48
49 Command-line options can be used to modify specific information
50 without invoking the editor. (With the --edit option, the editor is
51 invoked even if such command-line options are given.)
52
53 If the patch diff is edited but does not apply, no changes are made to
54 the patch at all. The edited patch is saved to a file which you can
55 feed to "stg edit --file", once you have made sure it does apply."""
56
57 args = [argparse.applied_patches, argparse.unapplied_patches,
58         argparse.hidden_patches]
59 options = [
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_committer_options() + argparse.diff_opts_option())
67
68 directory = common.DirectoryHasRepositoryLib()
69
70 def 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 = options.committer,
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)
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()