Release notes: Turn the 0.15-rc1 release notes into 0.15 release notes
[stgit] / stgit / lib / edit.py
CommitLineData
ef954fe6
KH
1"""This module contains utility functions for patch editing."""
2
3from stgit import utils
4from stgit.commands import common
5from stgit.lib import git
6
7def update_patch_description(repo, cd, text, contains_diff):
8 """Update the given L{CommitData<stgit.lib.git.CommitData>} with the
9 given text description, which may contain author name and time
10 stamp in addition to a new commit message. If C{contains_diff} is
11 true, it may also contain a replacement diff.
12
13 Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
14 and the diff text if it didn't apply, or C{None} otherwise."""
15 (message, authname, authemail, authdate, diff
16 ) = common.parse_patch(text, contains_diff)
17 a = cd.author
18 for val, setter in [(authname, 'set_name'), (authemail, 'set_email'),
19 (git.Date.maybe(authdate), 'set_date')]:
20 if val != None:
21 a = getattr(a, setter)(val)
22 cd = cd.set_message(message).set_author(a)
23 failed_diff = None
24 if diff:
25 tree = repo.apply(cd.parent.data.tree, diff, quiet = False)
26 if tree == None:
27 failed_diff = diff
28 else:
29 cd = cd.set_tree(tree)
30 return cd, failed_diff
31
32def patch_desc(repo, cd, append_diff, diff_flags, replacement_diff):
33 """Return a description text for the patch, suitable for editing
34 and/or reimporting with L{update_patch_description()}.
35
36 @param cd: The L{CommitData<stgit.lib.git.CommitData>} to generate
37 a description of
38 @param append_diff: Whether to append the patch diff to the
39 description
40 @type append_diff: C{bool}
41 @param diff_flags: Extra parameters to pass to C{git diff}
42 @param replacement_diff: Diff text to use; or C{None} if it should
43 be computed from C{cd}
44 @type replacement_diff: C{str} or C{None}"""
45 desc = ['From: %s <%s>' % (cd.author.name, cd.author.email),
46 'Date: %s' % cd.author.date.isoformat(),
47 '',
48 cd.message]
49 if append_diff:
50 if replacement_diff:
51 diff = replacement_diff
52 else:
53 just_diff = repo.diff_tree(cd.parent.data.tree, cd.tree, diff_flags)
54 diff = '\n'.join([git.diffstat(just_diff), just_diff])
55 desc += ['---', '', diff]
56 return '\n'.join(desc)
57
58def interactive_edit_patch(repo, cd, edit_diff, diff_flags, replacement_diff):
59 """Edit the patch interactively. If C{edit_diff} is true, edit the
60 diff as well. If C{replacement_diff} is not C{None}, it contains a
61 diff to edit instead of the patch's real diff.
62
63 Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
64 and the diff text if it didn't apply, or C{None} otherwise."""
65 return update_patch_description(
66 repo, cd, utils.edit_string(
67 patch_desc(repo, cd, edit_diff, diff_flags, replacement_diff),
68 '.stgit-edit.' + ['txt', 'patch'][bool(edit_diff)]),
69 edit_diff)
70
71def auto_edit_patch(repo, cd, msg, contains_diff, author, committer, sign_str):
72 """Edit the patch noninteractively in a couple of ways:
73
74 - If C{msg} is not C{None}, parse it to find a replacement
75 message, and possibly also replacement author and
76 timestamp. If C{contains_diff} is true, also look for a
77 replacement diff.
78
79 - C{author} and C{committer} are two functions that take the
80 original L{Person<stgit.lib.git.Person>} value as argument,
81 and return the new one.
82
83 - C{sign_str}, if not C{None}, is a sign string to append to
84 the message.
85
86 Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
87 and the diff text if it didn't apply, or C{None} otherwise."""
88 if msg == None:
89 failed_diff = None
90 else:
91 cd, failed_diff = update_patch_description(repo, cd, msg, contains_diff)
92 a, c = author(cd.author), committer(cd.committer)
93 if (a, c) != (cd.author, cd.committer):
94 cd = cd.set_author(a).set_committer(c)
95 if sign_str != None:
96 cd = cd.set_message(utils.add_sign_line(
97 cd.message, sign_str, git.Person.committer().name,
98 git.Person.committer().email))
99 return cd, failed_diff