git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Karl Hasselström" <kha@treskal.com>
To: Catalin Marinas <catalin.marinas@gmail.com>
Cc: git@vger.kernel.org, Jakub Narebski <jnareb@gmail.com>
Subject: [StGit PATCH 1/2] Refactor stgit.commands.edit
Date: Fri, 04 Jul 2008 08:40:30 +0200	[thread overview]
Message-ID: <20080704064030.9637.95802.stgit@yoghurt> (raw)
In-Reply-To: <20080704063755.9637.23750.stgit@yoghurt>

Reorganize a few existing functions, and break out stuff from the main
function into subroutines.

While we're at it, move one of the old and all of the new functions to
stgit.lib.edit, so that we can use them in a later patch to implement
"stg refresh --edit".

Signed-off-by: Karl Hasselström <kha@treskal.com>

---

 stgit/commands/common.py |    9 +++-
 stgit/commands/edit.py   |   79 +++++--------------------------------
 stgit/commands/imprt.py  |    2 -
 stgit/lib/edit.py        |   99 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 117 insertions(+), 72 deletions(-)
 create mode 100644 stgit/lib/edit.py


diff --git a/stgit/commands/common.py b/stgit/commands/common.py
index 2689a42..c92554d 100644
--- a/stgit/commands/common.py
+++ b/stgit/commands/common.py
@@ -453,12 +453,15 @@ def parse_mail(msg):
 
     return (descr, authname, authemail, authdate, diff)
 
-def parse_patch(text):
+def parse_patch(text, contains_diff):
     """Parse the input text and return (description, authname,
     authemail, authdate, diff)
     """
-    descr, diff = __split_descr_diff(text)
-    descr, authname, authemail, authdate = __parse_description(descr)
+    if contains_diff:
+        (text, diff) = __split_descr_diff(text)
+    else:
+        diff = None
+    (descr, authname, authemail, authdate) = __parse_description(text)
 
     # we don't yet have an agreed place for the creation date.
     # Just return None
diff --git a/stgit/commands/edit.py b/stgit/commands/edit.py
index a8499c6..a9e8991 100644
--- a/stgit/commands/edit.py
+++ b/stgit/commands/edit.py
@@ -22,7 +22,7 @@ from optparse import make_option
 
 from stgit import git, utils
 from stgit.commands import common
-from stgit.lib import git as gitlib, transaction
+from stgit.lib import git as gitlib, transaction, edit
 from stgit.out import *
 
 help = 'edit a patch description or diff'
@@ -64,45 +64,6 @@ options = [make_option('-d', '--diff',
                 + utils.make_author_committer_options()
                 + utils.make_diff_opts_option())
 
-def patch_diff(repository, cd, diff, diff_flags):
-    if diff:
-        diff = repository.diff_tree(cd.parent.data.tree, cd.tree, diff_flags)
-        return '\n'.join([git.diffstat(diff), diff])
-    else:
-        return None
-
-def patch_description(cd, diff):
-    """Generate a string containing the description to edit."""
-
-    desc = ['From: %s <%s>' % (cd.author.name, cd.author.email),
-            'Date: %s' % cd.author.date.isoformat(),
-            '',
-            cd.message]
-    if diff:
-        desc += ['---',
-                 '',
-                diff]
-    return '\n'.join(desc)
-
-def patch_desc(repository, cd, failed_diff, diff, diff_flags):
-    return patch_description(cd, failed_diff or patch_diff(
-            repository, cd, diff, diff_flags))
-
-def update_patch_description(repository, cd, text):
-    message, authname, authemail, authdate, diff = common.parse_patch(text)
-    cd = (cd.set_message(message)
-            .set_author(cd.author.set_name(authname)
-                                 .set_email(authemail)
-                                 .set_date(gitlib.Date.maybe(authdate))))
-    failed_diff = None
-    if diff:
-        tree = repository.apply(cd.parent.data.tree, diff)
-        if tree == None:
-            failed_diff = diff
-        else:
-            cd = cd.set_tree(tree)
-    return cd, failed_diff
-
 def func(parser, options, args):
     """Edit the given patch or the current one.
     """
@@ -122,44 +83,26 @@ def func(parser, options, args):
 
     cd = orig_cd = stack.patches.get(patchname).commit.data
 
-    # Read patch from user-provided description.
-    if options.message == None:
-        failed_diff = None
-    else:
-        cd, failed_diff = update_patch_description(stack.repository, cd,
-                                                   options.message)
-
-    # Modify author and committer data.
-    a, c = options.author(cd.author), options.committer(cd.committer)
-    if (a, c) != (cd.author, cd.committer):
-        cd = cd.set_author(a).set_committer(c)
-
-    # Add Signed-off-by: or similar.
-    if options.sign_str != None:
-        cd = cd.set_message(utils.add_sign_line(
-                cd.message, options.sign_str, gitlib.Person.committer().name,
-                gitlib.Person.committer().email))
+    cd, failed_diff = edit.auto_edit_patch(
+        stack.repository, cd, msg = options.message, contains_diff = True,
+        author = options.author, committer = options.committer,
+        sign_str = options.sign_str)
 
     if options.save_template:
         options.save_template(
-            patch_desc(stack.repository, cd, failed_diff,
-                       options.diff, options.diff_flags))
+            patch_desc(stack.repository, cd,
+                       options.diff, options.diff_flags, failed_diff))
         return utils.STGIT_SUCCESS
 
-    # Let user edit the patch manually.
     if cd == orig_cd or options.edit:
-        fn = '.stgit-edit.' + ['txt', 'patch'][bool(options.diff)]
-        cd, failed_diff = update_patch_description(
-            stack.repository, cd, utils.edit_string(
-                patch_desc(stack.repository, cd, failed_diff,
-                           options.diff, options.diff_flags),
-                fn))
+        cd, failed_diff = edit.interactive_edit_patch(
+            stack.repository, cd, options.diff, options.diff_flags, failed_diff)
 
     def failed():
         fn = '.stgit-failed.patch'
         f = file(fn, 'w')
-        f.write(patch_desc(stack.repository, cd, failed_diff,
-                           options.diff, options.diff_flags))
+        f.write(patch_desc(stack.repository, cd,
+                           options.diff, options.diff_flags, failed_diff))
         f.close()
         out.error('Edited patch did not apply.',
                   'It has been saved to "%s".' % fn)
diff --git a/stgit/commands/imprt.py b/stgit/commands/imprt.py
index 5fb4da3..b958412 100644
--- a/stgit/commands/imprt.py
+++ b/stgit/commands/imprt.py
@@ -220,7 +220,7 @@ def __import_file(filename, options, patch = None):
                  parse_mail(msg)
     else:
         message, author_name, author_email, author_date, diff = \
-                 parse_patch(f.read())
+                 parse_patch(f.read(), contains_diff = True)
 
     if filename:
         f.close()
diff --git a/stgit/lib/edit.py b/stgit/lib/edit.py
new file mode 100644
index 0000000..6874355
--- /dev/null
+++ b/stgit/lib/edit.py
@@ -0,0 +1,99 @@
+"""This module contains utility functions for patch editing."""
+
+from stgit import utils
+from stgit.commands import common
+from stgit.lib import git
+
+def update_patch_description(repo, cd, text, contains_diff):
+    """Update the given L{CommitData<stgit.lib.git.CommitData>} with the
+    given text description, which may contain author name and time
+    stamp in addition to a new commit message. If C{contains_diff} is
+    true, it may also contain a replacement diff.
+
+    Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
+    and the diff text if it didn't apply, or C{None} otherwise."""
+    (message, authname, authemail, authdate, diff
+     ) = common.parse_patch(text, contains_diff)
+    a = cd.author
+    for val, setter in [(authname, 'set_name'), (authemail, 'set_email'),
+                        (git.Date.maybe(authdate), 'set_date')]:
+        if val != None:
+            a = getattr(a, setter)(val)
+    cd = cd.set_message(message).set_author(a)
+    failed_diff = None
+    if diff:
+        tree = repo.apply(cd.parent.data.tree, diff)
+        if tree == None:
+            failed_diff = diff
+        else:
+            cd = cd.set_tree(tree)
+    return cd, failed_diff
+
+def patch_desc(repo, cd, append_diff, diff_flags, replacement_diff):
+    """Return a description text for the patch, suitable for editing
+    and/or reimporting with L{update_patch_description()}.
+
+    @param cd: The L{CommitData<stgit.lib.git.CommitData>} to generate
+               a description of
+    @param append_diff: Whether to append the patch diff to the
+                        description
+    @type append_diff: C{bool}
+    @param diff_flags: Extra parameters to pass to C{git diff}
+    @param replacement_diff: Diff text to use; or C{None} if it should
+                             be computed from C{cd}
+    @type replacement_diff: C{str} or C{None}"""
+    desc = ['From: %s <%s>' % (cd.author.name, cd.author.email),
+            'Date: %s' % cd.author.date.isoformat(),
+            '',
+            cd.message]
+    if append_diff:
+        if replacement_diff:
+            diff = replacement_diff
+        else:
+            just_diff = repo.diff_tree(cd.parent.data.tree, cd.tree, diff_flags)
+            diff = '\n'.join([git.diffstat(just_diff), just_diff])
+        desc += ['---', '', diff]
+    return '\n'.join(desc)
+
+def interactive_edit_patch(repo, cd, edit_diff, diff_flags, replacement_diff):
+    """Edit the patch interactively. If C{edit_diff} is true, edit the
+    diff as well. If C{replacement_diff} is not C{None}, it contains a
+    diff to edit instead of the patch's real diff.
+
+    Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
+    and the diff text if it didn't apply, or C{None} otherwise."""
+    return update_patch_description(
+        repo, cd, utils.edit_string(
+            patch_desc(repo, cd, edit_diff, diff_flags, replacement_diff),
+            '.stgit-edit.' + ['txt', 'patch'][bool(edit_diff)]),
+        edit_diff)
+
+def auto_edit_patch(repo, cd, msg, contains_diff, author, committer, sign_str):
+    """Edit the patch noninteractively in a couple of ways:
+
+         - If C{msg} is not C{None}, parse it to find a replacement
+           message, and possibly also replacement author and
+           timestamp. If C{contains_diff} is true, also look for a
+           replacement diff.
+
+         - C{author} and C{committer} are two functions that take the
+           original L{Person<stgit.lib.git.Person>} value as argument,
+           and return the new one.
+
+         - C{sign_str}, if not C{None}, is a sign string to append to
+           the message.
+
+    Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
+    and the diff text if it didn't apply, or C{None} otherwise."""
+    if msg == None:
+        failed_diff = None
+    else:
+        cd, failed_diff = update_patch_description(repo, cd, msg, contains_diff)
+    a, c = author(cd.author), committer(cd.committer)
+    if (a, c) != (cd.author, cd.committer):
+        cd = cd.set_author(a).set_committer(c)
+    if sign_str != None:
+        cd = cd.set_message(utils.add_sign_line(
+                cd.message, sign_str, git.Person.committer().name,
+                git.Person.committer().email))
+    return cd, failed_diff

  reply	other threads:[~2008-07-04  6:42 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-04  6:40 [StGit PATCH 0/2] stg refresh -e/--edit Karl Hasselström
2008-07-04  6:40 ` Karl Hasselström [this message]
2008-07-04  6:40 ` [StGit PATCH 2/2] Implement "stg refresh --edit" again Karl Hasselström
2008-07-04  7:32   ` Jakub Narebski
2008-07-07 20:56   ` Catalin Marinas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080704064030.9637.95802.stgit@yoghurt \
    --to=kha@treskal.com \
    --cc=catalin.marinas@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=jnareb@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).