Make StGIT comply with the author information retrieving
[stgit] / stgit / commands / imprt.py
index 9dccaf9..3759722 100644 (file)
@@ -34,17 +34,21 @@ mail format, the Subject, From and Date headers being used for
 generating the patch information.
 
 The patch description has to be separated from the data with a '---'
-line. For a normal file, if no author information is given, the first
-'Signed-off-by:' line is used."""
+line."""
 
 options = [make_option('-m', '--mail',
                        help = 'import the patch from a standard e-mail file',
                        action = 'store_true'),
            make_option('-n', '--name',
                        help = 'use NAME as the patch name'),
+           make_option('-b', '--base',
+                       help = 'use BASE instead of HEAD for file importing'),
            make_option('-e', '--edit',
                        help = 'invoke an editor for the patch description',
                        action = 'store_true'),
+           make_option('-s', '--showpatch',
+                       help = 'show the patch content in the editor buffer',
+                       action = 'store_true'),
            make_option('-a', '--author', metavar = '"NAME <EMAIL>"',
                        help = 'use "NAME <EMAIL>" as the author details'),
            make_option('--authname',
@@ -59,6 +63,46 @@ options = [make_option('-m', '--mail',
                        help = 'use COMMEMAIL as the committer e-mail')]
 
 
+def __end_descr(line):
+    return re.match('---\s*$', line) or re.match('diff -', line) or \
+            re.match('Index: ', line)
+
+def __parse_description(descr):
+    """Parse the patch description and return the new description and
+    author information (if any).
+    """
+    subject = body = ''
+    authname = authemail = None
+
+    descr_lines = [line.strip() for line in descr.split('\n')]
+    if not descr_lines:
+        raise CmdException, "Empty patch description"
+
+    pos = 1
+    end = len(descr_lines)
+
+    # get the subject
+    subject = descr_lines[0]
+
+    # ignore the empty lines after subject
+    while pos < end and descr_lines[pos] == '':
+        pos += 1
+
+    # check for a "From:" line
+    if pos < end and re.match('from:\s+', descr_lines[pos], re.I):
+        auth = re.findall('^.*?:\s+(.*)$', descr_lines[pos])[0]
+        authname, authemail = name_email(auth)
+        pos += 1
+
+        # ignore the empty lines
+        while pos < end and descr_lines[pos] == '':
+            pos += 1
+
+    # get the body
+    body = reduce(lambda x, y: x + '\n' + y, descr_lines[pos:], '').strip()
+
+    return (subject + '\n\n' + body, authname, authemail)
+
 def __parse_mail(filename = None):
     """Parse the input file in a mail format and return (description,
     authname, authemail, authdate)
@@ -71,7 +115,10 @@ def __parse_mail(filename = None):
     descr = authname = authemail = authdate = None
 
     # parse the headers
-    for line in f:
+    while True:
+        line = f.readline()
+        if not line:
+            break
         line = line.strip()
         if re.match('from:\s+', line, re.I):
             auth = re.findall('^.*?:\s+(.*)$', line)[0]
@@ -86,14 +133,18 @@ def __parse_mail(filename = None):
 
     # remove the '[*PATCH*]' expression in the subject
     if descr:
-        descr = re.findall('^(\[[^\s]*PATCH.*?\])?\s*(.*)$', descr)[0][1]
+        descr = re.findall('^(\[[^\s]*[Pp][Aa][Tt][Cc][Hh].*?\])?\s*(.*)$',
+                           descr)[0][1]
         descr += '\n\n'
     else:
         raise CmdException, 'Subject: line not found'
 
     # the rest of the patch description
-    for line in f:
-        if re.match('---\s*$', line) or re.match('diff -', line):
+    while True:
+        line = f.readline()
+        if not line:
+            break
+        if __end_descr(line):
             break
         else:
             descr += line
@@ -102,6 +153,13 @@ def __parse_mail(filename = None):
     if filename:
         f.close()
 
+    # parse the description for author information
+    descr, descr_authname, descr_authemail = __parse_description(descr)
+    if descr_authname:
+        authname = descr_authname
+    if descr_authemail:
+        authemail = descr_authemail
+
     return (descr, authname, authemail, authdate)
 
 def __parse_patch(filename = None):
@@ -113,28 +171,26 @@ def __parse_patch(filename = None):
     else:
         f = sys.stdin
 
-    authname = authemail = authdate = None
-
     descr = ''
-    for line in f:
-        # the first 'Signed-of-by:' is the author
-        if not authname and re.match('signed-off-by:\s+', line, re.I):
-            auth = re.findall('^.*?:\s+(.*)$', line)[0]
-            authname, authemail = name_email(auth)
+    while True:
+        line = f.readline()
+        if not line:
+            break
 
-        if re.match('---\s*$', line) or re.match('diff -', line):
+        if __end_descr(line):
             break
         else:
             descr += line
     descr.rstrip()
 
-    if descr == '':
-        descr = None
-
     if filename:
         f.close()
 
-    return (descr, authname, authemail, authdate)
+    descr, authname, authemail = __parse_description(descr)
+
+    # we don't yet have an agreed place for the creation date.
+    # Just return None
+    return (descr, authname, authemail, None)
 
 def func(parser, options, args):
     """Import a GNU diff file as a new patch
@@ -172,9 +228,10 @@ def func(parser, options, args):
         message, author_name, author_email, author_date = \
                  __parse_patch(filename)
 
-    # new_patch() will invoke the editor in this case
+    # refresh_patch() will invoke the editor in this case, with correct
+    # patch content
     if not message:
-        edit = False
+        can_edit = False
 
     # override the automatically parsed settings
     if options.authname:
@@ -188,7 +245,7 @@ def func(parser, options, args):
     if options.commemail:
         committer_email = options.commemail
 
-    crt_series.new_patch(patch, message = message,
+    crt_series.new_patch(patch, message = message, can_edit = False,
                          author_name = author_name,
                          author_email = author_email,
                          author_date = author_date,
@@ -198,8 +255,13 @@ def func(parser, options, args):
     print 'Importing patch %s...' % patch,
     sys.stdout.flush()
 
-    git.apply_patch(filename)
-    crt_series.refresh_patch(edit = options.edit)
+    if options.base:
+        git.apply_patch(filename, git_id(options.base))
+    else:
+        git.apply_patch(filename)
+
+    crt_series.refresh_patch(edit = options.edit,
+                             show_patch = options.showpatch)
 
     print 'done'
     print_crt_patch()