~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
6
import os
7
import grp
8
import pwd
9
import sys
10
import errno
7064.1.4 by Barry Warsaw
Response to Francis's review.
11
import socket
4897.4.6 by Barry Warsaw
The first step toward a comprehensive Launchpad/Mailman integration test.
12
import tempfile
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
13
import subprocess
14
4002.5.26 by Barry Warsaw
Branch fixes based on salgado's review.
15
from canonical.config import config
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
16
from lp.services.mailman.config import (
7064.1.4 by Barry Warsaw
Response to Francis's review.
17
    configure_prefix, configure_siteowner)
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.monkeypatches import monkey_patch
7465.5.1 by Gary Poster
integrate lazr.config and lazr.delegates
19
from lazr.config import as_username_groupname
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
20
5863.9.1 by Curtis Hovey
Updated configs and code to used simple datatypes. Changes may still be needed aftert testing.
21
basepath = [part for part in sys.path if part]
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
22
23
24
def build_mailman():
25
    # Build and install Mailman if it is enabled and not yet built.
5863.9.7 by Curtis Hovey
Refacortings per review.
26
    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.
27
        # 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.
28
        return 0
5863.9.7 by Curtis Hovey
Refacortings per review.
29
    mailman_path = configure_prefix(config.mailman.build_prefix)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
30
    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.
31
    var_dir = os.path.abspath(config.mailman.build_var_dir)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
32
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)
37
    try:
38
        import Mailman
11706.3.1 by Martin Pool
Better check that pseudomonkeypatches are installed into the Mailman module
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
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
44
    except ImportError:
45
        pass
46
    else:
47
        return 0
48
9328.1.2 by Max Bowsher
Make comment more detailed.
49
    # 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
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
9328.1.2 by Max Bowsher
Make comment more detailed.
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.
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.
55
    del sys.path_importer_cache[mailman_path]
56
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
57
    # Make sure the target directories exist and have the correct
58
    # permissions, otherwise configure will complain.
7064.1.4 by Barry Warsaw
Response to Francis's review.
59
    user, group = as_username_groupname(config.mailman.build_user_group)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
60
    # 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.
61
    try:
62
        uid = pwd.getpwnam(user).pw_uid
63
    except KeyError:
64
        print >> sys.stderr, 'No user found:', user
65
        sys.exit(1)
66
    try:
67
        gid = grp.getgrnam(group).gr_gid
68
    except KeyError:
69
        print >> sys.stderr, 'No group found:', group
70
        sys.exit(1)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
71
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).
76
    try:
77
        os.makedirs(var_dir)
78
    except OSError, e:
4002.5.26 by Barry Warsaw
Branch fixes based on salgado's review.
79
        if e.errno != errno.EEXIST:
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
80
            raise
81
    os.chown(var_dir, uid, gid)
82
    os.chmod(var_dir, 02775)
83
84
    mailman_source = os.path.join('sourcecode', 'mailman')
7064.1.4 by Barry Warsaw
Response to Francis's review.
85
    if config.mailman.build_host_name:
86
        build_host_name = config.mailman.build_host_name
87
    else:
88
        build_host_name = socket.getfqdn()
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
89
5427.2.1 by Barry Warsaw
Correct a bald-faced lie. Mailman's buildout for Launchpad /does/ need to set
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.
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.
92
    executable = os.path.abspath('bin/py')
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
93
    configure_args = (
94
        './configure',
95
        '--prefix', mailman_path,
96
        '--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.
97
        '--with-python=' + executable,
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
98
        '--with-username=' + user,
99
        '--with-groupname=' + group,
5427.2.1 by Barry Warsaw
Correct a bald-faced lie. Mailman's buildout for Launchpad /does/ need to set
100
        '--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.
101
        '--with-mailhost=' + build_host_name,
102
        '--with-urlhost=' + build_host_name,
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
103
        )
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.
104
    # Configure.
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
105
    retcode = subprocess.call(configure_args, cwd=mailman_source)
106
    if retcode:
107
        print >> sys.stderr, 'Could not configure Mailman:'
108
        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.
109
    # Make.
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
110
    retcode = subprocess.call(('make', ), cwd=mailman_source)
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
111
    if retcode:
112
        print >> sys.stderr, 'Could not make Mailman.'
113
        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.
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')
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
124
    original = '#! %s\n' % (executable, )
125
    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.
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:
131
                rest = f.read()
132
                f.close()
133
                f = open(filename, 'w')
134
                f.write(modified)
135
                f.write(rest)
136
            f.close()
137
    # Now we actually install.
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
138
    retcode = subprocess.call(('make', 'install'), cwd=mailman_source)
139
    if retcode:
140
        print >> sys.stderr, 'Could not install Mailman.'
141
        sys.exit(retcode)
142
    # Try again to import the package.
143
    try:
7064.1.4 by Barry Warsaw
Response to Francis's review.
144
        # pylint: disable-msg=W0404
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
145
        import Mailman
146
    except ImportError:
147
        print >> sys.stderr, 'Could not import the Mailman package'
148
        return 1
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
149
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)
156
157
    import Mailman.mm_cfg
158
    retcode = subprocess.call(
159
        ('./config_list', '-o', '/dev/null',
160
         Mailman.mm_cfg.MAILMAN_SITE_LIST),
161
        cwd=mailman_bin,
162
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
163
164
    if retcode:
5863.9.7 by Curtis Hovey
Refacortings per review.
165
        addr, password = configure_siteowner(
166
            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
167
168
        # The site list does not yet exist, so create it now.
169
        retcode = subprocess.call(
170
            ('./newlist', '--quiet',
5863.9.1 by Curtis Hovey
Updated configs and code to used simple datatypes. Changes may still be needed aftert testing.
171
             '--emailhost=' + build_host_name,
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
172
             Mailman.mm_cfg.MAILMAN_SITE_LIST,
173
             addr, password),
174
            cwd=mailman_bin)
175
        if retcode:
176
            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
177
            return retcode
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
178
5046.3.2 by Barry Warsaw
Some modifications in response to Francis's comments.
179
    retcode = configure_site_list(
180
        mailman_bin, Mailman.mm_cfg.MAILMAN_SITE_LIST)
181
    if retcode:
182
        print >> sys.stderr, 'Could not configure site list'
183
        return retcode
184
185
    # Create a directory to hold the gzip'd tarballs for the directories of
186
    # deactivated lists.
187
    try:
188
        os.mkdir(os.path.join(Mailman.mm_cfg.VAR_PREFIX, 'backups'))
189
    except OSError, e:
190
        if e.errno != errno.EEXIST:
191
            raise
192
193
    return 0
194
195
196
def configure_site_list(mailman_bin, site_list_name):
197
    """Configure the site list.
198
11568.1.1 by Curtis Hovey
Move mailman to lp.services. Fixed staging.txt and logging.txt that were broken by
199
    Currently, the only thing we want to set is to not advertise the
200
    site list.
5046.3.2 by Barry Warsaw
Some modifications in response to Francis's comments.
201
    """
4897.4.6 by Barry Warsaw
The first step toward a comprehensive Launchpad/Mailman integration test.
202
    fd, config_file_name = tempfile.mkstemp()
203
    try:
204
        os.close(fd)
205
        config_file = open(config_file_name, 'w')
206
        try:
207
            print >> config_file, 'advertised = False'
208
        finally:
209
            config_file.close()
5046.3.2 by Barry Warsaw
Some modifications in response to Francis's comments.
210
        return subprocess.call(
211
            ('./config_list', '-i', config_file_name, site_list_name),
212
            cwd=mailman_bin)
4897.4.6 by Barry Warsaw
The first step toward a comprehensive Launchpad/Mailman integration test.
213
    finally:
214
        os.remove(config_file_name)
215
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
216
217
def main():
218
    # setting python paths
219
    program = sys.argv[0]
220
221
    src = 'lib'
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()
4002.5.31 by Barry Warsaw
Updates to the mmbuild branch based on feedback from SteveA and spiv over
226
4002.5.14 by Barry Warsaw
Changes to address jamesh's review comments.
227
228
if __name__ == '__main__':
229
    return_code = main()
230
    sys.exit(return_code)