# HG changeset patch # User Greg Ward # Date 1317177527 14400 # Node ID 7bddec63282156b1054ae155660841d3e35e4d1f # Parent d67a15b2e6080d6b0a7a89a386af0772dceafd09 patchbomb: make it easy for the user to decline sending an intro message. - prompt(): respect interactive mode; clarify logic a bit - rename introneeded() to introwanted() and give it only one caller - add 'numbered' arg to makepatch() so it does not need to call introwanted() - factor makeintro() out of getpatchmsgs(), so it's easier to skip the intro message based on the user's behaviour Unexpected but perfectly reasonable side effect: in non-interactive mode, we don't show unanswerable "Cc" or "From" prompts anymore, so remove those from the test expectations. diff -r d67a15b2e608 -r 7bddec632821 hgext/patchbomb.py --- a/hgext/patchbomb.py Mon Sep 26 21:29:13 2011 -0400 +++ b/hgext/patchbomb.py Tue Sep 27 22:38:47 2011 -0400 @@ -57,24 +57,25 @@ command = cmdutil.command(cmdtable) def prompt(ui, prompt, default=None, rest=':'): - if not ui.interactive() and default is None: - raise util.Abort(_("%s Please enter a valid value" % (prompt + rest))) + if not ui.interactive(): + return default if default: prompt += ' [%s]' % default prompt += rest while True: - r = ui.prompt(prompt, default=default) - if r: - return r - if default is not None: + result = ui.prompt(prompt, default=default) + if result is not None: + return result + elif default is not None: return default - ui.warn(_('Please enter a valid value.\n')) + else: + ui.warn(_('Please enter a valid value.\n')) -def introneeded(opts, number): - '''is an introductory message required?''' +def introwanted(opts, number): + '''is an introductory message apparently wanted?''' return number > 1 or opts.get('intro') or opts.get('desc') -def makepatch(ui, repo, patchlines, opts, _charsets, idx, total, +def makepatch(ui, repo, patchlines, opts, _charsets, idx, total, numbered, patchname=None): desc = [] @@ -141,7 +142,7 @@ flag = ' ' + flag subj = desc[0].strip().rstrip('. ') - if not introneeded(opts, total): + if not numbered: subj = '[PATCH%s] %s' % (flag, opts.get('subject') or subj) else: tlen = len(str(total)) @@ -352,51 +353,66 @@ ui.write(_('\nWrite the introductory message for the ' 'patch series.\n\n')) body = ui.edit(body, sender) - # Save serie description in case sendmail fails + # Save series description in case sendmail fails msgfile = repo.opener('last-email.txt', 'wb') msgfile.write(body) msgfile.close() return body def getpatchmsgs(patches, patchnames=None): - jumbo = [] msgs = [] ui.write(_('This patch series consists of %d patches.\n\n') % len(patches)) + # build the intro message, or skip it if the user declines + if introwanted(opts, len(patches)): + msg = makeintro(patches) + if msg: + msgs.append(msg) + + # are we going to send more than one message? + numbered = len(msgs) + len(patches) > 1 + + # now generate the actual patch messages name = None for i, p in enumerate(patches): - jumbo.extend(p) if patchnames: name = patchnames[i] msg = makepatch(ui, repo, p, opts, _charsets, i + 1, - len(patches), name) + len(patches), numbered, name) msgs.append(msg) - if introneeded(opts, len(patches)): - tlen = len(str(len(patches))) + return msgs + + def makeintro(patches): + tlen = len(str(len(patches))) - flag = ' '.join(opts.get('flag')) - if flag: - subj = '[PATCH %0*d of %d %s]' % (tlen, 0, len(patches), flag) - else: - subj = '[PATCH %0*d of %d]' % (tlen, 0, len(patches)) - subj += ' ' + (opts.get('subject') or - prompt(ui, 'Subject: ', rest=subj)) + flag = opts.get('flag') or '' + if flag: + flag = ' ' + ' '.join(flag) + prefix = '[PATCH %0*d of %d%s]' % (tlen, 0, len(patches), flag) + + subj = (opts.get('subject') or + prompt(ui, 'Subject: ', rest=prefix, default='')) + if not subj: + return None # skip intro if the user doesn't bother - body = '' - ds = patch.diffstat(jumbo) - if ds and opts.get('diffstat'): - body = '\n' + ds + subj = prefix + ' ' + subj - body = getdescription(body, sender) - msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) - msg['Subject'] = mail.headencode(ui, subj, _charsets, - opts.get('test')) + body = '' + if opts.get('diffstat'): + # generate a cumulative diffstat of the whole patch series + diffstat = patch.diffstat(sum(patches, [])) + body = '\n' + diffstat + else: + diffstat = None - msgs.insert(0, (msg, subj, ds)) - return msgs + body = getdescription(body, sender) + msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) + msg['Subject'] = mail.headencode(ui, subj, _charsets, + opts.get('test')) + return (msg, subj, diffstat) def getbundlemsgs(bundle): subj = (opts.get('subject') @@ -442,14 +458,19 @@ ui.config('patchbomb', configkey) or '') if not addr and ask: - addr = prompt(ui, header, default) + addr = prompt(ui, header, default=default) if addr: showaddrs.append('%s: %s' % (header, addr)) - return mail.addrlistencode(ui, [addr], _charsets, opts.get('test')) + return mail.addrlistencode(ui, [addr], _charsets, opts.get('test')) + else: + return default to = getaddrs('To', ask=True) - cc = getaddrs('Cc', ask=True, default='') - bcc = getaddrs('Bcc') + if not to: + # we can get here in non-interactive mode + raise util.Abort(_('no recipient addresses provided')) + cc = getaddrs('Cc', ask=True, default='') or [] + bcc = getaddrs('Bcc') or [] replyto = getaddrs('Reply-To') if opts.get('diffstat') or opts.get('confirm'): diff -r d67a15b2e608 -r 7bddec632821 tests/test-patchbomb.t --- a/tests/test-patchbomb.t Mon Sep 26 21:29:13 2011 -0400 +++ b/tests/test-patchbomb.t Tue Sep 27 22:38:47 2011 -0400 @@ -1469,13 +1469,70 @@ +ff2c9fa2018b15fa74b33363bda9527323e2a99f two +ff2c9fa2018b15fa74b33363bda9527323e2a99f two.diff - +no intro message in non-interactive mode $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar --in-reply-to baz \ - > -r 0:1 + > -r 0:1 | fixheaders This patch series consists of 2 patches. - abort: Subject: [PATCH 0 of 2] Please enter a valid value - [255] + + Displaying [PATCH 1 of 2] a ... + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Subject: [PATCH 1 of 2] a + X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab + Message-Id: <8580ff50825a50c8f716.60@ + In-Reply-To: + References: + User-Agent: Mercurial-patchbomb + Date: Thu, 01 Jan 1970 00:01:00 +0000 + From: quux + To: foo + Cc: bar + + # HG changeset patch + # User test + # Date 1 0 + # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab + # Parent 0000000000000000000000000000000000000000 + a + + diff -r 000000000000 -r 8580ff50825a a + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/a Thu Jan 01 00:00:01 1970 +0000 + @@ -0,0 +1,1 @@ + +a + + Displaying [PATCH 2 of 2] b ... + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Subject: [PATCH 2 of 2] b + X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9 + Message-Id: <97d72e5f12c7e84f8506.61@ + In-Reply-To: <8580ff50825a50c8f716.60@ + References: <8580ff50825a50c8f716.60@ + User-Agent: Mercurial-patchbomb + Date: Thu, 01 Jan 1970 00:01:01 +0000 + From: quux + To: foo + Cc: bar + + # HG changeset patch + # User test + # Date 2 0 + # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9 + # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab + b + + diff -r 8580ff50825a -r 97d72e5f12c7 b + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/b Thu Jan 01 00:00:02 1970 +0000 + @@ -0,0 +1,1 @@ + +b + + + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar --in-reply-to baz \ > -s test -r 0:1 | fixheaders @@ -1826,7 +1883,6 @@ $ hg email --date '1980-1-1 0:1' -m tmp.mbox -f quux -t "bar@${UUML}nicode.com" -s test -r 0 This patch series consists of 1 patches. - Cc: Writing [PATCH] test ... @@ -1871,13 +1927,11 @@ $ hg email --date '1980-1-1 0:1' -n -t foo -s test -o ../t comparing with ../t searching for changes - From [test]: test This patch series consists of 8 patches. Write the introductory message for the patch series. - Cc: Displaying [PATCH 0 of 8] test ... Content-Type: text/plain; charset="us-ascii" @@ -2145,10 +2199,8 @@ $ hg email --date '1980-1-1 0:1' -n -t foo -s test -o ../t#test comparing with ../t searching for changes - From [test]: test This patch series consists of 1 patches. - Cc: Displaying [PATCH] test ... Content-Type: text/plain; charset="us-ascii"