stg import now extracts Message-ID header
[stgit.git] / stgit / commands / edit.py
blobe1e3700cf74c123e9415d241a41b405f74d55b93
1 """Patch editing command"""
3 from stgit import argparse, utils
4 from stgit.argparse import opt
5 from stgit.commands.common import (
6 CmdException,
7 DirectoryHasRepository,
8 run_commit_msg_hook,
10 from stgit.config import config
11 from stgit.lib import edit
13 __copyright__ = """
14 Copyright (C) 2007, Catalin Marinas <catalin.marinas@gmail.com>
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License version 2 as
18 published by the Free Software Foundation.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, see http://www.gnu.org/licenses/.
27 """
29 help = 'Edit a patch description or diff'
30 kind = 'patch'
31 usage = ['[options] [--] [<patch>]']
32 description = """
33 Edit the description and author information of the given patch (or the
34 current patch if no patch name was given). With --diff, also edit the
35 diff.
37 The editor is invoked with the following contents:
39 From: A U Thor <author@example.com>
40 Date: creation date
42 Patch description
44 If --diff was specified, the diff appears at the bottom, after a
45 separator:
47 ---
49 Diff text
51 Command-line options can be used to modify specific information
52 without invoking the editor. (With the --edit option, the editor is
53 invoked even if such command-line options are given.)
55 If the patch diff is edited but does not apply, no changes are made to
56 the patch at all. The edited patch is saved to a file which you can
57 feed to "stg edit --file", once you have made sure it does apply.
59 With --set-tree you set the git tree of the patch to the specified
60 TREE-ISH without changing the tree of any other patches. When used on
61 the top patch, the index and work tree will be updated to match the
62 tree. This low-level option is primarily meant to be used by tools
63 built on top of StGit, such as the Emacs mode. See also the --set-tree
64 flag of stg push."""
66 args = ['applied_patches', 'unapplied_patches', 'hidden_patches']
67 options = [
68 opt('-d', '--diff', action='store_true', short='Edit the patch diff'),
69 opt('-e', '--edit', action='store_true', short='Invoke interactive editor'),
71 options.extend(argparse.trailer_options())
72 options.extend(argparse.message_options(save_template=True))
73 options.extend(argparse.hook_options())
74 options.extend(argparse.author_options())
75 options.extend(argparse.diff_opts_option())
76 options.append(
77 opt(
78 '-t',
79 '--set-tree',
80 action='store',
81 metavar='TREE-ISH',
82 short='Set the git tree of the patch to TREE-ISH',
87 directory = DirectoryHasRepository()
90 def func(parser, options, args):
91 """Edit the given patch or the current one."""
92 stack = directory.repository.current_stack
94 if len(args) == 0:
95 if not stack.patchorder.applied:
96 raise CmdException('Cannot edit top patch because no patches are applied')
97 patchname = stack.patchorder.applied[-1]
98 elif len(args) == 1:
99 [patchname] = args
100 if patchname not in stack.patches:
101 raise CmdException('%s: no such patch' % patchname)
102 else:
103 parser.error('Cannot edit more than one patch')
105 cd = orig_cd = stack.patches[patchname].data
107 if options.set_tree:
108 cd = cd.set_tree(
109 stack.repository.rev_parse(
110 options.set_tree, discard_stderr=True, object_type='tree'
114 cd = edit.auto_edit_patch(
115 stack.repository,
117 msg=(
118 None
119 if options.message is None
120 else options.message.encode(config.get('i18n.commitencoding'))
122 author=options.author,
123 trailers=options.trailers,
126 if options.save_template:
127 options.save_template(
128 edit.get_patch_description(
129 stack.repository, cd, patchname, options.diff, options.diff_flags
132 return utils.STGIT_SUCCESS
134 use_editor = cd == orig_cd or options.edit or options.diff
135 if use_editor:
136 cd, new_patchname, failed_diff = edit.interactive_edit_patch(
137 stack.repository, cd, patchname, options.diff, options.diff_flags
139 # If we couldn't apply the patch, fail without even trying to
140 # affect any of the changes.
141 if failed_diff is not None:
142 return utils.STGIT_COMMAND_ERROR
143 else:
144 new_patchname = None
146 if not options.no_verify and (use_editor or cd.message != orig_cd.message):
147 try:
148 cd = run_commit_msg_hook(stack.repository, cd, use_editor)
149 except Exception:
150 if options.diff:
151 patch_desc = edit.get_patch_description(
152 stack.repository, cd, patchname, options.diff, options.diff_flags
154 edit.note_patch_application_failure(
155 patch_desc, 'The commit-msg hook failed.'
157 raise
159 retval, _ = edit.perform_edit(
160 stack,
162 patchname,
163 new_patchname,
164 options.diff,
165 options.diff_flags,
166 options.set_tree,
168 return retval