Commit | Line | Data |
---|---|---|
ef954fe6 KH |
1 | """This module contains utility functions for patch editing.""" |
2 | ||
3 | from stgit import utils | |
4 | from stgit.commands import common | |
5 | from stgit.lib import git | |
6 | ||
7 | def 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 | ||
32 | def 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 | ||
58 | def 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 | ||
71 | def 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 |