Mercurial > hg > mercurial-crew-with-dirclash
annotate contrib/patchbomb @ 1270:fc3b41570082
Switch to new syntax for .hgignore files.
Here is the new syntax, in summary.
Trailing white space is dropped.
The escape character is "\".
Comments start with #.
Empty lines are skipped.
Lines can be of the following formats:
syntax: regexp # defaults following lines to non-rooted regexps
syntax: glob # defaults following lines to non-rooted globs
re:pattern # non-rooted regular expression
glob:pattern # non-rooted glob
pattern # pattern of the current default type
The default pattern type is regexp, which is completely backwards
compatible with the old hgignore syntax.
In the dirstate class, the ignore method has been reworked to be based
on the util.matcher function, by way of a new dirstate.hgignore
method.
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Sat, 17 Sep 2005 00:27:27 -0700 |
parents | f3837564ed03 |
children | 5352a5407dc1 |
rev | line source |
---|---|
875 | 1 #!/usr/bin/python |
2 # | |
3 # Interactive script for sending a collection of Mercurial changesets | |
4 # as a series of patch emails. | |
5 # | |
6 # The series is started off with a "[PATCH 0 of N]" introduction, | |
7 # which describes the series as a whole. | |
8 # | |
9 # Each patch email has a Subject line of "[PATCH M of N] ...", using | |
10 # the first line of the changeset description as the subject text. | |
11 # The message contains two or three body parts: | |
12 # | |
13 # The remainder of the changeset description. | |
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 | 17 # |
18 # The patch itself, as generated by "hg export". | |
19 # | |
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 | |
22 # threaded mail and news readers, and in mail archives. | |
23 # | |
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 | |
26 # changes. | |
27 # | |
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 | 31 # |
32 # To configure a default mail host, add a section like this to your | |
33 # hgrc file: | |
34 # | |
35 # [smtp] | |
36 # host = my_mail_host | |
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 | 49 |
50 from email.MIMEMultipart import MIMEMultipart | |
51 from email.MIMEText import MIMEText | |
52 from mercurial import commands | |
53 from mercurial import fancyopts | |
54 from mercurial import hg | |
55 from mercurial import ui | |
56 import os | |
57 import popen2 | |
58 import smtplib | |
59 import socket | |
60 import sys | |
61 import tempfile | |
62 import time | |
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 | 70 def diffstat(patch): |
71 fd, name = tempfile.mkstemp() | |
72 try: | |
73 p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name) | |
74 try: | |
75 for line in patch: print >> p.tochild, line | |
76 p.tochild.close() | |
77 if p.wait(): return | |
78 fp = os.fdopen(fd, 'r') | |
79 stat = [] | |
80 for line in fp: stat.append(line.lstrip()) | |
81 last = stat.pop() | |
82 stat.insert(0, last) | |
83 stat = ''.join(stat) | |
84 if stat.startswith('0 files'): raise ValueError | |
85 return stat | |
86 except: raise | |
87 finally: | |
88 try: os.unlink(name) | |
89 except: pass | |
90 | |
91 def patchbomb(ui, repo, *revs, **opts): | |
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 | 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 | 101 |
102 def confirm(s): | |
103 if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'): | |
104 raise ValueError | |
105 | |
106 def cdiffstat(summary, patch): | |
107 s = diffstat(patch) | |
108 if s: | |
109 if summary: | |
110 ui.write(summary, '\n') | |
111 ui.write(s, '\n') | |
112 confirm('Does the diffstat above look okay') | |
113 return s | |
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 | 116 desc = [] |
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 | 119 for line in patch: |
120 if line.startswith('#'): | |
121 if line.startswith('# Node ID'): node = line.split()[-1] | |
122 continue | |
123 if line.startswith('diff -r'): break | |
124 desc.append(line) | |
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 | 135 subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip()) |
136 if subj.endswith('.'): subj = subj[:-1] | |
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 | 139 return msg |
140 | |
141 start_time = int(time.time()) | |
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 | 144 return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn()) |
145 | |
146 patches = [] | |
147 | |
148 class exportee: | |
149 def __init__(self, container): | |
150 self.lines = [] | |
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 | 153 |
154 def write(self, data): | |
155 self.lines.append(data) | |
156 | |
157 def close(self): | |
158 self.container.append(''.join(self.lines).split('\n')) | |
159 self.lines = [] | |
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 | 163 |
164 jumbo = [] | |
165 msgs = [] | |
166 | |
167 ui.write('This patch series consists of %d patches.\n\n' % len(patches)) | |
168 | |
169 for p, i in zip(patches, range(len(patches))): | |
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 | 172 |
173 ui.write('\nWrite the introductory message for the patch series.\n\n') | |
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 | 177 |
178 msg = MIMEMultipart() | |
179 msg['Subject'] = '[PATCH 0 of %d] %s' % ( | |
180 len(patches), | |
877
25430c523677
Polish patchbomb script.
Bryan O'Sullivan <bos@serpentine.com>
parents:
876
diff
changeset
|
181 opts['subject'] or |
875 | 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 | 190 |
191 ui.write('Finish with ^D or a dot on a line by itself.\n\n') | |
192 | |
193 body = [] | |
194 | |
195 while True: | |
196 try: l = raw_input() | |
197 except EOFError: break | |
198 if l == '.': break | |
199 body.append(l) | |
200 | |
201 msg.attach(MIMEText('\n'.join(body) + '\n')) | |
202 | |
203 ui.write('\n') | |
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 | 208 |
209 msgs.insert(0, msg) | |
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 | 223 parent = None |
224 tz = time.strftime('%z') | |
225 for m in msgs: | |
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 | 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 | 230 if parent: |
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 | 235 start_time += 1 |
236 m['From'] = sender | |
237 m['To'] = ', '.join(to) | |
238 if cc: m['Cc'] = ', '.join(cc) | |
239 ui.status('Sending ', m['Subject'], ' ...\n') | |
240 if opts['test']: | |
241 fp = os.popen(os.getenv('PAGER', 'more'), 'w') | |
242 fp.write(m.as_string(0)) | |
243 fp.write('\n') | |
244 fp.close() | |
245 else: | |
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 | 249 |
250 if __name__ == '__main__': | |
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 | 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 | 256 ('t', 'to', [], 'email addresses of recipients')] |
257 options = {} | |
258 try: | |
259 args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec, | |
260 options) | |
261 except fancyopts.getopt.GetoptError, inst: | |
262 u = ui.ui() | |
263 u.warn('error: %s' % inst) | |
264 sys.exit(1) | |
265 | |
266 u = ui.ui(options["verbose"], options["debug"], options["quiet"], | |
267 not options["noninteractive"]) | |
268 repo = hg.repository(ui = u) | |
269 | |
270 patchbomb(u, repo, *args, **options) |