annotate mercurial/mail.py @ 5909:f45f7390c1c5

strip: calculate list of extra nodes to save and pass it to changegroupsubset When we remove revision N from the repository, all revisions >= N are affected: either it's a descendant from N and will also be removed, or it's not a descendant of N and will be renumbered. As a consequence, we have to (at least temporarily) remove all filelog and manifest revisions that have a linkrev >= N, readding some of them later. Unfortunately, it's possible to have a revlog with two revisions r1 and r2 such that r1 < r2, but linkrev(r1) > linkrev(r2). If we try to strip revision linkrev(r1) from the repository, we'll also lose revision r2 when we truncate this revlog. We already use changegroupsubset to create a temporary changegroup containing the revisions that have to be restored, but that function is unable to detect that we also wanted to save the r2 in the case above. So we manually calculate these extra nodes and pass it to changegroupsubset. This should fix issue764.
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
date Sat, 19 Jan 2008 18:01:16 -0200
parents dc6ed2736c81
children 528c986f0162
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # mail.py - mail sending bits for mercurial
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
5 # This software may be used and distributed according to the terms
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
6 # of the GNU General Public License, incorporated herein by reference.
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7
3891
6b4127c7d52a Simplify i18n imports
Matt Mackall <mpm@selenic.com>
parents: 3877
diff changeset
8 from i18n import _
4096
49237d6ae97d merge with crew-stable
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3963 4093
diff changeset
9 import os, smtplib, templater, util, socket
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
10
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
11 def _smtp(ui):
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
12 '''send mail using smtp.'''
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
13
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
14 local_hostname = ui.config('smtp', 'local_hostname')
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
15 s = smtplib.SMTP(local_hostname=local_hostname)
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
16 mailhost = ui.config('smtp', 'host')
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
17 if not mailhost:
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
18 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
19 mailport = int(ui.config('smtp', 'port', 25))
2964
26c8d37496c2 fix typo in mail.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2929
diff changeset
20 ui.note(_('sending mail: smtp host %s, port %s\n') %
26c8d37496c2 fix typo in mail.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2929
diff changeset
21 (mailhost, mailport))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
22 s.connect(host=mailhost, port=mailport)
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
23 if ui.configbool('smtp', 'tls'):
4093
669f99f78db0 mail.py: don't try to use TLS if python doesn't have SSL support
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2964
diff changeset
24 if not hasattr(socket, 'ssl'):
669f99f78db0 mail.py: don't try to use TLS if python doesn't have SSL support
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2964
diff changeset
25 raise util.Abort(_("can't use TLS: Python SSL support "
669f99f78db0 mail.py: don't try to use TLS if python doesn't have SSL support
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2964
diff changeset
26 "not installed"))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
27 ui.note(_('(using tls)\n'))
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
28 s.ehlo()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
29 s.starttls()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
30 s.ehlo()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
31 username = ui.config('smtp', 'username')
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
32 password = ui.config('smtp', 'password')
5749
4fba4fee0718 Patchbomb: Prompt password when using SMTP/TLS and no password in .hgrc.
Arun Thomas <arun.thomas@gmail.com>
parents: 5472
diff changeset
33 if username and not password:
4fba4fee0718 Patchbomb: Prompt password when using SMTP/TLS and no password in .hgrc.
Arun Thomas <arun.thomas@gmail.com>
parents: 5472
diff changeset
34 password = ui.getpass()
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
35 if username and password:
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
36 ui.note(_('(authenticating to mail server as %s)\n') %
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
37 (username))
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
38 s.login(username, password)
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
39 return s
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
40
5866
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
41 def _sendmail(ui, sender, recipients, msg):
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
42 '''send mail using sendmail.'''
5866
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
43 program = ui.config('email', 'method')
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
44 cmdline = '%s -f %s %s' % (program, templater.email(sender),
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
45 ' '.join(map(templater.email, recipients)))
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
46 ui.note(_('sending mail: %s\n') % cmdline)
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
47 fp = os.popen(cmdline, 'w')
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
48 fp.write(msg)
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
49 ret = fp.close()
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
50 if ret:
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
51 raise util.Abort('%s %s' % (
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
52 os.path.basename(program.split(None, 1)[0]),
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
53 util.explain_exit(ret)[0]))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
54
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
55 def connect(ui):
5866
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
56 '''make a mail connection. return a function to send mail.
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
57 call as sendmail(sender, list-of-recipients, msg).'''
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
58
5866
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
59 func = _sendmail
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
60 if ui.config('email', 'method', 'smtp') == 'smtp':
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
61 func = _smtp(ui)
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
62
5866
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
63 def send(ui, sender, recipients, msg):
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
64 try:
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
65 return func.sendmail(sender, recipients, msg)
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
66 except smtplib.SMTPRecipientsRefused, inst:
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
67 recipients = [r[1] for r in inst.recipients.values()]
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
68 raise util.Abort('\n' + '\n'.join(recipients))
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
69 except smtplib.SMTPException, inst:
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
70 raise util.Abort(inst)
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
71
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
72 return send
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
73
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
74 def sendmail(ui, sender, recipients, msg):
5472
23889160905a Catch smtp exceptions
Christian Ebert <blacktrash@gmx.net>
parents: 4489
diff changeset
75 try:
5866
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
76 send = connect(ui)
dc6ed2736c81 patchbomb: prompt only once for SMTP password
Matt Mackall <mpm@selenic.com>
parents: 5749
diff changeset
77 return send(sender, recipients, msg)
5472
23889160905a Catch smtp exceptions
Christian Ebert <blacktrash@gmx.net>
parents: 4489
diff changeset
78 except smtplib.SMTPRecipientsRefused, inst:
23889160905a Catch smtp exceptions
Christian Ebert <blacktrash@gmx.net>
parents: 4489
diff changeset
79 recipients = [r[1] for r in inst.recipients.values()]
23889160905a Catch smtp exceptions
Christian Ebert <blacktrash@gmx.net>
parents: 4489
diff changeset
80 raise util.Abort('\n' + '\n'.join(recipients))
23889160905a Catch smtp exceptions
Christian Ebert <blacktrash@gmx.net>
parents: 4489
diff changeset
81 except smtplib.SMTPException, inst:
23889160905a Catch smtp exceptions
Christian Ebert <blacktrash@gmx.net>
parents: 4489
diff changeset
82 raise util.Abort(inst)
4489
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
83
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
84 def validateconfig(ui):
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
85 '''determine if we have enough config data to try sending email.'''
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
86 method = ui.config('email', 'method', 'smtp')
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
87 if method == 'smtp':
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
88 if not ui.config('smtp', 'host'):
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
89 raise util.Abort(_('smtp specified as email transport, '
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
90 'but no smtp host configured'))
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
91 else:
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
92 if not util.find_exe(method):
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
93 raise util.Abort(_('%r specified as email transport, '
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
94 'but not in PATH') % method)