patchbomb: let diffstat prompt only once with complete summary
authorChristian Ebert <blacktrash@gmx.net>
Fri, 10 Sep 2010 15:32:14 +0200
changeset 12200 aebb39d45500
parent 12199 17d604e522b4
child 12201 5bfa45651cf6
patchbomb: let diffstat prompt only once with complete summary This changes the behaviour of --diffstat. Before the user was asked for confirmation of each patch with its description and diffstat, and a final summary. Now there is only one prompt right before sending with a final summary which does not include the patch descriptions, but the message details and the diffstats: Final summary: From: sender To: recipient(s) Cc: (if present) Bcc: (if present) Reply-To: (if present) Subject: [patch 0 of x [flags]] intro (if present) a | 28 ++++++++++++++++++++++++++++ b | 15 +++++++++++++++ Subject: [patch 1 of x [flags]] subject a | 28 ++++++++++++++++++++++++++++ [ ... ] are you sure you want to send (yn)?
hgext/patchbomb.py
tests/test-patchbomb.t
--- a/hgext/patchbomb.py	Fri Sep 10 15:56:13 2010 +0200
+++ b/hgext/patchbomb.py	Fri Sep 10 15:32:14 2010 +0200
@@ -22,9 +22,9 @@
 and References headers, so they will show up as a sequence in threaded
 mail and news readers, and in mail archives.
 
-With the -d/--diffstat option, you will be prompted for each changeset
-with a diffstat summary and the changeset summary, so you can be sure
-you are sending the right changes.
+With the -d/--diffstat option, you will be presented with a final
+summary of all messages and asked for confirmation before the messages
+are sent.
 
 To configure other defaults, add a section like this to your hgrc
 file::
@@ -94,16 +94,6 @@
             return default
         ui.warn(_('Please enter a valid value.\n'))
 
-def cdiffstat(ui, summary, patchlines):
-    s = patch.diffstat(patchlines)
-    if summary:
-        ui.write(summary, '\n')
-        ui.write(s, '\n')
-    if ui.promptchoice(_('does the diffstat above look okay (yn)?'),
-                       (_('&Yes'), _('&No'))):
-        raise util.Abort(_('diffstat rejected'))
-    return s
-
 def introneeded(opts, number):
     '''is an introductory message required?'''
     return number > 1 or opts.get('intro') or opts.get('desc')
@@ -140,8 +130,9 @@
         while patchlines and not patchlines[0].strip():
             patchlines.pop(0)
 
+    ds = patch.diffstat(patchlines)
     if opts.get('diffstat'):
-        body += cdiffstat(ui, '\n'.join(desc), patchlines) + '\n\n'
+        body += ds + '\n\n'
 
     if opts.get('attach') or opts.get('inline'):
         msg = email.MIMEMultipart.MIMEMultipart()
@@ -181,7 +172,7 @@
         subj = '[PATCH %0*d of %d%s] %s' % (tlen, idx, total, flag, subj)
     msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
     msg['X-Mercurial-Node'] = node
-    return msg, subj
+    return msg, subj, ds
 
 def patchbomb(ui, repo, *revs, **opts):
     '''send changesets by email
@@ -351,17 +342,16 @@
                            prompt(ui, 'Subject: ', rest=subj))
 
             body = ''
-            if opts.get('diffstat'):
-                d = cdiffstat(ui, _('Final summary:\n'), jumbo)
-                if d:
-                    body = '\n' + d
+            ds = patch.diffstat(jumbo)
+            if ds and opts.get('diffstat'):
+                body = '\n' + ds
 
             body = getdescription(body, sender)
             msg = mail.mimeencode(ui, body, _charsets, opts.get('test'))
             msg['Subject'] = mail.headencode(ui, subj, _charsets,
                                              opts.get('test'))
 
-            msgs.insert(0, (msg, subj))
+            msgs.insert(0, (msg, subj, ds))
         return msgs
 
     def getbundlemsgs(bundle):
@@ -380,7 +370,7 @@
         email.Encoders.encode_base64(datapart)
         msg.attach(datapart)
         msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
-        return [(msg, subj)]
+        return [(msg, subj, None)]
 
     sender = (opts.get('from') or ui.config('email', 'from') or
               ui.config('patchbomb', 'from') or
@@ -393,9 +383,17 @@
     else:
         msgs = getpatchmsgs(list(getpatches(revs)))
 
+    showaddrs = []
+
     def getaddrs(opt, prpt=None, default=None):
         addrs = opts.get(opt.replace('-', '_'))
+        if opt != 'reply-to':
+            showaddr = '%s:' % opt.capitalize()
+        else:
+            showaddr = 'Reply-To:'
+
         if addrs:
+            showaddrs.append('%s %s' % (showaddr, ', '.join(addrs)))
             return mail.addrlistencode(ui, addrs, _charsets,
                                        opts.get('test'))
 
@@ -403,6 +401,10 @@
         if not addrs and prpt:
             addrs = prompt(ui, prpt, default)
 
+        if addrs:
+            showaddr = '%s %s' % (showaddr, addrs)
+            showaddrs.append(showaddr)
+
         return mail.addrlistencode(ui, [addrs], _charsets, opts.get('test'))
 
     to = getaddrs('to', 'To')
@@ -410,6 +412,20 @@
     bcc = getaddrs('bcc')
     replyto = getaddrs('reply-to')
 
+    if opts.get('diffstat'):
+        ui.write(_('\nFinal summary:\n\n'))
+        ui.write('From: %s\n' % sender)
+        for addr in showaddrs:
+            ui.write('%s\n' % addr)
+        for m, subj, ds in msgs:
+            ui.write('Subject: %s\n' % subj)
+            if ds:
+                ui.write(ds)
+        ui.write('\n')
+        if ui.promptchoice(_('are you sure you want to send (yn)?'),
+                           (_('&Yes'), _('&No'))):
+            raise util.Abort(_('patchbomb canceled'))
+
     ui.write('\n')
 
     parent = opts.get('in_reply_to') or None
@@ -425,7 +441,7 @@
     sender_addr = email.Utils.parseaddr(sender)[1]
     sender = mail.addressencode(ui, sender, _charsets, opts.get('test'))
     sendmail = None
-    for m, subj in msgs:
+    for m, subj, ds in msgs:
         try:
             m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
         except TypeError:
--- a/tests/test-patchbomb.t	Fri Sep 10 15:56:13 2010 +0200
+++ b/tests/test-patchbomb.t	Fri Sep 10 15:32:14 2010 +0200
@@ -332,12 +332,17 @@
   >  fixheaders
   This patch series consists of 1 patches.
   
-  c
+  
+  Final summary:
   
+  From: quux
+  To: foo
+  Cc: bar
+  Subject: [PATCH] test
    c |  1 +
    1 files changed, 1 insertions(+), 0 deletions(-)
   
-  does the diffstat above look okay (yn)? y
+  are you sure you want to send (yn)? y
   
   Displaying [PATCH] test ...
   Content-Type: text/plain; charset="us-ascii"
@@ -375,28 +380,27 @@
   >  -r 0:1 | fixheaders
   This patch series consists of 2 patches.
   
-  a
+  
+  Write the introductory message for the patch series.
+  
+  
+  Final summary:
   
+  From: quux
+  To: foo
+  Cc: bar
+  Subject: [PATCH 0 of 2] test
+   a |  1 +
+   b |  1 +
+   2 files changed, 2 insertions(+), 0 deletions(-)
+  Subject: [PATCH 1 of 2] a
    a |  1 +
    1 files changed, 1 insertions(+), 0 deletions(-)
-  
-  does the diffstat above look okay (yn)? y
-  b
-  
+  Subject: [PATCH 2 of 2] b
    b |  1 +
    1 files changed, 1 insertions(+), 0 deletions(-)
   
-  does the diffstat above look okay (yn)? y
-  Final summary:
-  
-   a |  1 +
-   b |  1 +
-   2 files changed, 2 insertions(+), 0 deletions(-)
-  
-  does the diffstat above look okay (yn)? y
-  
-  Write the introductory message for the patch series.
-  
+  are you sure you want to send (yn)? y
   
   Displaying [PATCH 0 of 2] test ...
   Content-Type: text/plain; charset="us-ascii"