1
# Copyright (C) 2005, 2006 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
"""Submit an email to a Patch Queue Manager"""
22
from bzrlib.branch import Branch
24
from bzrlib.errors import BzrCommandError
27
from bzrlib.trace import note
28
import bzrlib.urlutils
31
_default_smtp_server = 'localhost'
34
def _signed_submission(branch, config, target_base):
35
"""Get the signed text that we would submit to the pqm"""
37
merge_target = config.get_user_option('pqm_branch')
39
raise BzrCommandError('No PQM target branch specified '
42
unsigned_text = 'star-merge %s %s' % (target_base, merge_target)
44
strategy = bzrlib.gpg.GPGStrategy(config)
46
return strategy.sign(unsigned_text)
49
_default_headers = '''From: %s
56
def _setup_headers(message, user_from, user_to):
57
"""Get all of the important headers filled out."""
59
return _default_headers % (user_from
63
def public_branch(branch, config):
64
target_base = config.get_user_option('public_branch')
65
if target_base is None:
66
repo_loc = branch.repository.bzrdir.root_transport.local_abspath('.')
67
repo_config = bzrlib.config.LocationConfig(repo_loc)
68
public_repo = repo_config.get_user_option("public_repository")
69
if public_repo is not None:
70
branch_relpath = bzrlib.osutils.relpath(repo_loc,
71
branch.bzrdir.root_transport.local_abspath('.'))
72
target_base = bzrlib.urlutils.join(public_repo, branch_relpath)
75
target_base = branch.get_bound_location()
76
except AttributeError:
80
target_base = branch.get_push_location()
83
target_base = branch.get_parent()
86
target_base = branch.base
90
def submit(branch, message, dry_run=False, public_location=None):
91
"""Submit the given branch to the pqm."""
92
config = branch.get_config()
95
rev = branch.repository.get_revision(branch.last_revision())
97
message = message.encode('utf8')
99
user_from = config.get_user_option('pqm_user_email')
101
user_from = config.username()
102
user_from = user_from.encode('utf8') # Make sure this isn't unicode
103
user_to = config.get_user_option('pqm_email')
105
raise BzrCommandError('No PQM submission address specified '
107
user_to = user_to.encode('utf8') # same here
109
# All the entries must be utf-8 so the message creation doesn't fail
110
msg = _setup_headers(message, user_from, user_to)
112
server = config.get_user_option('smtp_server')
114
server = _default_smtp_server
115
smtp_username = config.get_user_option('smtp_username')
116
smtp_password = config.get_user_option('smtp_password')
118
if public_location is None:
119
target_base = public_branch(branch, config)
121
target_base = public_location
122
note('Checking that the public branch is up to date ...')
123
public_revision = Branch.open(target_base).last_revision()
124
if public_revision != branch.last_revision():
125
raise BzrCommandError(
126
'Local last revision does not match public last revision: %s' %
128
# Get the signed text, this should be done just before
129
# emailing, so that we don't run gpg --cl for nothing
130
msg += _signed_submission(branch, config, target_base)
133
return print_info(msg, server, user_from, user_to)
135
smtp = smtplib.SMTP()
139
# The world can always use a little bit more encryption :)
141
except smtplib.SMTPException:
144
if smtp_username is not None:
145
if smtp_password is None:
146
smtp_password = getpass.getpass(
147
'Please enter SMTP password for %s: ' % server)
149
smtp.login(smtp_username, smtp_password)
150
except smtplib.SMTPHeloError, e:
151
raise BzrCommandError('SMTP server refused HELO: %d %s'
152
% (e.smtp_code, e.smtp_error))
153
except smtplib.SMTPAuthenticationError, e:
154
raise BzrCommandError('SMTP server refused authentication: %d %s'
155
% (e.smtp_code, e.smtp_error))
156
except smtplib.SMTPException, e:
157
raise BzrCommandError(str(e))
159
smtp.sendmail(user_from, [user_to], msg)
162
def print_info(msg, server, user_from, user_to):
163
print "Server: %s" % server