contrib/patchbomb
changeset 877 25430c523677
parent 876 14cfaaec2e8e
child 878 781266a78fe1
equal deleted inserted replaced
876:14cfaaec2e8e 877:25430c523677
    10 # the first line of the changeset description as the subject text.
    10 # the first line of the changeset description as the subject text.
    11 # The message contains two or three body parts:
    11 # The message contains two or three body parts:
    12 #
    12 #
    13 #   The remainder of the changeset description.
    13 #   The remainder of the changeset description.
    14 #
    14 #
    15 #   If the diffstat program is installed, the result of running
    15 #   [Optional] If the diffstat program is installed, the result of
    16 #   diffstat on the patch.
    16 #   running diffstat on the patch.
    17 #
    17 #
    18 #   The patch itself, as generated by "hg export".
    18 #   The patch itself, as generated by "hg export".
    19 #
    19 #
    20 # Each message refers to all of its predecessors using the In-Reply-To
    20 # Each message refers to all of its predecessors using the In-Reply-To
    21 # and References headers, so they will show up as a sequence in
    21 # and References headers, so they will show up as a sequence in
    24 # For each changeset, you will be prompted with a diffstat summary and
    24 # For each changeset, you will be prompted with a diffstat summary and
    25 # the changeset summary, so you can be sure you are sending the right
    25 # the changeset summary, so you can be sure you are sending the right
    26 # changes.
    26 # changes.
    27 #
    27 #
    28 # It is best to run this script with the "-n" (test only) flag before
    28 # It is best to run this script with the "-n" (test only) flag before
    29 # firing it up "for real", in which case it will display each of the
    29 # firing it up "for real", in which case it will use your pager to
    30 # messages that it would send.
    30 # display each of the messages that it would send.
    31 #
    31 #
    32 # To configure a default mail host, add a section like this to your
    32 # To configure a default mail host, add a section like this to your
    33 # hgrc file:
    33 # hgrc file:
    34 #
    34 #
    35 # [smtp]
    35 # [smtp]
    36 # host = my_mail_host
    36 # host = my_mail_host
    37 # port = 1025
    37 # port = 1025
       
    38 #
       
    39 # To configure other defaults, add a section like this to your hgrc
       
    40 # file:
       
    41 #
       
    42 # [patchbomb]
       
    43 # from = My Name <my@email>
       
    44 # to = recipient1, recipient2, ...
       
    45 # cc = cc1, cc2, ...
    38 
    46 
    39 from email.MIMEMultipart import MIMEMultipart
    47 from email.MIMEMultipart import MIMEMultipart
    40 from email.MIMEText import MIMEText
    48 from email.MIMEText import MIMEText
    41 from mercurial import commands
    49 from mercurial import commands
    42 from mercurial import fancyopts
    50 from mercurial import fancyopts
    79         while True:
    87         while True:
    80             r = raw_input(prompt)
    88             r = raw_input(prompt)
    81             if r: return r
    89             if r: return r
    82             if default is not None: return default
    90             if default is not None: return default
    83             if empty_ok: return r
    91             if empty_ok: return r
    84             print >> sys.stderr, 'Please enter a valid value.'
    92             ui.warn('Please enter a valid value.\n')
    85 
    93 
    86     def confirm(s):
    94     def confirm(s):
    87         if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
    95         if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
    88             raise ValueError
    96             raise ValueError
    89 
    97 
   106             if line.startswith('diff -r'): break
   114             if line.startswith('diff -r'): break
   107             desc.append(line)
   115             desc.append(line)
   108         if not node: raise ValueError
   116         if not node: raise ValueError
   109         body = ('\n'.join(desc[1:]).strip() or
   117         body = ('\n'.join(desc[1:]).strip() or
   110                 'Patch subject is complete summary.')
   118                 'Patch subject is complete summary.')
   111         body += '\n\n\n' + cdiffstat('\n'.join(desc), patch) + '\n\n'
   119         body += '\n\n\n'
       
   120         if opts['diffstat']:
       
   121             body += cdiffstat('\n'.join(desc), patch) + '\n\n'
   112         body += '\n'.join(patch)
   122         body += '\n'.join(patch)
   113         msg = MIMEText(body)
   123         msg = MIMEText(body)
   114         subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
   124         subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
   115         if subj.endswith('.'): subj = subj[:-1]
   125         if subj.endswith('.'): subj = subj[:-1]
   116         msg['Subject'] = subj
   126         msg['Subject'] = subj
   148         jumbo.extend(p)
   158         jumbo.extend(p)
   149         msgs.append(makepatch(p, i + 1, len(patches)))
   159         msgs.append(makepatch(p, i + 1, len(patches)))
   150 
   160 
   151     ui.write('\nWrite the introductory message for the patch series.\n\n')
   161     ui.write('\nWrite the introductory message for the patch series.\n\n')
   152 
   162 
   153     sender = opts['sender'] or prompt('From', ui.username())
   163     sender = (opts['from'] or ui.config('patchbomb', 'from') or
       
   164               prompt('From', ui.username()))
   154 
   165 
   155     msg = MIMEMultipart()
   166     msg = MIMEMultipart()
   156     msg['Subject'] = '[PATCH 0 of %d] %s' % (
   167     msg['Subject'] = '[PATCH 0 of %d] %s' % (
   157         len(patches),
   168         len(patches),
       
   169         opts['subject'] or
   158         prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
   170         prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
   159     to = opts['to'] or [s.strip() for s in prompt('To').split(',')]
   171     to = (opts['to'] or ui.config('patchbomb', 'to') or
   160     cc = opts['cc'] or [s.strip() for s in prompt('Cc', default = '').split(',')]
   172           [s.strip() for s in prompt('To').split(',')])
       
   173     cc = (opts['cc'] or ui.config('patchbomb', 'cc') or
       
   174           [s.strip() for s in prompt('Cc', default = '').split(',')])
   161 
   175 
   162     ui.write('Finish with ^D or a dot on a line by itself.\n\n')
   176     ui.write('Finish with ^D or a dot on a line by itself.\n\n')
   163 
   177 
   164     body = []
   178     body = []
   165 
   179 
   192             m['Message-Id'] = genmsgid('patchbomb')
   206             m['Message-Id'] = genmsgid('patchbomb')
   193         if parent:
   207         if parent:
   194             m['In-Reply-To'] = parent
   208             m['In-Reply-To'] = parent
   195         else:
   209         else:
   196             parent = m['Message-Id']
   210             parent = m['Message-Id']
   197         m['Date'] = time.strftime('%a, %m %b %Y %T ', time.localtime(start_time)) + tz
   211         m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz
   198         start_time += 1
   212         start_time += 1
   199         m['From'] = sender
   213         m['From'] = sender
   200         m['To'] = ', '.join(to)
   214         m['To'] = ', '.join(to)
   201         if cc: m['Cc'] = ', '.join(cc)
   215         if cc: m['Cc'] = ', '.join(cc)
   202         ui.status('Sending ', m['Subject'], ' ...\n')
   216         ui.status('Sending ', m['Subject'], ' ...\n')
   210     if not opts['test']:
   224     if not opts['test']:
   211         s.close()
   225         s.close()
   212 
   226 
   213 if __name__ == '__main__':
   227 if __name__ == '__main__':
   214     optspec = [('c', 'cc', [], 'email addresses of copy recipients'),
   228     optspec = [('c', 'cc', [], 'email addresses of copy recipients'),
       
   229                ('d', 'diffstat', None, 'add diffstat output to messages'),
       
   230                ('f', 'from', '', 'email address of sender'),
   215                ('n', 'test', None, 'print messages that would be sent'),
   231                ('n', 'test', None, 'print messages that would be sent'),
   216                ('s', 'sender', '', 'email address of sender'),
   232                ('s', 'subject', '', 'subject of introductory message'),
   217                ('t', 'to', [], 'email addresses of recipients')]
   233                ('t', 'to', [], 'email addresses of recipients')]
   218     options = {}
   234     options = {}
   219     try:
   235     try:
   220         args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec,
   236         args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec,
   221                                    options)
   237                                    options)