hgext/patchbomb.py
changeset 15164 7bddec632821
parent 15162 d67a15b2e608
child 15165 3a55cee825ba
equal deleted inserted replaced
15162:d67a15b2e608 15164:7bddec632821
    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)