108 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST |
108 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST |
109 |
109 |
110 Before using this command, you will need to enable email in your hgrc. |
110 Before using this command, you will need to enable email in your hgrc. |
111 See the [email] section in hgrc(5) for details. |
111 See the [email] section in hgrc(5) for details. |
112 ''' |
112 ''' |
|
113 |
|
114 _charsets = mail._charsets(ui) |
113 |
115 |
114 def prompt(prompt, default = None, rest = ': ', empty_ok = False): |
116 def prompt(prompt, default = None, rest = ': ', empty_ok = False): |
115 if not ui.interactive: |
117 if not ui.interactive: |
116 return default |
118 return default |
117 if default: |
119 if default: |
174 if opts.get('diffstat'): |
176 if opts.get('diffstat'): |
175 body += cdiffstat('\n'.join(desc), patch) + '\n\n' |
177 body += cdiffstat('\n'.join(desc), patch) + '\n\n' |
176 if opts.get('attach') or opts.get('inline'): |
178 if opts.get('attach') or opts.get('inline'): |
177 msg = email.MIMEMultipart.MIMEMultipart() |
179 msg = email.MIMEMultipart.MIMEMultipart() |
178 if body: |
180 if body: |
179 msg.attach(email.MIMEText.MIMEText(body, 'plain')) |
181 msg.attach(mail.mimeencode(ui, body, _charsets, |
|
182 opts.get('test'))) |
180 p = email.MIMEText.MIMEText('\n'.join(patch), 'x-patch') |
183 p = email.MIMEText.MIMEText('\n'.join(patch), 'x-patch') |
181 binnode = bin(node) |
184 binnode = bin(node) |
182 # if node is mq patch, it will have patch file name as tag |
185 # if node is mq patch, it will have patch file name as tag |
183 patchname = [t for t in repo.nodetags(binnode) |
186 patchname = [t for t in repo.nodetags(binnode) |
184 if t.endswith('.patch') or t.endswith('.diff')] |
187 if t.endswith('.patch') or t.endswith('.diff')] |
202 if total == 1: |
205 if total == 1: |
203 subj = '[PATCH] ' + (opts.get('subject') or subj) |
206 subj = '[PATCH] ' + (opts.get('subject') or subj) |
204 else: |
207 else: |
205 tlen = len(str(total)) |
208 tlen = len(str(total)) |
206 subj = '[PATCH %0*d of %d] %s' % (tlen, idx, total, subj) |
209 subj = '[PATCH %0*d of %d] %s' % (tlen, idx, total, subj) |
207 msg['Subject'] = subj |
210 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) |
208 msg['X-Mercurial-Node'] = node |
211 msg['X-Mercurial-Node'] = node |
209 return msg |
212 return msg, subj |
210 |
213 |
211 def outgoing(dest, revs): |
214 def outgoing(dest, revs): |
212 '''Return the revisions present locally but not in dest''' |
215 '''Return the revisions present locally but not in dest''' |
213 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
216 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
214 revs = [repo.lookup(rev) for rev in revs] |
217 revs = [repo.lookup(rev) for rev in revs] |
326 d = cdiffstat(_('Final summary:\n'), jumbo) |
329 d = cdiffstat(_('Final summary:\n'), jumbo) |
327 if d: |
330 if d: |
328 body = '\n' + d |
331 body = '\n' + d |
329 |
332 |
330 body = getdescription(body, sender) |
333 body = getdescription(body, sender) |
331 msg = email.MIMEText.MIMEText(body) |
334 msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) |
332 msg['Subject'] = subj |
335 msg['Subject'] = mail.headencode(ui, subj, _charsets, |
333 |
336 opts.get('test')) |
334 msgs.insert(0, msg) |
337 |
|
338 msgs.insert(0, (msg, subj)) |
335 return msgs |
339 return msgs |
336 |
340 |
337 def getbundlemsgs(bundle): |
341 def getbundlemsgs(bundle): |
338 subj = (opts.get('subject') |
342 subj = (opts.get('subject') |
339 or prompt('Subject:', default='A bundle for your repository')) |
343 or prompt('Subject:', default='A bundle for your repository')) |
340 |
344 |
341 body = getdescription('', sender) |
345 body = getdescription('', sender) |
342 msg = email.MIMEMultipart.MIMEMultipart() |
346 msg = email.MIMEMultipart.MIMEMultipart() |
343 if body: |
347 if body: |
344 msg.attach(email.MIMEText.MIMEText(body, 'plain')) |
348 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test'))) |
345 datapart = email.MIMEBase.MIMEBase('application', 'x-mercurial-bundle') |
349 datapart = email.MIMEBase.MIMEBase('application', 'x-mercurial-bundle') |
346 datapart.set_payload(bundle) |
350 datapart.set_payload(bundle) |
347 datapart.add_header('Content-Disposition', 'attachment', |
351 datapart.add_header('Content-Disposition', 'attachment', |
348 filename='bundle.hg') |
352 filename='bundle.hg') |
349 email.Encoders.encode_base64(datapart) |
353 email.Encoders.encode_base64(datapart) |
350 msg.attach(datapart) |
354 msg.attach(datapart) |
351 msg['Subject'] = subj |
355 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) |
352 return [msg] |
356 return [(msg, subj)] |
353 |
357 |
354 sender = (opts.get('from') or ui.config('email', 'from') or |
358 sender = (opts.get('from') or ui.config('email', 'from') or |
355 ui.config('patchbomb', 'from') or |
359 ui.config('patchbomb', 'from') or |
356 prompt('From', ui.username())) |
360 prompt('From', ui.username())) |
357 |
361 |
362 |
366 |
363 def getaddrs(opt, prpt, default = None): |
367 def getaddrs(opt, prpt, default = None): |
364 addrs = opts.get(opt) or (ui.config('email', opt) or |
368 addrs = opts.get(opt) or (ui.config('email', opt) or |
365 ui.config('patchbomb', opt) or |
369 ui.config('patchbomb', opt) or |
366 prompt(prpt, default = default)).split(',') |
370 prompt(prpt, default = default)).split(',') |
367 return [a.strip() for a in addrs if a.strip()] |
371 return [mail.addressencode(ui, a.strip(), _charsets, opts.get('test')) |
|
372 for a in addrs if a.strip()] |
368 |
373 |
369 to = getaddrs('to', 'To') |
374 to = getaddrs('to', 'To') |
370 cc = getaddrs('cc', 'Cc', '') |
375 cc = getaddrs('cc', 'Cc', '') |
371 |
376 |
372 bcc = opts.get('bcc') or (ui.config('email', 'bcc') or |
377 bcc = opts.get('bcc') or (ui.config('email', 'bcc') or |
373 ui.config('patchbomb', 'bcc') or '').split(',') |
378 ui.config('patchbomb', 'bcc') or '').split(',') |
374 bcc = [a.strip() for a in bcc if a.strip()] |
379 bcc = [mail.addressencode(ui, a.strip(), _charsets, opts.get('test')) |
|
380 for a in bcc if a.strip()] |
375 |
381 |
376 ui.write('\n') |
382 ui.write('\n') |
377 |
383 |
378 parent = None |
384 parent = None |
379 |
385 |
380 sender_addr = email.Utils.parseaddr(sender)[1] |
386 sender_addr = email.Utils.parseaddr(sender)[1] |
|
387 sender = mail.addressencode(ui, sender, _charsets, opts.get('test')) |
381 sendmail = None |
388 sendmail = None |
382 for m in msgs: |
389 for m, subj in msgs: |
383 try: |
390 try: |
384 m['Message-Id'] = genmsgid(m['X-Mercurial-Node']) |
391 m['Message-Id'] = genmsgid(m['X-Mercurial-Node']) |
385 except TypeError: |
392 except TypeError: |
386 m['Message-Id'] = genmsgid('patchbomb') |
393 m['Message-Id'] = genmsgid('patchbomb') |
387 if parent: |
394 if parent: |
396 if cc: |
403 if cc: |
397 m['Cc'] = ', '.join(cc) |
404 m['Cc'] = ', '.join(cc) |
398 if bcc: |
405 if bcc: |
399 m['Bcc'] = ', '.join(bcc) |
406 m['Bcc'] = ', '.join(bcc) |
400 if opts.get('test'): |
407 if opts.get('test'): |
401 ui.status(_('Displaying '), m['Subject'], ' ...\n') |
408 ui.status(_('Displaying '), subj, ' ...\n') |
402 ui.flush() |
409 ui.flush() |
403 if 'PAGER' in os.environ: |
410 if 'PAGER' in os.environ: |
404 fp = util.popen(os.environ['PAGER'], 'w') |
411 fp = util.popen(os.environ['PAGER'], 'w') |
405 else: |
412 else: |
406 fp = ui |
413 fp = ui |
412 if inst.errno != errno.EPIPE: |
419 if inst.errno != errno.EPIPE: |
413 raise |
420 raise |
414 if fp is not ui: |
421 if fp is not ui: |
415 fp.close() |
422 fp.close() |
416 elif opts.get('mbox'): |
423 elif opts.get('mbox'): |
417 ui.status(_('Writing '), m['Subject'], ' ...\n') |
424 ui.status(_('Writing '), subj, ' ...\n') |
418 fp = open(opts.get('mbox'), 'In-Reply-To' in m and 'ab+' or 'wb+') |
425 fp = open(opts.get('mbox'), 'In-Reply-To' in m and 'ab+' or 'wb+') |
419 generator = email.Generator.Generator(fp, mangle_from_=True) |
426 generator = email.Generator.Generator(fp, mangle_from_=True) |
420 date = util.datestr(start_time, '%a %b %d %H:%M:%S %Y') |
427 date = util.datestr(start_time, '%a %b %d %H:%M:%S %Y') |
421 fp.write('From %s %s\n' % (sender_addr, date)) |
428 fp.write('From %s %s\n' % (sender_addr, date)) |
422 generator.flatten(m, 0) |
429 generator.flatten(m, 0) |
423 fp.write('\n\n') |
430 fp.write('\n\n') |
424 fp.close() |
431 fp.close() |
425 else: |
432 else: |
426 if not sendmail: |
433 if not sendmail: |
427 sendmail = mail.connect(ui) |
434 sendmail = mail.connect(ui) |
428 ui.status(_('Sending '), m['Subject'], ' ...\n') |
435 ui.status(_('Sending '), subj, ' ...\n') |
429 # Exim does not remove the Bcc field |
436 # Exim does not remove the Bcc field |
430 del m['Bcc'] |
437 del m['Bcc'] |
431 fp = cStringIO.StringIO() |
438 fp = cStringIO.StringIO() |
432 generator = email.Generator.Generator(fp, mangle_from_=False) |
439 generator = email.Generator.Generator(fp, mangle_from_=False) |
433 generator.flatten(m, 0) |
440 generator.flatten(m, 0) |