Subject: [StGIT PATCH 1/5] Make the "name" argument to "stg new" optional

From: Karl Hasselström <[email-masked]>
Date: Fri, 11 May 2007 03:40:05 +0200

From: Karl Hasselström <[email-masked]>

If no name is given, one is generated from the commit message. This
can be very handy.

Signed-off-by: Karl Hasselström <[email-masked]>
---

 Documentation/stg-new.txt  |    5 +++--
 stgit/commands/common.py   |   25 -------------------------
 stgit/commands/new.py      |   15 +++++++++++----
 stgit/commands/pick.py     |    2 +-
 stgit/commands/uncommit.py |    3 +--
 stgit/stack.py             |   17 +++++++++++------
 stgit/utils.py             |   27 ++++++++++++++++++++++++++-
 t/t1003-new.sh             |   29 +++++++++++++++++++++++++++++
 8 files changed, 82 insertions(+), 41 deletions(-)

diff --git a/Documentation/stg-new.txt b/Documentation/stg-new.txt
index 009659a..fbf2f67 100644
--- a/Documentation/stg-new.txt
+++ b/Documentation/stg-new.txt
@@ -10,7 +10,7 @@ stg-new - stgdesc:new[]
 SYNOPSIS
 --------
 [verse]
-'stg' new [OPTIONS] <name>
+'stg' new [OPTIONS] [name]
 
 DESCRIPTION
 -----------
@@ -22,7 +22,8 @@ tree are not included in the patch. A stglink:refresh[] command is
 needed for this.
 
 The given <name> must be unique in the stack, and may only contain
-alphanumeric characters, dashes and underscores.
+alphanumeric characters, dashes and underscores. If no name is given,
+one is generated from the first line of the commit message.
 
 An editor will be launched to edit the commit message to be used for
 the patch, unless the '--message' flag already specified one.  The
diff --git a/stgit/commands/common.py b/stgit/commands/common.py
index 674d8c1..28026da 100644
--- a/stgit/commands/common.py
+++ b/stgit/commands/common.py
@@ -323,31 +323,6 @@ def address_or_alias(addr_str):
                  for addr in addr_str.split(',')]
     return ', '.join([addr for addr in addr_list if addr])
 
-def patch_name_from_msg(msg):
-    """Return a string to be used as a patch name. This is generated
-    from the first 30 characters of the top line of the string passed
-    as argument."""
-    if not msg:
-        return None
-
-    subject_line = msg[:30].lstrip().split('\n', 1)[0].lower()
-    return re.sub('[\W]+', '-', subject_line).strip('-')
-
-def make_patch_name(msg, unacceptable, default_name = 'patch',
-                    alternative = True):
-    """Return a patch name generated from the given commit message,
-    guaranteed to make unacceptable(name) be false. If the commit
-    message is empty, base the name on default_name instead."""
-    patchname = patch_name_from_msg(msg)
-    if not patchname:
-        patchname = default_name
-    if alternative and unacceptable(patchname):
-        suffix = 0
-        while unacceptable('%s-%d' % (patchname, suffix)):
-            suffix += 1
-        patchname = '%s-%d' % (patchname, suffix)
-    return patchname
-
 def prepare_rebase(real_rebase, force=None):
     if not force:
         # Be sure we won't loose results of stg-(un)commit by error.
diff --git a/stgit/commands/new.py b/stgit/commands/new.py
index 2c1e94b..f192e34 100644
--- a/stgit/commands/new.py
+++ b/stgit/commands/new.py
@@ -25,7 +25,7 @@ from stgit import stack, git

 help = 'create a new patch and make it the topmost one'
-usage = """%prog [options] <name>
+usage = """%prog [options] [name]
 
 Create a new, empty patch and make it the topmost one. If the
 '--message' option is not passed, an editor is invoked with the
@@ -33,7 +33,10 @@ Create a new, empty patch and make it the topmost one. If the
 /usr/share/stgit/templates/patchdescr.tmpl file used a as template,
 together with generated lines. By default, the local changes in the
 working tree are not included in the patch. A 'refresh' command is
-needed for this."""
+needed for this.
+
+If no name is given for the new patch, one is generated from the first
+line of the commit message."""
 
 options = [make_option('-m', '--message',
                        help = 'use MESSAGE as the patch description'),
@@ -57,7 +60,11 @@ options = [make_option('-m', '--message',
 def func(parser, options, args):
     """Creates a new patch
     """
-    if len(args) != 1:
+    if len(args) == 0:
+        name = None # autogenerate a name
+    elif len(args) == 1:
+        name = args[0]
+    else:
         parser.error('incorrect number of arguments')
 
     check_conflicts()
@@ -66,7 +73,7 @@ def func(parser, options, args):
     if options.author:
         options.authname, options.authemail = name_email(options.author)
 
-    crt_series.new_patch(args[0], message = options.message,
+    crt_series.new_patch(name, message = options.message,
                          show_patch = options.showpatch,
                          author_name = options.authname,
                          author_email = options.authemail,
diff --git a/stgit/commands/pick.py b/stgit/commands/pick.py
index edd614d..75def2a 100644
--- a/stgit/commands/pick.py
+++ b/stgit/commands/pick.py
@@ -75,7 +75,7 @@ def func(parser, options, args):
         elif len(patch_branch) == 2:
             patch = patch_branch[0]
         else:
-            patch = make_patch_name(commit.get_log(), crt_series.patch_exists)
+            patch = None
 
     if options.parent:
         parent = git_id(options.parent)
diff --git a/stgit/commands/uncommit.py b/stgit/commands/uncommit.py
index 462846c..04c7e52 100644
--- a/stgit/commands/uncommit.py
+++ b/stgit/commands/uncommit.py
@@ -95,8 +95,7 @@ def func(parser, options, args):
         if patchnames:
             patchname = patchnames[n]
         else:
-            patchname = make_patch_name(commit.get_log(),
-                                        crt_series.patch_exists)
+            patchname = None
 
         crt_series.new_patch(patchname,
                              can_edit = False, before_existing = True,
diff --git a/stgit/stack.py b/stgit/stack.py
index 76704e8..d0008bc 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -777,20 +777,25 @@ class Series(StgitObject):
                   before_existing = False, refresh = True):
         """Creates a new patch
         """
-        self.__patch_name_valid(name)
 
-        if self.patch_applied(name) or self.patch_unapplied(name):
-            raise StackException, 'Patch "%s" already exists' % name
+        if name != None:
+            self.__patch_name_valid(name)
+            if self.patch_applied(name) or self.patch_unapplied(name):
+                raise StackException, 'Patch "%s" already exists' % name
 
         if not message and can_edit:
-            descr = edit_file(self, None, \
-                              'Please enter the description for patch "%s" ' \
-                              'above.' % name, show_patch)
+            descr = edit_file(
+                self, None,
+                'Please enter the description for the patch above.',
+                show_patch)
         else:
             descr = message
 
         head = git.get_head()
 
+        if name == None:
+            name = make_patch_name(descr, self.patch_exists)
+
         patch = Patch(name, self.__patch_dir, self.__refs_dir)
         patch.create()
 
diff --git a/stgit/utils.py b/stgit/utils.py
index d04d077..18198c0 100644
--- a/stgit/utils.py
+++ b/stgit/utils.py
@@ -1,7 +1,7 @@
 """Common utility functions
 """
 
-import errno, os, os.path, sys
+import errno, os, os.path, re, sys
 from stgit.config import config
 
 __copyright__ = """
@@ -172,3 +172,28 @@ def call_editor(filename):
     if err:
         raise EditorException, 'editor failed, exit code: %d' % err
     print 'done'
+
+def patch_name_from_msg(msg):
+    """Return a string to be used as a patch name. This is generated
+    from the first 30 characters of the top line of the string passed
+    as argument."""
+    if not msg:
+        return None
+
+    subject_line = msg[:30].lstrip().split('\n', 1)[0].lower()
+    return re.sub('[\W]+', '-', subject_line).strip('-')
+
+def make_patch_name(msg, unacceptable, default_name = 'patch',
+                    alternative = True):
+    """Return a patch name generated from the given commit message,
+    guaranteed to make unacceptable(name) be false. If the commit
+    message is empty, base the name on default_name instead."""
+    patchname = patch_name_from_msg(msg)
+    if not patchname:
+        patchname = default_name
+    if alternative and unacceptable(patchname):
+        suffix = 0
+        while unacceptable('%s-%d' % (patchname, suffix)):
+            suffix += 1
+        patchname = '%s-%d' % (patchname, suffix)
+    return patchname
diff --git a/t/t1003-new.sh b/t/t1003-new.sh
new file mode 100755
index 0000000..0be5d9b
--- /dev/null
+++ b/t/t1003-new.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Karl Hasselström
+#
+
+test_description='Test the new command.
+
+'
+
+. ./test-lib.sh
+
+test_expect_success \
+    'Initialize the StGIT repository' '
+    stg init
+'
+
+test_expect_success \
+    'Create a named patch' '
+    stg new foo -m foobar &&
+    [ $(stg applied -c) -eq 1 ]
+'
+
+test_expect_success \
+    'Create a patch without giving a name' '
+    stg new -m yo &&
+    [ $(stg applied -c) -eq 2 ]
+'
+
+test_done