contrib/patchbomb
author bos@serpentine.internal.keyresearch.com
Mon, 22 Aug 2005 15:08:20 -0700
changeset 1003 6dfc9cc71f42
parent 998 c37dd58a444a
child 1032 706c590c9060
permissions -rwxr-xr-x
Emacs support: numerous changes. Most SCM commands now work in derived buffers (e.g. diff viewing buffers) as well as buffers backed by files. diff and log now work properly on repositories and files. Commit support is more solid. Doc strings are better.
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
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    38
#
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    39
# 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
    40
# file:
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
# [patchbomb]
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    43
# from = My Name <my@email>
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    44
# to = recipient1, recipient2, ...
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    45
# cc = cc1, cc2, ...
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    46
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    47
from email.MIMEMultipart import MIMEMultipart
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    48
from email.MIMEText import MIMEText
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    49
from mercurial import commands
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    50
from mercurial import fancyopts
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    51
from mercurial import hg
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    52
from mercurial import ui
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    53
import os
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    54
import popen2
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    55
import readline
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    56
import smtplib
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    57
import socket
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    58
import sys
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    59
import tempfile
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    60
import time
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    61
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    62
def diffstat(patch):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    63
    fd, name = tempfile.mkstemp()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    64
    try:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    65
        p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    66
        try:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    67
            for line in patch: print >> p.tochild, line
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    68
            p.tochild.close()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    69
            if p.wait(): return
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    70
            fp = os.fdopen(fd, 'r')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    71
            stat = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    72
            for line in fp: stat.append(line.lstrip())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    73
            last = stat.pop()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    74
            stat.insert(0, last)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    75
            stat = ''.join(stat)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    76
            if stat.startswith('0 files'): raise ValueError
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    77
            return stat
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    78
        except: raise
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    79
    finally:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    80
        try: os.unlink(name)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    81
        except: pass
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    82
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    83
def patchbomb(ui, repo, *revs, **opts):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    84
    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
    85
        if default: prompt += ' [%s]' % default
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    86
        prompt += rest
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    87
        while True:
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    88
            r = raw_input(prompt)
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    89
            if r: return r
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
    90
            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
    91
            if empty_ok: return r
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
    92
            ui.warn('Please enter a valid value.\n')
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    93
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    94
    def confirm(s):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    95
        if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    96
            raise ValueError
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    97
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    98
    def cdiffstat(summary, patch):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    99
        s = diffstat(patch)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   100
        if s:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   101
            if summary:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   102
                ui.write(summary, '\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   103
                ui.write(s, '\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   104
            confirm('Does the diffstat above look okay')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   105
        return s
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   106
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   107
    def makepatch(patch, idx, total):
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   108
        desc = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   109
        node = None
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   110
        for line in patch:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   111
            if line.startswith('#'):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   112
                if line.startswith('# Node ID'): node = line.split()[-1]
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   113
                continue
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   114
            if line.startswith('diff -r'): break
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   115
            desc.append(line)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   116
        if not node: raise ValueError
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   117
        body = ('\n'.join(desc[1:]).strip() or
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   118
                'Patch subject is complete summary.')
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   119
        body += '\n\n\n'
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   120
        if opts['diffstat']:
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   121
            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
   122
        body += '\n'.join(patch)
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   123
        msg = MIMEText(body)
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   124
        subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   125
        if subj.endswith('.'): subj = subj[:-1]
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   126
        msg['Subject'] = subj
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   127
        msg['X-Mercurial-Node'] = node
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   128
        return msg
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   129
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   130
    start_time = int(time.time())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   131
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   132
    def genmsgid(id):
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   133
        return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn())
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   134
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   135
    patches = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   136
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   137
    class exportee:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   138
        def __init__(self, container):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   139
            self.lines = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   140
            self.container = container
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   141
            self.name = 'email'
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   142
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   143
        def write(self, data):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   144
            self.lines.append(data)
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
        def close(self):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   147
            self.container.append(''.join(self.lines).split('\n'))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   148
            self.lines = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   149
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   150
    commands.export(ui, repo, *args, **{'output': exportee(patches)})
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   151
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   152
    jumbo = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   153
    msgs = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   154
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   155
    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
   156
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   157
    for p, i in zip(patches, range(len(patches))):
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   158
        jumbo.extend(p)
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   159
        msgs.append(makepatch(p, i + 1, len(patches)))
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   160
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   161
    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
   162
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   163
    sender = (opts['from'] or ui.config('patchbomb', 'from') or
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   164
              prompt('From', ui.username()))
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   165
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   166
    msg = MIMEMultipart()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   167
    msg['Subject'] = '[PATCH 0 of %d] %s' % (
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   168
        len(patches),
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   169
        opts['subject'] or
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   170
        prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
997
458b84a96e1c Fix handling of addresses in hgrc.
Bryan O'Sullivan <bos@serpentine.com>
parents: 896
diff changeset
   171
    to = opts['to'] or ui.config('patchbomb', 'to') or prompt('To')
458b84a96e1c Fix handling of addresses in hgrc.
Bryan O'Sullivan <bos@serpentine.com>
parents: 896
diff changeset
   172
    to = [t.strip() for t in to.split(',')]
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   173
    cc = (opts['cc'] or ui.config('patchbomb', 'cc') or
997
458b84a96e1c Fix handling of addresses in hgrc.
Bryan O'Sullivan <bos@serpentine.com>
parents: 896
diff changeset
   174
          prompt('Cc', default = ''))
998
c37dd58a444a contrib/patchbomb: Fix buglet with empty cc list.
Bryan O'Sullivan <bos@serpentine.com>
parents: 997
diff changeset
   175
    cc = (cc and [c.strip() for c in cc.split(',')]) or []
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   176
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   177
    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
   178
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   179
    body = []
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   180
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   181
    while True:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   182
        try: l = raw_input()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   183
        except EOFError: break
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   184
        if l == '.': break
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   185
        body.append(l)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   186
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   187
    msg.attach(MIMEText('\n'.join(body) + '\n'))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   188
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   189
    ui.write('\n')
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
    d = cdiffstat('Final summary:\n', jumbo)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   192
    if d: msg.attach(MIMEText(d))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   193
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   194
    msgs.insert(0, msg)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   195
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   196
    if not opts['test']:
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   197
        s = smtplib.SMTP()
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   198
        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
   199
                  port = int(ui.config('smtp', 'port', 25)))
875
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
    parent = None
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   202
    tz = time.strftime('%z')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   203
    for m in msgs:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   204
        try:
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   205
            m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   206
        except TypeError:
876
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   207
            m['Message-Id'] = genmsgid('patchbomb')
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   208
        if parent:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   209
            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
   210
        else:
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   211
            parent = m['Message-Id']
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   212
        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
   213
        start_time += 1
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   214
        m['From'] = sender
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   215
        m['To'] = ', '.join(to)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   216
        if cc: m['Cc'] = ', '.join(cc)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   217
        ui.status('Sending ', m['Subject'], ' ...\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   218
        if opts['test']:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   219
            fp = os.popen(os.getenv('PAGER', 'more'), 'w')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   220
            fp.write(m.as_string(0))
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   221
            fp.write('\n')
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   222
            fp.close()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   223
        else:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   224
            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
   225
    if not opts['test']:
14cfaaec2e8e Get patchbomb script to not use MIME attachments.
Bryan O'Sullivan <bos@serpentine.com>
parents: 875
diff changeset
   226
        s.close()
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   227
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   228
if __name__ == '__main__':
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   229
    optspec = [('c', 'cc', [], 'email addresses of copy recipients'),
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   230
               ('d', 'diffstat', None, 'add diffstat output to messages'),
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   231
               ('f', 'from', '', 'email address of sender'),
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   232
               ('n', 'test', None, 'print messages that would be sent'),
877
25430c523677 Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents: 876
diff changeset
   233
               ('s', 'subject', '', 'subject of introductory message'),
875
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   234
               ('t', 'to', [], 'email addresses of recipients')]
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   235
    options = {}
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   236
    try:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   237
        args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec,
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   238
                                   options)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   239
    except fancyopts.getopt.GetoptError, inst:
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   240
        u = ui.ui()
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   241
        u.warn('error: %s' % inst)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   242
        sys.exit(1)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   243
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   244
    u = ui.ui(options["verbose"], options["debug"], options["quiet"],
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   245
              not options["noninteractive"])
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   246
    repo = hg.repository(ui = u)
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   247
d3f836bf6cc1 Add patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   248
    patchbomb(u, repo, *args, **options)