Stgit: allow importing series files where patch names include slashes
[stgit] / stgit / commands / imprt.py
index 6ccdcc9..c8cf42b 100644 (file)
@@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-import sys, os
+import sys, os, re
 from optparse import OptionParser, make_option
 
 from stgit.commands.common import *
 from optparse import OptionParser, make_option
 
 from stgit.commands.common import *
@@ -28,7 +28,7 @@ usage = """%prog [options] [<file>]
 
 Create a new patch and apply the given GNU diff file (or the standard
 input). By default, the file name is used as the patch name but this
 
 Create a new patch and apply the given GNU diff file (or the standard
 input). By default, the file name is used as the patch name but this
-can be overriden with the '--name' option. The patch can either be a
+can be overridden with the '--name' option. The patch can either be a
 normal file with the description at the top or it can have standard
 mail format, the Subject, From and Date headers being used for
 generating the patch information.
 normal file with the description at the top or it can have standard
 mail format, the Subject, From and Date headers being used for
 generating the patch information.
@@ -41,12 +41,24 @@ options = [make_option('-m', '--mail',
                        action = 'store_true'),
            make_option('-n', '--name',
                        help = 'use NAME as the patch name'),
                        action = 'store_true'),
            make_option('-n', '--name',
                        help = 'use NAME as the patch name'),
+           make_option('-t', '--strip',
+                       help = 'strip numbering and extension from patch name',
+                       action = 'store_true'),
+           make_option('-s', '--series',
+                       help = 'import a series of patches',
+                       action = 'store_true'),
+           make_option('-i', '--ignore',
+                       help = 'ignore the applied patches in the series',
+                       action = 'store_true'),
+           make_option('--replace',
+                       help = 'replace the unapplied patches in the series',
+                       action = 'store_true'),
            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('-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',
+           make_option('-p', '--showpatch',
                        help = 'show the patch content in the editor buffer',
                        action = 'store_true'),
            make_option('-a', '--author', metavar = '"NAME <EMAIL>"',
                        help = 'show the patch content in the editor buffer',
                        action = 'store_true'),
            make_option('-a', '--author', metavar = '"NAME <EMAIL>"',
@@ -67,6 +79,17 @@ def __end_descr(line):
     return re.match('---\s*$', line) or re.match('diff -', line) or \
             re.match('Index: ', line)
 
     return re.match('---\s*$', line) or re.match('diff -', line) or \
             re.match('Index: ', line)
 
+def __strip_patch_name(name):
+    stripped = re.sub('^[0-9]+-(.*)$', '\g<1>', name)
+    stripped = re.sub('^(.*)\.(diff|patch)$', '\g<1>', stripped)
+
+    return stripped
+
+def __replace_slashes_with_dashes(name):
+    stripped = name.replace('/', '-')
+
+    return stripped
+
 def __parse_description(descr):
     """Parse the patch description and return the new description and
     author information (if any).
 def __parse_description(descr):
     """Parse the patch description and return the new description and
     author information (if any).
@@ -199,28 +222,9 @@ def __parse_patch(filename = None):
     # Just return None
     return (descr, authname, authemail, authdate)
 
     # Just return None
     return (descr, authname, authemail, authdate)
 
-def func(parser, options, args):
-    """Import a GNU diff file as a new patch
+def __import_patch(patch, filename, options):
+    """Import a patch from a file or standard input
     """
     """
-    if len(args) > 1:
-        parser.error('incorrect number of arguments')
-
-    check_local_changes()
-    check_conflicts()
-    check_head_top_equal()
-
-    if len(args) == 1:
-        filename = args[0]
-    else:
-        filename = None
-
-    if options.name:
-        patch = options.name
-    elif filename:
-        patch = os.path.basename(filename)
-    else:
-        raise CmdException, 'Unkown patch name'
-
     # the defaults
     message = author_name = author_email = author_date = committer_name = \
               committer_email = None
     # the defaults
     message = author_name = author_email = author_date = committer_name = \
               committer_email = None
@@ -235,6 +239,11 @@ def func(parser, options, args):
         message, author_name, author_email, author_date = \
                  __parse_patch(filename)
 
         message, author_name, author_email, author_date = \
                  __parse_patch(filename)
 
+    if not patch:
+        patch = make_patch_name(message)
+        if not patch:
+            raise CmdException, 'Unknown patch name'
+
     # refresh_patch() will invoke the editor in this case, with correct
     # patch content
     if not message:
     # refresh_patch() will invoke the editor in this case, with correct
     # patch content
     if not message:
@@ -252,6 +261,9 @@ def func(parser, options, args):
     if options.commemail:
         committer_email = options.commemail
 
     if options.commemail:
         committer_email = options.commemail
 
+    if options.replace and patch in crt_series.get_unapplied():
+        crt_series.delete_patch(patch)
+
     crt_series.new_patch(patch, message = message, can_edit = False,
                          author_name = author_name,
                          author_email = author_email,
     crt_series.new_patch(patch, message = message, can_edit = False,
                          author_name = author_name,
                          author_email = author_email,
@@ -259,7 +271,7 @@ def func(parser, options, args):
                          committer_name = committer_name,
                          committer_email = committer_email)
 
                          committer_name = committer_name,
                          committer_email = committer_email)
 
-    print 'Importing patch %s...' % patch,
+    print 'Importing patch "%s"...' % patch,
     sys.stdout.flush()
 
     if options.base:
     sys.stdout.flush()
 
     if options.base:
@@ -271,4 +283,61 @@ def func(parser, options, args):
                              show_patch = options.showpatch)
 
     print 'done'
                              show_patch = options.showpatch)
 
     print 'done'
+
+def __import_series(filename, options):
+    """Import a series of patches
+    """
+    applied = crt_series.get_applied()
+
+    if filename:
+        f = file(filename)
+        patchdir = os.path.dirname(filename)
+    else:
+        f = sys.stdin
+        patchdir = ''
+
+    for line in f:
+        patch = re.sub('#.*$', '', line).strip()
+        if not patch:
+            continue
+        patchfile = os.path.join(patchdir, patch)
+
+        if options.strip:
+            patch = __strip_patch_name(patch)
+        patch = __replace_slashes_with_dashes(patch);
+        if options.ignore and patch in applied:
+            print 'Ignoring already applied patch "%s"' % patch
+            continue
+
+        __import_patch(patch, patchfile, options)
+
+def func(parser, options, args):
+    """Import a GNU diff file as a new patch
+    """
+    if len(args) > 1:
+        parser.error('incorrect number of arguments')
+
+    check_local_changes()
+    check_conflicts()
+    check_head_top_equal()
+
+    if len(args) == 1:
+        filename = args[0]
+    else:
+        filename = None
+
+    if options.series:
+        __import_series(filename, options)
+    else:
+        if options.name:
+            patch = options.name
+        elif filename:
+            patch = os.path.basename(filename)
+        else:
+            patch = ''
+        if options.strip:
+            patch = __strip_patch_name(patch)
+
+        __import_patch(patch, filename, options)
+
     print_crt_patch()
     print_crt_patch()