moinsetup

Changeset

2:9af79935e78d
2010-05-03 Paul Boddie raw files shortlog changelog graph Converted the setup function into a class, dividing the work between a number of different methods. Added support for MoinMoin 1.8.x and earlier, along with version detection. Added localhost-only site definitions. Introduced a function for the compilation of Wiki configuration file search definitions. Moved the notes into a post-installation script. Changed the owner of data files to that of the user running the script.
moinsetup.py (file)
     1.1 --- a/moinsetup.py	Sat May 01 02:54:58 2010 +0200
     1.2 +++ b/moinsetup.py	Mon May 03 01:21:45 2010 +0200
     1.3 @@ -8,13 +8,18 @@
     1.4  
     1.5  # Regular expressions for editing MoinMoin scripts and configuration files.
     1.6  
     1.7 -moin_cgi_prefix = re.compile("^#sys.path.insert\(0, 'PREFIX.*$", re.MULTILINE)
     1.8 -moin_cgi_wikiconfig = re.compile("^#sys.path.insert\(0, '/path/to/wikiconfigdir.*$", re.MULTILINE)
     1.9 -wikiconfig_py_site_name = re.compile(r"^(\s*sitename =).*$", re.MULTILINE)
    1.10 -wikiconfig_py_url_prefix_static = re.compile(r"^(\s*)#(url_prefix_static =).*$", re.MULTILINE)
    1.11 -wikiconfig_py_superuser = re.compile(r"^(\s*)#(superuser =).*$", re.MULTILINE)
    1.12 -wikiconfig_py_acl_rights_before = re.compile(r"^(\s*)#(acl_rights_before =).*$", re.MULTILINE)
    1.13 -wikiconfig_py_page_front_page = re.compile(r"^(\s*)#(page_front_page =).*$", re.MULTILINE)
    1.14 +def compile_definition(name):
    1.15 +    return re.compile(r"^(\s*)#?(%s =).*$" % name, re.MULTILINE)
    1.16 +
    1.17 +moin_cgi_prefix                 = re.compile("^#sys.path.insert\(0, 'PREFIX.*$", re.MULTILINE)
    1.18 +moin_cgi_wikiconfig             = re.compile("^#sys.path.insert\(0, '/path/to/wikiconfigdir.*$", re.MULTILINE)
    1.19 +wikiconfig_py_site_name         = compile_definition("site_name")
    1.20 +wikiconfig_py_url_prefix_static = compile_definition("url_prefix_static")
    1.21 +wikiconfig_py_superuser         = compile_definition("superuser")
    1.22 +wikiconfig_py_acl_rights_before = compile_definition("acl_rights_before")
    1.23 +wikiconfig_py_page_front_page   = compile_definition("page_front_page")
    1.24 +wikiconfig_py_data_dir          = compile_definition("data_dir")
    1.25 +wikiconfig_py_data_underlay_dir = compile_definition("data_underlay_dir")
    1.26  
    1.27  # Templates for Apache site definitions.
    1.28  
    1.29 @@ -23,7 +28,14 @@
    1.30  """
    1.31  
    1.32  apache_site_extra_moin18 = """
    1.33 -Alias %(static_path)s "%(prefix)s/share/moin/htdocs/"
    1.34 +Alias %(static_url_path)s "%(htdocs_dir)s/"
    1.35 +"""
    1.36 +
    1.37 +apache_site_host_restriction = """
    1.38 +<Location "%(url_path)s">
    1.39 +    Deny from all
    1.40 +    Allow from %(superuser_client_host)s
    1.41 +</Location>
    1.42  """
    1.43  
    1.44  # Utility functions.
    1.45 @@ -48,122 +60,253 @@
    1.46  def note(message):
    1.47      print message
    1.48  
    1.49 -# NOTE: Support the detection of the Apache sites directory.
    1.50 -
    1.51 -def setup(moin_distribution, prefix, web_app_dir, web_site_dir, common_dir, url_path, site_name, front_page_name, superuser):
    1.52 -
    1.53 -    """
    1.54 -    Set up a Wiki installation using the following:
    1.55 -
    1.56 -      * moin_distribution - the directory containing a MoinMoin source
    1.57 -                            distribution
    1.58 -      * prefix            - the installation prefix (equivalent to /usr)
    1.59 -      * web_app_dir       - the directory where Web applications and scripts
    1.60 -                            reside (such as /home/www-user/cgi-bin)
    1.61 -      * web_site_dir      - the directory where Web site definitions reside
    1.62 -                            (such as /etc/apache2/sites-available)
    1.63 -      * common_dir        - the directory where the Wiki configuration,
    1.64 -                            resources and instance will reside (such as
    1.65 -                            /home/www-user/mywiki)
    1.66 -      * url_path          - the URL path at which the Wiki will be made
    1.67 -                            available (such as / or /mywiki)
    1.68 -      * site_name         - the name of the site (such as "My Wiki")
    1.69 -      * front_page_name   - the front page name for the site (such as
    1.70 -                            "FrontPage" or a specific name for the site)
    1.71 -      * superuser         - the name of the site's superuser (such as
    1.72 -                            "AdminUser")
    1.73 -    """
    1.74 -
    1.75 -    prefix, web_app_dir, web_site_dir, common_dir = map(abspath, (prefix, web_app_dir, web_site_dir, common_dir))
    1.76 -
    1.77 -    conf_dir = join(common_dir, "conf")
    1.78 -    instance_dir = join(common_dir, "wikidata")
    1.79 -
    1.80 -    for d in (conf_dir, instance_dir, web_app_dir, web_site_dir):
    1.81 -        if not exists(d):
    1.82 -            os.makedirs(d)
    1.83 -
    1.84 -    # Enter the distribution directory and run the setup script.
    1.85 -
    1.86 -    this_dir = os.getcwd()
    1.87 -    os.chdir(moin_distribution)
    1.88 -
    1.89 -    log_filename = "install-%s.log" % split(common_dir)[-1]
    1.90 -
    1.91 -    status("Installing MoinMoin in %s..." % prefix)
    1.92 -
    1.93 -    os.system("python setup.py --quiet install --force --prefix='%s' --install-data='%s' --record='%s'" % (
    1.94 -        prefix, instance_dir, log_filename))
    1.95 -
    1.96 -    os.chdir(this_dir)
    1.97 -
    1.98 -    # The default wikiconfig assumes data and underlay in the same directory.
    1.99 -
   1.100 -    status("Installing data and underlay in %s..." % conf_dir)
   1.101 +class Installation:
   1.102  
   1.103 -    for d in ("data", "underlay"):
   1.104 -        shutil.copytree(join(moin_distribution, "wiki", d), join(conf_dir, d))
   1.105 -
   1.106 -    # NOTE: Single Wiki only so far.
   1.107 -    # NOTE: Static URLs seem to be different in MoinMoin 1.9.x.
   1.108 -
   1.109 -    wikiconfig_py = join(moin_distribution, "wiki", "config", "wikiconfig.py")
   1.110 -
   1.111 -    status("Editing configuration from %s..." % wikiconfig_py)
   1.112 -
   1.113 -    s = readfile(wikiconfig_py)
   1.114 -    s = wikiconfig_py_site_name.sub(r"\1 %r" % site_name, s)
   1.115 -    s = wikiconfig_py_url_prefix_static.sub(r"\1\2 %r + url_prefix_static" % url_path, s)
   1.116 -    s = wikiconfig_py_superuser.sub(r"\1\2 %r" % [superuser], s)
   1.117 -    s = wikiconfig_py_acl_rights_before.sub(r"\1\2 %r" % (u"%s:read,write,delete,revert,admin" % superuser), s)
   1.118 -    s = wikiconfig_py_page_front_page.sub(r"\1\2 %r" % front_page_name, s, count=1)
   1.119 -    writefile(join(conf_dir, "wikiconfig.py"), s)
   1.120 -
   1.121 -    # Edit moin script.
   1.122 -
   1.123 -    moin_script = join(prefix, "bin", "moin")
   1.124 -    prefix_site_packages = join(prefix, "lib", "python%s.%s" % sys.version_info[:2], "site-packages")
   1.125 -
   1.126 -    status("Editing moin script at %s..." % moin_script)
   1.127 -
   1.128 -    s = readfile(moin_script)
   1.129 -    s = s.replace("#import sys", "import sys\nsys.path.insert(0, %r)" % prefix_site_packages)
   1.130 +    "A class for installing and initialising MoinMoin."
   1.131  
   1.132 -    writefile(moin_script, s)
   1.133 -
   1.134 -    # Edit and install CGI script.
   1.135 -    # NOTE: CGI only so far.
   1.136 -    # NOTE: Permissions should be checked.
   1.137 -
   1.138 -    moin_cgi = join(instance_dir, "share", "moin", "server", "moin.cgi")
   1.139 -    moin_cgi_installed = join(web_app_dir, "moin.cgi")
   1.140 -
   1.141 -    status("Editing moin.cgi script from %s..." % moin_cgi)
   1.142 -
   1.143 -    s = readfile(moin_cgi)
   1.144 -    s = moin_cgi_prefix.sub("sys.path.insert(0, %r)" % prefix_site_packages, s)
   1.145 -    s = moin_cgi_wikiconfig.sub("sys.path.insert(0, %r)" % conf_dir, s)
   1.146 -
   1.147 -    writefile(moin_cgi_installed, s)
   1.148 -    os.system("chmod a+rx '%s'" % moin_cgi_installed)
   1.149 -
   1.150 -    # Configure server.
   1.151 -    # NOTE: Need to work with older MoinMoin versions.
   1.152 -    # NOTE: Using local namespace for substitution.
   1.153 -
   1.154 -    site_def = join(web_site_dir, site_name)
   1.155 -    status("Writing Apache site definition to %s..." % site_def)
   1.156 -
   1.157 -    writefile(site_def, apache_site % locals())
   1.158 -
   1.159 -    # General notes.
   1.160      # NOTE: Need to detect Web server user.
   1.161  
   1.162      web_user = "www-data"
   1.163      web_group = "www-data"
   1.164  
   1.165 -    for d in ("data", "underlay"):
   1.166 -        note("chown -R %s.%s '%s'" % (web_user, web_group, join(conf_dir, d)))
   1.167 +    def __init__(self, moin_distribution, prefix, web_app_dir, web_site_dir,
   1.168 +        common_dir, url_path, site_name, front_page_name, superuser):
   1.169 +
   1.170 +        """
   1.171 +        Initialise a Wiki installation using the following:
   1.172 +
   1.173 +          * moin_distribution - the directory containing a MoinMoin source
   1.174 +                                distribution
   1.175 +          * prefix            - the installation prefix (equivalent to /usr)
   1.176 +          * web_app_dir       - the directory where Web applications and scripts
   1.177 +                                reside (such as /home/www-user/cgi-bin)
   1.178 +          * web_site_dir      - the directory where Web site definitions reside
   1.179 +                                (such as /etc/apache2/sites-available)
   1.180 +          * common_dir        - the directory where the Wiki configuration,
   1.181 +                                resources and instance will reside (such as
   1.182 +                                /home/www-user/mywiki)
   1.183 +          * url_path          - the URL path at which the Wiki will be made
   1.184 +                                available (such as / or /mywiki)
   1.185 +          * site_name         - the name of the site (such as "My Wiki")
   1.186 +          * front_page_name   - the front page name for the site (such as
   1.187 +                                "FrontPage" or a specific name for the site)
   1.188 +          * superuser         - the name of the site's superuser (such as
   1.189 +                                "AdminUser")
   1.190 +        """
   1.191 +
   1.192 +        self.moin_distribution = moin_distribution
   1.193 +        self.site_name = site_name
   1.194 +        self.front_page_name = front_page_name
   1.195 +        self.superuser = superuser
   1.196 +
   1.197 +        # NOTE: Support the detection of the Apache sites directory.
   1.198 +
   1.199 +        self.prefix, self.web_app_dir, self.web_site_dir, self.common_dir = \
   1.200 +            map(abspath, (prefix, web_app_dir, web_site_dir, common_dir))
   1.201 +
   1.202 +        # Strip any trailing "/" from the URL path.
   1.203 +
   1.204 +        if url_path.endswith("/"):
   1.205 +            self.url_path = url_path[:-1]
   1.206 +        else:
   1.207 +            self.url_path = url_path
   1.208 +
   1.209 +        # Define and create specific directories.
   1.210 +
   1.211 +        self.conf_dir = join(self.common_dir, "conf")
   1.212 +        self.instance_dir = join(self.common_dir, "wikidata")
   1.213 +
   1.214 +        # For MoinMoin 1.8.x and earlier.
   1.215 +
   1.216 +        self.htdocs_dir = join(self.instance_dir, "share", "moin", "htdocs")
   1.217 +
   1.218 +        # Miscellaneous configuration options.
   1.219 +
   1.220 +        self.superuser_client_host = "127.0.0.1"
   1.221 +
   1.222 +        # Find the version.
   1.223 +
   1.224 +        self.moin_version = self.get_moin_version()
   1.225 +
   1.226 +    def get_moin_version(self):
   1.227 +
   1.228 +        "Inspect the MoinMoin package information, returning the version."
   1.229 +
   1.230 +        this_dir = os.getcwd()
   1.231 +        os.chdir(self.moin_distribution)
   1.232 +
   1.233 +        f = open("PKG-INFO")
   1.234 +        try:
   1.235 +            for line in f.xreadlines():
   1.236 +                columns = line.split()
   1.237 +                if columns[0] == "Version:":
   1.238 +                    return columns[1]
   1.239 +
   1.240 +            return None
   1.241 +
   1.242 +        finally:
   1.243 +            f.close()
   1.244 +            os.chdir(this_dir)
   1.245 +
   1.246 +    def setup(self):
   1.247 +
   1.248 +        "Set up the installation."
   1.249 +
   1.250 +        for d in (self.conf_dir, self.instance_dir, self.web_app_dir, self.web_site_dir):
   1.251 +            if not exists(d):
   1.252 +                os.makedirs(d)
   1.253 +
   1.254 +        self.install_moin()
   1.255 +        self.install_data()
   1.256 +        self.configure_moin()
   1.257 +        self.edit_moin_scripts()
   1.258 +        self.make_site_files()
   1.259 +        self.make_post_install_script()
   1.260 +
   1.261 +    def install_moin(self):
   1.262 +
   1.263 +        "Enter the distribution directory and run the setup script."
   1.264 +
   1.265 +        # NOTE: Possibly check for an existing installation and skip repeated
   1.266 +        # NOTE: installation attempts.
   1.267 +
   1.268 +        this_dir = os.getcwd()
   1.269 +        os.chdir(self.moin_distribution)
   1.270 +
   1.271 +        log_filename = "install-%s.log" % split(self.common_dir)[-1]
   1.272 +
   1.273 +        status("Installing MoinMoin in %s..." % self.prefix)
   1.274 +
   1.275 +        os.system("python setup.py --quiet install --force --prefix='%s' --install-data='%s' --record='%s'" % (
   1.276 +            self.prefix, self.instance_dir, log_filename))
   1.277 +
   1.278 +        os.chdir(this_dir)
   1.279 +
   1.280 +    def install_data(self):
   1.281 +
   1.282 +        "Install Wiki data."
   1.283 +
   1.284 +        # The default wikiconfig assumes data and underlay in the same directory.
   1.285 +
   1.286 +        status("Installing data and underlay in %s..." % self.conf_dir)
   1.287 +
   1.288 +        for d in ("data", "underlay"):
   1.289 +            shutil.copytree(join(self.moin_distribution, "wiki", d), join(self.conf_dir, d))
   1.290 +
   1.291 +    def configure_moin(self):
   1.292 +
   1.293 +        "Edit the Wiki configuration file."
   1.294 +
   1.295 +        # NOTE: Single Wiki only so far.
   1.296 +
   1.297 +        # Static URLs seem to be different in MoinMoin 1.9.x.
   1.298 +        # For earlier versions, reserve URL space alongside the Wiki.
   1.299 +        # NOTE: MoinMoin usually uses an apparently common URL space associated
   1.300 +        # NOTE: with the version, but more specific locations are probably
   1.301 +        # NOTE: acceptable if less efficient.
   1.302 +
   1.303 +        if self.moin_version.startswith("1.9"):
   1.304 +            self.static_url_path = self.url_path
   1.305 +            url_prefix_static_sub = r"\1\2 %r + url_prefix_static" % self.static_url_path
   1.306 +        else:
   1.307 +            self.static_url_path = self.url_path + "-static"
   1.308 +            url_prefix_static_sub = r"\1\2 %r" % self.static_url_path
   1.309 +
   1.310 +        # Edit the Wiki configuration file.
   1.311 +
   1.312 +        wikiconfig_py = join(self.moin_distribution, "wiki", "config", "wikiconfig.py")
   1.313 +
   1.314 +        status("Editing configuration from %s..." % wikiconfig_py)
   1.315 +
   1.316 +        s = readfile(wikiconfig_py)
   1.317 +        s = wikiconfig_py_site_name.sub(r"\1\2 %r" % self.site_name, s)
   1.318 +        s = wikiconfig_py_url_prefix_static.sub(url_prefix_static_sub, s)
   1.319 +        s = wikiconfig_py_superuser.sub(r"\1\2 %r" % [self.superuser], s)
   1.320 +        s = wikiconfig_py_acl_rights_before.sub(r"\1\2 %r" % (u"%s:read,write,delete,revert,admin" % self.superuser), s)
   1.321 +        s = wikiconfig_py_page_front_page.sub(r"\1\2 %r" % self.front_page_name, s, count=1)
   1.322 +
   1.323 +        if not self.moin_version.startswith("1.9"):
   1.324 +            data_dir = join(self.conf_dir, "data")
   1.325 +            data_underlay_dir = join(self.conf_dir, "underlay")
   1.326 +
   1.327 +            s = wikiconfig_py_data_dir.sub(r"\1\2 %r" % data_dir, s)
   1.328 +            s = wikiconfig_py_data_underlay_dir.sub(r"\1\2 %r" % data_underlay_dir, s)
   1.329 +
   1.330 +        writefile(join(self.conf_dir, "wikiconfig.py"), s)
   1.331 +
   1.332 +    def edit_moin_scripts(self):
   1.333 +
   1.334 +        "Edit the moin script and the CGI script."
   1.335 +
   1.336 +        moin_script = join(self.prefix, "bin", "moin")
   1.337 +        prefix_site_packages = join(self.prefix, "lib", "python%s.%s" % sys.version_info[:2], "site-packages")
   1.338 +
   1.339 +        status("Editing moin script at %s..." % moin_script)
   1.340 +
   1.341 +        s = readfile(moin_script)
   1.342 +        s = s.replace("#import sys", "import sys\nsys.path.insert(0, %r)" % prefix_site_packages)
   1.343 +
   1.344 +        writefile(moin_script, s)
   1.345 +
   1.346 +        # Edit and install CGI script.
   1.347 +        # NOTE: CGI only so far.
   1.348 +        # NOTE: Permissions should be checked.
   1.349 +
   1.350 +        moin_cgi = join(self.instance_dir, "share", "moin", "server", "moin.cgi")
   1.351 +        moin_cgi_installed = join(self.web_app_dir, "moin.cgi")
   1.352 +
   1.353 +        status("Editing moin.cgi script from %s..." % moin_cgi)
   1.354 +
   1.355 +        s = readfile(moin_cgi)
   1.356 +        s = moin_cgi_prefix.sub("sys.path.insert(0, %r)" % prefix_site_packages, s)
   1.357 +        s = moin_cgi_wikiconfig.sub("sys.path.insert(0, %r)" % self.conf_dir, s)
   1.358 +
   1.359 +        writefile(moin_cgi_installed, s)
   1.360 +        os.system("chmod a+rx '%s'" % moin_cgi_installed)
   1.361 +
   1.362 +    def make_site_files(self):
   1.363 +
   1.364 +        "Make the Apache site files."
   1.365 +
   1.366 +        # NOTE: Using local namespace for substitution.
   1.367 +
   1.368 +        site_def = join(self.web_site_dir, self.site_name)
   1.369 +        site_def_private = join(self.web_site_dir, "%s-private" % self.site_name)
   1.370 +
   1.371 +        status("Writing Apache site definitions to %s and %s..." % (site_def, site_def_private))
   1.372 +
   1.373 +        s = apache_site % self.__dict__
   1.374 +
   1.375 +        if not self.moin_version.startswith("1.9"):
   1.376 +            s += apache_site_extra_moin18 % self.__dict__
   1.377 +
   1.378 +        writefile(site_def, s)
   1.379 +
   1.380 +        # NOTE: By making the superuser in the installed Wiki, this site file
   1.381 +        # NOTE: would no longer be required.
   1.382 +
   1.383 +        s += apache_site_host_restriction % self.__dict__
   1.384 +
   1.385 +        writefile(site_def_private, s)
   1.386 +
   1.387 +    def make_post_install_script(self):
   1.388 +
   1.389 +        "Write a post-install script with additional actions."
   1.390 +
   1.391 +        this_user = os.environ["USER"]
   1.392 +        postinst_script = "moinsetup-post.sh"
   1.393 +
   1.394 +        s = ""
   1.395 +
   1.396 +        for d in ("data", "underlay"):
   1.397 +            s += "chown -R %s.%s '%s'\n" % (this_user, self.web_group, join(self.conf_dir, d))
   1.398 +            s += "chmod -R g+w '%s'\n" % join(self.conf_dir, d)
   1.399 +
   1.400 +        if not self.moin_version.startswith("1.9"):
   1.401 +            s += "chown -R %s.%s '%s'\n" % (this_user, self.web_group, self.htdocs_dir)
   1.402 +
   1.403 +        writefile(postinst_script, s)
   1.404 +        note("Run %s as root to set file ownership and permissions." % postinst_script)
   1.405  
   1.406  # Main program.
   1.407  
   1.408 @@ -172,13 +315,14 @@
   1.409      # Obtain as many arguments as needed for the setup function.
   1.410  
   1.411      try:
   1.412 -        n = 9 # number of setup function arguments
   1.413 +        n = 9 # number of Installation initialiser arguments
   1.414          args = sys.argv[1:n+1]
   1.415          args[n-1]
   1.416      except (IndexError, ValueError):
   1.417 -        print setup.__doc__
   1.418 +        print Installation.__init__.__doc__
   1.419          sys.exit(1)
   1.420  
   1.421 -    setup(*args)
   1.422 +    installation = Installation(*args)
   1.423 +    installation.setup()
   1.424  
   1.425  # vim: tabstop=4 expandtab shiftwidth=4