3
# Copyright 2009, 2010 Canonical Ltd. This software is licensed under the
4
# GNU Affero General Public License version 3 (see the file LICENSE).
15
from canonical.config import config
16
from lp.services.mailman.config import (
17
configure_prefix, configure_siteowner)
18
from lp.services.mailman.monkeypatches import monkey_patch
19
from lazr.config import as_username_groupname
21
basepath = [part for part in sys.path if part]
25
# Build and install Mailman if it is enabled and not yet built.
26
if not config.mailman.build:
27
# There's nothing to do.
29
mailman_path = configure_prefix(config.mailman.build_prefix)
30
mailman_bin = os.path.join(mailman_path, 'bin')
31
var_dir = os.path.abspath(config.mailman.build_var_dir)
33
# If we can import the package, we assume Mailman is properly built and
34
# installed. This does not catch re-installs that might be necessary
35
# should our copy in sourcecode be updated. Do that manually.
36
sys.path.append(mailman_path)
39
# Also check for Launchpad-specific bits stuck into the source tree by
40
# monkey_patch(), in case this is half-installed. See
41
# <https://bugs.launchpad.net/launchpad-registry/+bug/683486>.
42
from Mailman.Queue import XMLRPCRunner
43
from Mailman.Handlers import LPModerate
49
# sys.path_importer_cache is a mapping of elements of sys.path to importer
50
# objects used to handle them. In Python2.5+ when an element of sys.path
51
# is found to not exist on disk, a NullImporter is created and cached -
52
# this causes Python to never bother re-inspecting the disk for that path
53
# element. We must clear that cache element so that our second attempt to
54
# import MailMan after building it will actually check the disk.
55
del sys.path_importer_cache[mailman_path]
57
# Make sure the target directories exist and have the correct
58
# permissions, otherwise configure will complain.
59
user, group = as_username_groupname(config.mailman.build_user_group)
60
# Now work backwards to get the uid and gid
62
uid = pwd.getpwnam(user).pw_uid
64
print >> sys.stderr, 'No user found:', user
67
gid = grp.getgrnam(group).gr_gid
69
print >> sys.stderr, 'No group found:', group
72
# Ensure that the var_dir exists, is owned by the user:group, and has
73
# the necessary permissions. Set the mode separately after the
74
# makedirs() call because some platforms ignore mkdir()'s mode (though
75
# I think Linux does not ignore it -- better safe than sorry).
79
if e.errno != errno.EEXIST:
81
os.chown(var_dir, uid, gid)
82
os.chmod(var_dir, 02775)
84
mailman_source = os.path.join('sourcecode', 'mailman')
85
if config.mailman.build_host_name:
86
build_host_name = config.mailman.build_host_name
88
build_host_name = socket.getfqdn()
90
# Build and install the Mailman software. Note that we don't care about
91
# --with-cgi-gid because we're not going to use that Mailman subsystem.
92
executable = os.path.abspath('bin/py')
95
'--prefix', mailman_path,
96
'--with-var-prefix=' + var_dir,
97
'--with-python=' + executable,
98
'--with-username=' + user,
99
'--with-groupname=' + group,
100
'--with-mail-gid=' + group,
101
'--with-mailhost=' + build_host_name,
102
'--with-urlhost=' + build_host_name,
105
retcode = subprocess.call(configure_args, cwd=mailman_source)
107
print >> sys.stderr, 'Could not configure Mailman:'
110
retcode = subprocess.call(('make', ), cwd=mailman_source)
112
print >> sys.stderr, 'Could not make Mailman.'
114
# We have a brief interlude before we install. Hardy will not
115
# accept a script as the executable for the shebang line--it will
116
# treat the file as a shell script instead. The ``bin/by``
117
# executable that we specified in '--with-python' above is a script
118
# so this behavior causes problems for us. Our work around is to
119
# prefix the ``bin/py`` script with ``/usr/bin/env``, which makes
120
# Hardy happy. We need to do this before we install because the
121
# installation will call Mailman's ``bin/update``, which is a script
122
# that needs this fix.
123
build_dir = os.path.join(mailman_source, 'build')
124
original = '#! %s\n' % (executable, )
125
modified = '#! /usr/bin/env %s\n' % (executable, )
126
for (dirpath, dirnames, filenames) in os.walk(build_dir):
127
for filename in filenames:
128
filename = os.path.join(dirpath, filename)
129
f = open(filename, 'r')
130
if f.readline() == original:
133
f = open(filename, 'w')
137
# Now we actually install.
138
retcode = subprocess.call(('make', 'install'), cwd=mailman_source)
140
print >> sys.stderr, 'Could not install Mailman.'
142
# Try again to import the package.
144
# pylint: disable-msg=W0404
147
print >> sys.stderr, 'Could not import the Mailman package'
150
# Check to see if the site list exists. The output can go to /dev/null
151
# because we don't really care about it. The site list exists if
152
# config_list returns a zero exit status, otherwise it doesn't
153
# (probably). Before we can do this however, we must monkey patch
154
# Mailman, otherwise mm_cfg.py won't be set up correctly.
155
monkey_patch(mailman_path, config)
157
import Mailman.mm_cfg
158
retcode = subprocess.call(
159
('./config_list', '-o', '/dev/null',
160
Mailman.mm_cfg.MAILMAN_SITE_LIST),
162
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
165
addr, password = configure_siteowner(
166
config.mailman.build_site_list_owner)
168
# The site list does not yet exist, so create it now.
169
retcode = subprocess.call(
170
('./newlist', '--quiet',
171
'--emailhost=' + build_host_name,
172
Mailman.mm_cfg.MAILMAN_SITE_LIST,
176
print >> sys.stderr, 'Could not create site list'
179
retcode = configure_site_list(
180
mailman_bin, Mailman.mm_cfg.MAILMAN_SITE_LIST)
182
print >> sys.stderr, 'Could not configure site list'
185
# Create a directory to hold the gzip'd tarballs for the directories of
188
os.mkdir(os.path.join(Mailman.mm_cfg.VAR_PREFIX, 'backups'))
190
if e.errno != errno.EEXIST:
196
def configure_site_list(mailman_bin, site_list_name):
197
"""Configure the site list.
199
Currently, the only thing we want to set is to not advertise the
202
fd, config_file_name = tempfile.mkstemp()
205
config_file = open(config_file_name, 'w')
207
print >> config_file, 'advertised = False'
210
return subprocess.call(
211
('./config_list', '-i', config_file_name, site_list_name),
214
os.remove(config_file_name)
218
# setting python paths
219
program = sys.argv[0]
222
here = os.path.dirname(os.path.abspath(program))
223
srcdir = os.path.join(here, src)
224
sys.path = [srcdir, here] + basepath
225
return build_mailman()
228
if __name__ == '__main__':
230
sys.exit(return_code)