Merge branch 'stable'
[stgit] / stgit / commands / refresh.py
index 306e7b3..4695c62 100644 (file)
@@ -21,97 +21,120 @@ from optparse import OptionParser, make_option
 
 from stgit.commands.common import *
 from stgit.utils import *
+from stgit.out import *
 from stgit import stack, git
 from stgit.config import config
 
 
 help = 'generate a new commit for the current patch'
-usage = """%prog [options] [<files...>]
+usage = """%prog [options] [<files or dirs>]
 
 Include the latest tree changes in the current patch. This command
 generates a new GIT commit object with the patch details, the previous
-one no longer being visible. The patch attributes like author,
-committer and description can be changed with the command line
-options. The '--force' option is useful when a commit object was
-created with a different tool but the changes need to be included in
-the current patch."""
+one no longer being visible. The '--force' option is useful
+when a commit object was created with a different tool
+but the changes need to be included in the current patch."""
 
+directory = DirectoryHasRepository()
 options = [make_option('-f', '--force',
                        help = 'force the refresh even if HEAD and '\
                        'top differ',
                        action = 'store_true'),
-           make_option('-e', '--edit',
-                       help = 'invoke an editor for the patch '\
-                       'description',
+           make_option('--update',
+                       help = 'only update the current patch files',
                        action = 'store_true'),
-           make_option('-s', '--showpatch',
-                       help = 'show the patch content in the editor buffer',
+           make_option('--index',
+                       help = 'use the current contents of the index instead of looking at the working directory',
                        action = 'store_true'),
            make_option('--undo',
                        help = 'revert the commit generated by the last refresh',
                        action = 'store_true'),
-           make_option('-m', '--message',
-                       help = 'use MESSAGE as the patch ' \
-                       'description'),
-           make_option('-a', '--author', metavar = '"NAME <EMAIL>"',
-                       help = 'use "NAME <EMAIL>" as the author details'),
-           make_option('--authname',
-                       help = 'use AUTHNAME as the author name'),
-           make_option('--authemail',
-                       help = 'use AUTHEMAIL as the author e-mail'),
-           make_option('--authdate',
-                       help = 'use AUTHDATE as the author date'),
-           make_option('--commname',
-                       help = 'use COMMNAME as the committer name'),
-           make_option('--commemail',
-                       help = 'use COMMEMAIL as the committer ' \
-                       'e-mail')]
-
+           make_option('-a', '--annotate', metavar = 'NOTE',
+                       help = 'annotate the patch log entry'),
+           make_option('-p', '--patch',
+                       help = 'refresh (applied) PATCH instead of the top one')
+           ]
 
 def func(parser, options, args):
-    autoresolved = config.get('stgit', 'autoresolved')
+    """Generate a new commit for the current or given patch.
+    """
+    args = git.ls_files(args)
+    directory.cd_to_topdir()
 
+    autoresolved = config.get('stgit.autoresolved')
     if autoresolved != 'yes':
         check_conflicts()
 
-    patch = crt_series.get_current()
-    if not patch:
-        raise CmdException, 'No patches applied'
+    if options.patch:
+        if args or options.update:
+            raise CmdException, \
+                  'Only full refresh is available with the --patch option'
+        patch = options.patch
+        if not crt_series.patch_applied(patch):
+            raise CmdException, 'Patches "%s" not applied' % patch
+    else:
+        patch = crt_series.get_current()
+        if not patch:
+            raise CmdException, 'No patches applied'
+
+    if options.index:
+        if args or options.update:
+            raise CmdException, \
+                  'Only full refresh is available with the --index option'
+        if options.patch:
+            raise CmdException, \
+                  '--patch is not compatible with the --index option'
 
     if not options.force:
-        check_head_top_equal()
+        check_head_top_equal(crt_series)
 
     if options.undo:
-        print 'Undoing the "%s" refresh...' % patch,
-        sys.stdout.flush()
+        out.start('Undoing the refresh of "%s"' % patch)
         crt_series.undo_refresh()
-        print 'done'
+        out.done()
         return
 
-    if options.author:
-        options.authname, options.authemail = name_email(options.author)
-
-    if git.local_changes() \
-           or not crt_series.head_top_equal() \
-           or options.edit or options.message \
-           or options.authname or options.authemail or options.authdate \
-           or options.commname or options.commemail:
-        print 'Refreshing patch "%s"...' % patch,
-        sys.stdout.flush()
+    if not options.index:
+        files = [path for (stat, path) in git.tree_status(files = args, verbose = True)]
+
+    if options.index or files or not crt_series.head_top_equal():
+        if options.patch:
+            applied = crt_series.get_applied()
+            between = applied[:applied.index(patch):-1]
+            pop_patches(crt_series, between, keep = True)
+        elif options.update:
+            rev1 = git_id(crt_series, '//bottom')
+            rev2 = git_id(crt_series, '//top')
+            patch_files = git.barefiles(rev1, rev2).split('\n')
+            files = [f for f in files if f in patch_files]
+            if not files:
+                out.info('No modified files for updating patch "%s"' % patch)
+                return
+
+        out.start('Refreshing patch "%s"' % patch)
 
         if autoresolved == 'yes':
             resolved_all()
-        crt_series.refresh_patch(files = args,
-                                 message = options.message,
-                                 edit = options.edit,
-                                 show_patch = options.showpatch,
-                                 author_name = options.authname,
-                                 author_email = options.authemail,
-                                 author_date = options.authdate,
-                                 committer_name = options.commname,
-                                 committer_email = options.commemail,
-                                 backup = True)
-
-        print 'done'
+
+        if options.index:
+            crt_series.refresh_patch(cache_update = False,
+                                     backup = True, notes = options.annotate)
+        else:
+            crt_series.refresh_patch(files = files,
+                                     backup = True, notes = options.annotate)
+
+        if crt_series.empty_patch(patch):
+            out.done('empty patch')
+        else:
+            out.done()
+
+        if options.patch:
+            between.reverse()
+            push_patches(crt_series, between)
+    elif options.annotate:
+        # only annotate the top log entry as there is no need to
+        # refresh the patch and generate a full commit
+        crt_series.log_patch(crt_series.get_patch(patch), None,
+                             notes = options.annotate)
     else:
-        print 'Patch "%s" is already up to date' % patch
+        out.info('Patch "%s" is already up to date' % patch)