contrib/patchbomb
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
Wed, 23 Nov 2005 08:02:35 +0100
changeset 1555 01a5121a005a
parent 1226 f3837564ed03
child 1603 5352a5407dc1
permissions -rwxr-xr-x
bash_completion: use hg --debug help to get the list of debug commands. Also, try completing with the debug commands only when there's no other candidates. Based on an idea by TK Soh.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     1
#!/usr/bin/python
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     2
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     3
# Interactive script for sending a collection of Mercurial changesets
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     4
# as a series of patch emails.
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     5
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     6
# The series is started off with a "[PATCH 0 of N]" introduction,
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     7
# which describes the series as a whole.
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     8
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     9
# Each patch email has a Subject line of "[PATCH M of N] ...", using
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    10
# the first line of the changeset description as the subject text.
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    11
# The message contains two or three body parts:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    12
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    13
#   The remainder of the changeset description.
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    14
#
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    15
#   [Optional] If the diffstat program is installed, the result of
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    16
#   running diffstat on the patch.
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    17
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    18
#   The patch itself, as generated by "hg export".
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    19
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    20
# Each message refers to all of its predecessors using the In-Reply-To
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    21
# and References headers, so they will show up as a sequence in
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    22
# threaded mail and news readers, and in mail archives.
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    23
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    24
# For each changeset, you will be prompted with a diffstat summary and
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    25
# the changeset summary, so you can be sure you are sending the right
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    26
# changes.
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    27
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    28
# It is best to run this script with the "-n" (test only) flag before
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    29
# firing it up "for real", in which case it will use your pager to
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    30
# display each of the messages that it would send.
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    31
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    32
# To configure a default mail host, add a section like this to your
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    33
# hgrc file:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    34
#
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    35
# [smtp]
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    36
# host = my_mail_host
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    37
# port = 1025
1226
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
    38
# tls = yes # or omit if not needed
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
    39
# username = user     # if SMTP authentication required
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
    40
# password = password # if SMTP authentication required - PLAINTEXT
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    41
#
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    42
# To configure other defaults, add a section like this to your hgrc
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    43
# file:
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    44
#
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    45
# [patchbomb]
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    46
# from = My Name <my@email>
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    47
# to = recipient1, recipient2, ...
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    48
# cc = cc1, cc2, ...
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    49
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    50
from email.MIMEMultipart import MIMEMultipart
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    51
from email.MIMEText import MIMEText
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    52
from mercurial import commands
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    53
from mercurial import fancyopts
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    54
from mercurial import hg
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    55
from mercurial import ui
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    56
import os
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    57
import popen2
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    58
import smtplib
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    59
import socket
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    60
import sys
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    61
import tempfile
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    62
import time
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    63
1204
b0f6053df539 patchbomb: continue if we can't import readline.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1154
diff changeset
    64
try:
b0f6053df539 patchbomb: continue if we can't import readline.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1154
diff changeset
    65
    # readline gives raw_input editing capabilities, but is not
b0f6053df539 patchbomb: continue if we can't import readline.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1154
diff changeset
    66
    # present on windows
b0f6053df539 patchbomb: continue if we can't import readline.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1154
diff changeset
    67
    import readline
b0f6053df539 patchbomb: continue if we can't import readline.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1154
diff changeset
    68
except ImportError: pass
b0f6053df539 patchbomb: continue if we can't import readline.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1154
diff changeset
    69
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    70
def diffstat(patch):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    71
    fd, name = tempfile.mkstemp()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    72
    try:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    73
        p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    74
        try:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    75
            for line in patch: print >> p.tochild, line
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    76
            p.tochild.close()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    77
            if p.wait(): return
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    78
            fp = os.fdopen(fd, 'r')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    79
            stat = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    80
            for line in fp: stat.append(line.lstrip())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    81
            last = stat.pop()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    82
            stat.insert(0, last)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    83
            stat = ''.join(stat)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    84
            if stat.startswith('0 files'): raise ValueError
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    85
            return stat
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    86
        except: raise
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    87
    finally:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    88
        try: os.unlink(name)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    89
        except: pass
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    90
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    91
def patchbomb(ui, repo, *revs, **opts):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    92
    def prompt(prompt, default = None, rest = ': ', empty_ok = False):
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    93
        if default: prompt += ' [%s]' % default
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    94
        prompt += rest
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    95
        while True:
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    96
            r = raw_input(prompt)
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    97
            if r: return r
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    98
            if default is not None: return default
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    99
            if empty_ok: return r
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   100
            ui.warn('Please enter a valid value.\n')
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   101
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   102
    def confirm(s):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   103
        if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   104
            raise ValueError
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   105
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   106
    def cdiffstat(summary, patch):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   107
        s = diffstat(patch)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   108
        if s:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   109
            if summary:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   110
                ui.write(summary, '\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   111
                ui.write(s, '\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   112
            confirm('Does the diffstat above look okay')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   113
        return s
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   114
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   115
    def makepatch(patch, idx, total):
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   116
        desc = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   117
        node = None
1135
e455d91f6259 Variable 'body' was missing in patchbomb script.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1118
diff changeset
   118
        body = ''
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   119
        for line in patch:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   120
            if line.startswith('#'):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   121
                if line.startswith('# Node ID'): node = line.split()[-1]
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   122
                continue
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   123
            if line.startswith('diff -r'): break
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   124
            desc.append(line)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   125
        if not node: raise ValueError
1118
63b5f68d8167 patchbomb: eliminate silly complete summary message
mpm@selenic.com
parents: 1032
diff changeset
   126
63b5f68d8167 patchbomb: eliminate silly complete summary message
mpm@selenic.com
parents: 1032
diff changeset
   127
        #body = ('\n'.join(desc[1:]).strip() or
63b5f68d8167 patchbomb: eliminate silly complete summary message
mpm@selenic.com
parents: 1032
diff changeset
   128
        #        'Patch subject is complete summary.')
63b5f68d8167 patchbomb: eliminate silly complete summary message
mpm@selenic.com
parents: 1032
diff changeset
   129
        #body += '\n\n\n'
63b5f68d8167 patchbomb: eliminate silly complete summary message
mpm@selenic.com
parents: 1032
diff changeset
   130
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   131
        if opts['diffstat']:
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   132
            body += cdiffstat('\n'.join(desc), patch) + '\n\n'
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   133
        body += '\n'.join(patch)
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   134
        msg = MIMEText(body)
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   135
        subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   136
        if subj.endswith('.'): subj = subj[:-1]
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   137
        msg['Subject'] = subj
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   138
        msg['X-Mercurial-Node'] = node
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   139
        return msg
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   140
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   141
    start_time = int(time.time())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   142
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   143
    def genmsgid(id):
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   144
        return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   145
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   146
    patches = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   147
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   148
    class exportee:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   149
        def __init__(self, container):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   150
            self.lines = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   151
            self.container = container
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   152
            self.name = 'email'
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   153
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   154
        def write(self, data):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   155
            self.lines.append(data)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   156
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   157
        def close(self):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   158
            self.container.append(''.join(self.lines).split('\n'))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   159
            self.lines = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   160
1032
706c590c9060 Get patchbomb working with tip again.
Bryan O'Sullivan <bos@serpentine.com>
parents: 998
diff changeset
   161
    commands.export(ui, repo, *args, **{'output': exportee(patches),
706c590c9060 Get patchbomb working with tip again.
Bryan O'Sullivan <bos@serpentine.com>
parents: 998
diff changeset
   162
                                        'text': None})
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   163
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   164
    jumbo = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   165
    msgs = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   166
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   167
    ui.write('This patch series consists of %d patches.\n\n' % len(patches))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   168
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   169
    for p, i in zip(patches, range(len(patches))):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   170
        jumbo.extend(p)
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   171
        msgs.append(makepatch(p, i + 1, len(patches)))
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   172
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   173
    ui.write('\nWrite the introductory message for the patch series.\n\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   174
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   175
    sender = (opts['from'] or ui.config('patchbomb', 'from') or
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   176
              prompt('From', ui.username()))
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   177
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   178
    msg = MIMEMultipart()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   179
    msg['Subject'] = '[PATCH 0 of %d] %s' % (
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   180
        len(patches),
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   181
        opts['subject'] or
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   182
        prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
1154
c3cb9f39a91f patchbomb: fix up confusion between strings and lists of strings.
bos@serpentine.internal.keyresearch.com
parents: 1136
diff changeset
   183
c3cb9f39a91f patchbomb: fix up confusion between strings and lists of strings.
bos@serpentine.internal.keyresearch.com
parents: 1136
diff changeset
   184
    def getaddrs(opt, prpt, default = None):
c3cb9f39a91f patchbomb: fix up confusion between strings and lists of strings.
bos@serpentine.internal.keyresearch.com
parents: 1136
diff changeset
   185
        addrs = opts[opt] or (ui.config('patchbomb', opt) or
c3cb9f39a91f patchbomb: fix up confusion between strings and lists of strings.
bos@serpentine.internal.keyresearch.com
parents: 1136
diff changeset
   186
                              prompt(prpt, default = default)).split(',')
c3cb9f39a91f patchbomb: fix up confusion between strings and lists of strings.
bos@serpentine.internal.keyresearch.com
parents: 1136
diff changeset
   187
        return [a.strip() for a in addrs if a.strip()]
c3cb9f39a91f patchbomb: fix up confusion between strings and lists of strings.
bos@serpentine.internal.keyresearch.com
parents: 1136
diff changeset
   188
    to = getaddrs('to', 'To')
c3cb9f39a91f patchbomb: fix up confusion between strings and lists of strings.
bos@serpentine.internal.keyresearch.com
parents: 1136
diff changeset
   189
    cc = getaddrs('cc', 'Cc', '')
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   190
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   191
    ui.write('Finish with ^D or a dot on a line by itself.\n\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   192
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   193
    body = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   194
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   195
    while True:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   196
        try: l = raw_input()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   197
        except EOFError: break
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   198
        if l == '.': break
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   199
        body.append(l)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   200
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   201
    msg.attach(MIMEText('\n'.join(body) + '\n'))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   202
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   203
    ui.write('\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   204
1136
d451888505d7 Make diffstat optional for patchbomb script.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1135
diff changeset
   205
    if opts['diffstat']:
d451888505d7 Make diffstat optional for patchbomb script.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1135
diff changeset
   206
        d = cdiffstat('Final summary:\n', jumbo)
d451888505d7 Make diffstat optional for patchbomb script.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1135
diff changeset
   207
        if d: msg.attach(MIMEText(d))
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   208
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   209
    msgs.insert(0, msg)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   210
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   211
    if not opts['test']:
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   212
        s = smtplib.SMTP()
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   213
        s.connect(host = ui.config('smtp', 'host', 'mail'),
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   214
                  port = int(ui.config('smtp', 'port', 25)))
1226
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   215
        if ui.configbool('smtp', 'tls'):
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   216
            s.ehlo()
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   217
            s.starttls()
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   218
            s.ehlo()
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   219
        username = ui.config('smtp', 'username')
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   220
        password = ui.config('smtp', 'password')
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   221
        if username and password:
f3837564ed03 patchbomb: add TLS and SMTP AUTH support.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1204
diff changeset
   222
            s.login(username, password)
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   223
    parent = None
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   224
    tz = time.strftime('%z')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   225
    for m in msgs:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   226
        try:
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   227
            m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   228
        except TypeError:
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   229
            m['Message-Id'] = genmsgid('patchbomb')
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   230
        if parent:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   231
            m['In-Reply-To'] = parent
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   232
        else:
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   233
            parent = m['Message-Id']
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   234
        m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   235
        start_time += 1
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   236
        m['From'] = sender
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   237
        m['To'] = ', '.join(to)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   238
        if cc: m['Cc'] = ', '.join(cc)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   239
        ui.status('Sending ', m['Subject'], ' ...\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   240
        if opts['test']:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   241
            fp = os.popen(os.getenv('PAGER', 'more'), 'w')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   242
            fp.write(m.as_string(0))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   243
            fp.write('\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   244
            fp.close()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   245
        else:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   246
            s.sendmail(sender, to + cc, m.as_string(0))
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   247
    if not opts['test']:
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   248
        s.close()
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   249
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   250
if __name__ == '__main__':
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   251
    optspec = [('c', 'cc', [], 'email addresses of copy recipients'),
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   252
               ('d', 'diffstat', None, 'add diffstat output to messages'),
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   253
               ('f', 'from', '', 'email address of sender'),
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   254
               ('n', 'test', None, 'print messages that would be sent'),
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   255
               ('s', 'subject', '', 'subject of introductory message'),
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   256
               ('t', 'to', [], 'email addresses of recipients')]
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   257
    options = {}
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   258
    try:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   259
        args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec,
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   260
                                   options)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   261
    except fancyopts.getopt.GetoptError, inst:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   262
        u = ui.ui()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   263
        u.warn('error: %s' % inst)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   264
        sys.exit(1)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   265
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   266
    u = ui.ui(options["verbose"], options["debug"], options["quiet"],
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   267
              not options["noninteractive"])
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   268
    repo = hg.repository(ui = u)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   269
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   270
    patchbomb(u, repo, *args, **options)