~launchpad-pqm/launchpad/devel

7675.1022.7 by Curtis Hovey
reverted hacks to makefile.
1
#! /usr/bin/python
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
2
#
11706.3.1 by Martin Pool
Better check that pseudomonkeypatches are installed into the Mailman module
3
# Copyright 2009, 2010 Canonical Ltd.  This software is licensed under the
8687.15.10 by Karl Fogel
Add the copyright header block to top-level files.
4
# GNU Affero General Public License version 3 (see the file LICENSE).
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
5
14612.2.9 by William Grant
Other bits and pieces.
6
import errno
7
import grp
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
8
import os
9
import pwd
14612.2.9 by William Grant
Other bits and pieces.
10
import socket
11
import subprocess
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
12
import sys
4897.4.6 by Barry Warsaw
The first step toward a comprehensive Launchpad/Mailman integration test.
13
import tempfile
14612.2.9 by William Grant
Other bits and pieces.
14
15
from lazr.config import as_username_groupname
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
16
14605.1.1 by Curtis Hovey
Moved canonical.config to lp.services.
17
from lp.services.config import config
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
18
from lp.services.mailman.config import (
14612.2.9 by William Grant
Other bits and pieces.
19
    configure_prefix,
20
    configure_siteowner,
21
    )
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
22
from lp.services.mailman.monkeypatches import monkey_patch
14612.2.9 by William Grant
Other bits and pieces.
23
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
24
5863.9.1 by Curtis Hovey
Updated configs and code to used simple datatypes. Changes may still be needed aftert testing.
25
basepath = [part for part in sys.path if part]
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
26
27
28
def build_mailman():
29
    # Build and install Mailman if it is enabled and not yet built.
5863.9.7 by Curtis Hovey
Refacortings per review.
30
    if not config.mailman.build:
5863.9.1 by Curtis Hovey
Updated configs and code to used simple datatypes. Changes may still be needed aftert testing.
31
        # There's nothing to do.
5415.1.1 by Barry Warsaw
If there is no <mailman> or <mailman-build> section, there's nothing to build, so return immediately.
32
        return 0
5863.9.7 by Curtis Hovey
Refacortings per review.
33
    mailman_path = configure_prefix(config.mailman.build_prefix)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
34
    mailman_bin = os.path.join(mailman_path, 'bin')
5863.9.1 by Curtis Hovey
Updated configs and code to used simple datatypes. Changes may still be needed aftert testing.
35
    var_dir = os.path.abspath(config.mailman.build_var_dir)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
36
37
    # If we can import the package, we assume Mailman is properly built and
38
    # installed.  This does not catch re-installs that might be necessary
39
    # should our copy in sourcecode be updated.  Do that manually.
40
    sys.path.append(mailman_path)
41
    try:
42
        import Mailman
11706.3.1 by Martin Pool
Better check that pseudomonkeypatches are installed into the Mailman module
43
        # Also check for Launchpad-specific bits stuck into the source tree by
44
        # monkey_patch(), in case this is half-installed.  See
45
        # <https://bugs.launchpad.net/launchpad-registry/+bug/683486>.
46
        from Mailman.Queue import XMLRPCRunner
47
        from Mailman.Handlers import LPModerate
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
48
    except ImportError:
49
        pass
50
    else:
51
        return 0
52
9328.1.2 by Max Bowsher
Make comment more detailed.
53
    # sys.path_importer_cache is a mapping of elements of sys.path to importer
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
54
    # objects used to handle them. In Python2.5+ when an element of sys.path
55
    # is found to not exist on disk, a NullImporter is created and cached -
56
    # this causes Python to never bother re-inspecting the disk for that path
9328.1.2 by Max Bowsher
Make comment more detailed.
57
    # element. We must clear that cache element so that our second attempt to
58
    # import MailMan after building it will actually check the disk.
9328.1.1 by Max Bowsher
Clear the mailman_path from sys.path_importer_cache after a failed import - otherwise Python >= 2.5 won't look again at a directory it has already determined does not exist.
59
    del sys.path_importer_cache[mailman_path]
60
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
61
    # Make sure the target directories exist and have the correct
62
    # permissions, otherwise configure will complain.
7064.1.4 by Barry Warsaw
Response to Francis's review.
63
    user, group = as_username_groupname(config.mailman.build_user_group)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
64
    # Now work backwards to get the uid and gid
5373.2.8 by Barry Warsaw
Solve a few other problems related to staging's Mailman configs.
65
    try:
66
        uid = pwd.getpwnam(user).pw_uid
67
    except KeyError:
68
        print >> sys.stderr, 'No user found:', user
69
        sys.exit(1)
70
    try:
71
        gid = grp.getgrnam(group).gr_gid
72
    except KeyError:
73
        print >> sys.stderr, 'No group found:', group
74
        sys.exit(1)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
75
76
    # Ensure that the var_dir exists, is owned by the user:group, and has
77
    # the necessary permissions.  Set the mode separately after the
78
    # makedirs() call because some platforms ignore mkdir()'s mode (though
79
    # I think Linux does not ignore it -- better safe than sorry).
80
    try:
81
        os.makedirs(var_dir)
82
    except OSError, e:
4002.5.26 by Barry Warsaw
Branch fixes based on salgado's review.
83
        if e.errno != errno.EEXIST:
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
84
            raise
85
    os.chown(var_dir, uid, gid)
86
    os.chmod(var_dir, 02775)
87
88
    mailman_source = os.path.join('sourcecode', 'mailman')
7064.1.4 by Barry Warsaw
Response to Francis's review.
89
    if config.mailman.build_host_name:
90
        build_host_name = config.mailman.build_host_name
91
    else:
92
        build_host_name = socket.getfqdn()
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
93
5427.2.1 by Barry Warsaw
Correct a bald-faced lie. Mailman's buildout for Launchpad /does/ need to set
94
    # Build and install the Mailman software.  Note that we don't care about
95
    # --with-cgi-gid because we're not going to use that Mailman subsystem.
9641.1.13 by Gary Poster
try a work-around for Hardy Heron dislike of scripts as executables in shebang lines. Also revert to using a shell script for bin/py rather than a Python script.
96
    executable = os.path.abspath('bin/py')
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
97
    configure_args = (
98
        './configure',
99
        '--prefix', mailman_path,
100
        '--with-var-prefix=' + var_dir,
9641.1.13 by Gary Poster
try a work-around for Hardy Heron dislike of scripts as executables in shebang lines. Also revert to using a shell script for bin/py rather than a Python script.
101
        '--with-python=' + executable,
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
102
        '--with-username=' + user,
103
        '--with-groupname=' + group,
5427.2.1 by Barry Warsaw
Correct a bald-faced lie. Mailman's buildout for Launchpad /does/ need to set
104
        '--with-mail-gid=' + group,
5863.9.1 by Curtis Hovey
Updated configs and code to used simple datatypes. Changes may still be needed aftert testing.
105
        '--with-mailhost=' + build_host_name,
106
        '--with-urlhost=' + build_host_name,
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
107
        )
9641.1.13 by Gary Poster
try a work-around for Hardy Heron dislike of scripts as executables in shebang lines. Also revert to using a shell script for bin/py rather than a Python script.
108
    # Configure.
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
109
    retcode = subprocess.call(configure_args, cwd=mailman_source)
110
    if retcode:
111
        print >> sys.stderr, 'Could not configure Mailman:'
112
        sys.exit(retcode)
9641.1.13 by Gary Poster
try a work-around for Hardy Heron dislike of scripts as executables in shebang lines. Also revert to using a shell script for bin/py rather than a Python script.
113
    # Make.
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
114
    retcode = subprocess.call(('make', ), cwd=mailman_source)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
115
    if retcode:
116
        print >> sys.stderr, 'Could not make Mailman.'
117
        sys.exit(retcode)
9641.1.13 by Gary Poster
try a work-around for Hardy Heron dislike of scripts as executables in shebang lines. Also revert to using a shell script for bin/py rather than a Python script.
118
    # We have a brief interlude before we install.  Hardy will not
119
    # accept a script as the executable for the shebang line--it will
120
    # treat the file as a shell script instead. The ``bin/by``
121
    # executable that we specified in '--with-python' above is a script
122
    # so this behavior causes problems for us. Our work around is to
123
    # prefix the ``bin/py`` script with ``/usr/bin/env``, which makes
124
    # Hardy happy.  We need to do this before we install because the
125
    # installation will call Mailman's ``bin/update``, which is a script
126
    # that needs this fix.
127
    build_dir = os.path.join(mailman_source, 'build')
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
128
    original = '#! %s\n' % (executable, )
129
    modified = '#! /usr/bin/env %s\n' % (executable, )
9641.1.13 by Gary Poster
try a work-around for Hardy Heron dislike of scripts as executables in shebang lines. Also revert to using a shell script for bin/py rather than a Python script.
130
    for (dirpath, dirnames, filenames) in os.walk(build_dir):
131
        for filename in filenames:
132
            filename = os.path.join(dirpath, filename)
133
            f = open(filename, 'r')
134
            if f.readline() == original:
135
                rest = f.read()
136
                f.close()
137
                f = open(filename, 'w')
138
                f.write(modified)
139
                f.write(rest)
140
            f.close()
141
    # Now we actually install.
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
142
    retcode = subprocess.call(('make', 'install'), cwd=mailman_source)
143
    if retcode:
144
        print >> sys.stderr, 'Could not install Mailman.'
145
        sys.exit(retcode)
146
    # Try again to import the package.
147
    try:
7064.1.4 by Barry Warsaw
Response to Francis's review.
148
        # pylint: disable-msg=W0404
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
149
        import Mailman
150
    except ImportError:
151
        print >> sys.stderr, 'Could not import the Mailman package'
152
        return 1
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
153
154
    # Check to see if the site list exists.  The output can go to /dev/null
155
    # because we don't really care about it.  The site list exists if
156
    # config_list returns a zero exit status, otherwise it doesn't
157
    # (probably).  Before we can do this however, we must monkey patch
158
    # Mailman, otherwise mm_cfg.py won't be set up correctly.
159
    monkey_patch(mailman_path, config)
160
161
    import Mailman.mm_cfg
162
    retcode = subprocess.call(
163
        ('./config_list', '-o', '/dev/null',
164
         Mailman.mm_cfg.MAILMAN_SITE_LIST),
165
        cwd=mailman_bin,
166
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
167
168
    if retcode:
5863.9.7 by Curtis Hovey
Refacortings per review.
169
        addr, password = configure_siteowner(
170
            config.mailman.build_site_list_owner)
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
171
172
        # The site list does not yet exist, so create it now.
173
        retcode = subprocess.call(
174
            ('./newlist', '--quiet',
5863.9.1 by Curtis Hovey
Updated configs and code to used simple datatypes. Changes may still be needed aftert testing.
175
             '--emailhost=' + build_host_name,
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
176
             Mailman.mm_cfg.MAILMAN_SITE_LIST,
177
             addr, password),
178
            cwd=mailman_bin)
179
        if retcode:
180
            print >> sys.stderr, 'Could not create site list'
4483.4.25 by Barry Warsaw
Last round of changes in response to bac's comments (who took over in BjornT's
181
            return retcode
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
182
5046.3.2 by Barry Warsaw
Some modifications in response to Francis's comments.
183
    retcode = configure_site_list(
184
        mailman_bin, Mailman.mm_cfg.MAILMAN_SITE_LIST)
185
    if retcode:
186
        print >> sys.stderr, 'Could not configure site list'
187
        return retcode
188
189
    # Create a directory to hold the gzip'd tarballs for the directories of
190
    # deactivated lists.
191
    try:
192
        os.mkdir(os.path.join(Mailman.mm_cfg.VAR_PREFIX, 'backups'))
193
    except OSError, e:
194
        if e.errno != errno.EEXIST:
195
            raise
196
197
    return 0
198
199
200
def configure_site_list(mailman_bin, site_list_name):
201
    """Configure the site list.
202
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
203
    Currently, the only thing we want to set is to not advertise the
204
    site list.
5046.3.2 by Barry Warsaw
Some modifications in response to Francis's comments.
205
    """
4897.4.6 by Barry Warsaw
The first step toward a comprehensive Launchpad/Mailman integration test.
206
    fd, config_file_name = tempfile.mkstemp()
207
    try:
208
        os.close(fd)
209
        config_file = open(config_file_name, 'w')
210
        try:
211
            print >> config_file, 'advertised = False'
212
        finally:
213
            config_file.close()
5046.3.2 by Barry Warsaw
Some modifications in response to Francis's comments.
214
        return subprocess.call(
215
            ('./config_list', '-i', config_file_name, site_list_name),
216
            cwd=mailman_bin)
4897.4.6 by Barry Warsaw
The first step toward a comprehensive Launchpad/Mailman integration test.
217
    finally:
218
        os.remove(config_file_name)
219
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
220
221
def main():
222
    # setting python paths
223
    program = sys.argv[0]
224
225
    src = 'lib'
226
    here = os.path.dirname(os.path.abspath(program))
227
    srcdir = os.path.join(here, src)
228
    sys.path = [srcdir, here] + basepath
229
    return build_mailman()
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
230
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
231
232
if __name__ == '__main__':
233
    return_code = main()
234
    sys.exit(return_code)