55 |
55 |
56 cmdtable = {} |
56 cmdtable = {} |
57 command = cmdutil.command(cmdtable) |
57 command = cmdutil.command(cmdtable) |
58 |
58 |
59 def prompt(ui, prompt, default=None, rest=':'): |
59 def prompt(ui, prompt, default=None, rest=':'): |
60 if not ui.interactive() and default is None: |
60 if not ui.interactive(): |
61 raise util.Abort(_("%s Please enter a valid value" % (prompt + rest))) |
61 return default |
62 if default: |
62 if default: |
63 prompt += ' [%s]' % default |
63 prompt += ' [%s]' % default |
64 prompt += rest |
64 prompt += rest |
65 while True: |
65 while True: |
66 r = ui.prompt(prompt, default=default) |
66 result = ui.prompt(prompt, default=default) |
67 if r: |
67 if result is not None: |
68 return r |
68 return result |
69 if default is not None: |
69 elif default is not None: |
70 return default |
70 return default |
71 ui.warn(_('Please enter a valid value.\n')) |
71 else: |
72 |
72 ui.warn(_('Please enter a valid value.\n')) |
73 def introneeded(opts, number): |
73 |
74 '''is an introductory message required?''' |
74 def introwanted(opts, number): |
|
75 '''is an introductory message apparently wanted?''' |
75 return number > 1 or opts.get('intro') or opts.get('desc') |
76 return number > 1 or opts.get('intro') or opts.get('desc') |
76 |
77 |
77 def makepatch(ui, repo, patchlines, opts, _charsets, idx, total, |
78 def makepatch(ui, repo, patchlines, opts, _charsets, idx, total, numbered, |
78 patchname=None): |
79 patchname=None): |
79 |
80 |
80 desc = [] |
81 desc = [] |
81 node = None |
82 node = None |
82 body = '' |
83 body = '' |
139 flag = ' '.join(opts.get('flag')) |
140 flag = ' '.join(opts.get('flag')) |
140 if flag: |
141 if flag: |
141 flag = ' ' + flag |
142 flag = ' ' + flag |
142 |
143 |
143 subj = desc[0].strip().rstrip('. ') |
144 subj = desc[0].strip().rstrip('. ') |
144 if not introneeded(opts, total): |
145 if not numbered: |
145 subj = '[PATCH%s] %s' % (flag, opts.get('subject') or subj) |
146 subj = '[PATCH%s] %s' % (flag, opts.get('subject') or subj) |
146 else: |
147 else: |
147 tlen = len(str(total)) |
148 tlen = len(str(total)) |
148 subj = '[PATCH %0*d of %d%s] %s' % (tlen, idx, total, flag, subj) |
149 subj = '[PATCH %0*d of %d%s] %s' % (tlen, idx, total, flag, subj) |
149 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) |
150 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) |
350 body = open(opts.get('desc')).read() |
351 body = open(opts.get('desc')).read() |
351 else: |
352 else: |
352 ui.write(_('\nWrite the introductory message for the ' |
353 ui.write(_('\nWrite the introductory message for the ' |
353 'patch series.\n\n')) |
354 'patch series.\n\n')) |
354 body = ui.edit(body, sender) |
355 body = ui.edit(body, sender) |
355 # Save serie description in case sendmail fails |
356 # Save series description in case sendmail fails |
356 msgfile = repo.opener('last-email.txt', 'wb') |
357 msgfile = repo.opener('last-email.txt', 'wb') |
357 msgfile.write(body) |
358 msgfile.write(body) |
358 msgfile.close() |
359 msgfile.close() |
359 return body |
360 return body |
360 |
361 |
361 def getpatchmsgs(patches, patchnames=None): |
362 def getpatchmsgs(patches, patchnames=None): |
362 jumbo = [] |
|
363 msgs = [] |
363 msgs = [] |
364 |
364 |
365 ui.write(_('This patch series consists of %d patches.\n\n') |
365 ui.write(_('This patch series consists of %d patches.\n\n') |
366 % len(patches)) |
366 % len(patches)) |
367 |
367 |
|
368 # build the intro message, or skip it if the user declines |
|
369 if introwanted(opts, len(patches)): |
|
370 msg = makeintro(patches) |
|
371 if msg: |
|
372 msgs.append(msg) |
|
373 |
|
374 # are we going to send more than one message? |
|
375 numbered = len(msgs) + len(patches) > 1 |
|
376 |
|
377 # now generate the actual patch messages |
368 name = None |
378 name = None |
369 for i, p in enumerate(patches): |
379 for i, p in enumerate(patches): |
370 jumbo.extend(p) |
|
371 if patchnames: |
380 if patchnames: |
372 name = patchnames[i] |
381 name = patchnames[i] |
373 msg = makepatch(ui, repo, p, opts, _charsets, i + 1, |
382 msg = makepatch(ui, repo, p, opts, _charsets, i + 1, |
374 len(patches), name) |
383 len(patches), numbered, name) |
375 msgs.append(msg) |
384 msgs.append(msg) |
376 |
385 |
377 if introneeded(opts, len(patches)): |
|
378 tlen = len(str(len(patches))) |
|
379 |
|
380 flag = ' '.join(opts.get('flag')) |
|
381 if flag: |
|
382 subj = '[PATCH %0*d of %d %s]' % (tlen, 0, len(patches), flag) |
|
383 else: |
|
384 subj = '[PATCH %0*d of %d]' % (tlen, 0, len(patches)) |
|
385 subj += ' ' + (opts.get('subject') or |
|
386 prompt(ui, 'Subject: ', rest=subj)) |
|
387 |
|
388 body = '' |
|
389 ds = patch.diffstat(jumbo) |
|
390 if ds and opts.get('diffstat'): |
|
391 body = '\n' + ds |
|
392 |
|
393 body = getdescription(body, sender) |
|
394 msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) |
|
395 msg['Subject'] = mail.headencode(ui, subj, _charsets, |
|
396 opts.get('test')) |
|
397 |
|
398 msgs.insert(0, (msg, subj, ds)) |
|
399 return msgs |
386 return msgs |
|
387 |
|
388 def makeintro(patches): |
|
389 tlen = len(str(len(patches))) |
|
390 |
|
391 flag = opts.get('flag') or '' |
|
392 if flag: |
|
393 flag = ' ' + ' '.join(flag) |
|
394 prefix = '[PATCH %0*d of %d%s]' % (tlen, 0, len(patches), flag) |
|
395 |
|
396 subj = (opts.get('subject') or |
|
397 prompt(ui, 'Subject: ', rest=prefix, default='')) |
|
398 if not subj: |
|
399 return None # skip intro if the user doesn't bother |
|
400 |
|
401 subj = prefix + ' ' + subj |
|
402 |
|
403 body = '' |
|
404 if opts.get('diffstat'): |
|
405 # generate a cumulative diffstat of the whole patch series |
|
406 diffstat = patch.diffstat(sum(patches, [])) |
|
407 body = '\n' + diffstat |
|
408 else: |
|
409 diffstat = None |
|
410 |
|
411 body = getdescription(body, sender) |
|
412 msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) |
|
413 msg['Subject'] = mail.headencode(ui, subj, _charsets, |
|
414 opts.get('test')) |
|
415 return (msg, subj, diffstat) |
400 |
416 |
401 def getbundlemsgs(bundle): |
417 def getbundlemsgs(bundle): |
402 subj = (opts.get('subject') |
418 subj = (opts.get('subject') |
403 or prompt(ui, 'Subject:', 'A bundle for your repository')) |
419 or prompt(ui, 'Subject:', 'A bundle for your repository')) |
404 |
420 |
440 # not on the command line: fallback to config and then maybe ask |
456 # not on the command line: fallback to config and then maybe ask |
441 addr = (ui.config('email', configkey) or |
457 addr = (ui.config('email', configkey) or |
442 ui.config('patchbomb', configkey) or |
458 ui.config('patchbomb', configkey) or |
443 '') |
459 '') |
444 if not addr and ask: |
460 if not addr and ask: |
445 addr = prompt(ui, header, default) |
461 addr = prompt(ui, header, default=default) |
446 if addr: |
462 if addr: |
447 showaddrs.append('%s: %s' % (header, addr)) |
463 showaddrs.append('%s: %s' % (header, addr)) |
448 return mail.addrlistencode(ui, [addr], _charsets, opts.get('test')) |
464 return mail.addrlistencode(ui, [addr], _charsets, opts.get('test')) |
|
465 else: |
|
466 return default |
449 |
467 |
450 to = getaddrs('To', ask=True) |
468 to = getaddrs('To', ask=True) |
451 cc = getaddrs('Cc', ask=True, default='') |
469 if not to: |
452 bcc = getaddrs('Bcc') |
470 # we can get here in non-interactive mode |
|
471 raise util.Abort(_('no recipient addresses provided')) |
|
472 cc = getaddrs('Cc', ask=True, default='') or [] |
|
473 bcc = getaddrs('Bcc') or [] |
453 replyto = getaddrs('Reply-To') |
474 replyto = getaddrs('Reply-To') |
454 |
475 |
455 if opts.get('diffstat') or opts.get('confirm'): |
476 if opts.get('diffstat') or opts.get('confirm'): |
456 ui.write(_('\nFinal summary:\n\n')) |
477 ui.write(_('\nFinal summary:\n\n')) |
457 ui.write('From: %s\n' % sender) |
478 ui.write('From: %s\n' % sender) |