moinsetup

moinsetup.py

4:4e672de9a373
2010-05-04 Paul Boddie Removed the use of private site definitions in favour of setting up a superuser during the Wiki setup process.
     1 #!/usr/bin/env python     2      3 from os.path import abspath, exists, join, split     4 from getpass import getpass     5 import os     6 import sys     7 import shutil     8 import re     9     10 # Regular expressions for editing MoinMoin scripts and configuration files.    11     12 def compile_definition(name):    13     return re.compile(r"^(\s*)#?(%s =).*$" % name, re.MULTILINE)    14     15 moin_cgi_prefix                 = re.compile("^#sys.path.insert\(0, 'PREFIX.*$", re.MULTILINE)    16 moin_cgi_wikiconfig             = re.compile("^#sys.path.insert\(0, '/path/to/wikiconfigdir.*$", re.MULTILINE)    17 wikiconfig_py_site_name         = compile_definition("site_name")    18 wikiconfig_py_url_prefix_static = compile_definition("url_prefix_static")    19 wikiconfig_py_superuser         = compile_definition("superuser")    20 wikiconfig_py_acl_rights_before = compile_definition("acl_rights_before")    21 wikiconfig_py_page_front_page   = compile_definition("page_front_page")    22 wikiconfig_py_data_dir          = compile_definition("data_dir")    23 wikiconfig_py_data_underlay_dir = compile_definition("data_underlay_dir")    24     25 # Templates for Apache site definitions.    26     27 apache_site = """    28 ScriptAlias %(url_path)s "%(web_app_dir)s/moin.cgi"    29 """    30     31 apache_site_extra_moin18 = """    32 Alias %(static_url_path)s "%(htdocs_dir)s/"    33 """    34     35 # Utility functions.    36     37 def readfile(filename):    38     f = open(filename)    39     try:    40         return f.read()    41     finally:    42         f.close()    43     44 def writefile(filename, s):    45     f = open(filename, "w")    46     try:    47         f.write(s)    48     finally:    49         f.close()    50     51 def status(message):    52     print message    53     54 def note(message):    55     print message    56     57 class Installation:    58     59     "A class for installing and initialising MoinMoin."    60     61     # NOTE: Need to detect Web server user.    62     63     web_user = "www-data"    64     web_group = "www-data"    65     66     def __init__(self, moin_distribution, prefix, web_app_dir, web_site_dir,    67         common_dir, url_path, site_name, front_page_name, superuser):    68     69         """    70         Initialise a Wiki installation using the following:    71     72           * moin_distribution - the directory containing a MoinMoin source    73                                 distribution    74           * prefix            - the installation prefix (equivalent to /usr)    75           * web_app_dir       - the directory where Web applications and scripts    76                                 reside (such as /home/www-user/cgi-bin)    77           * web_site_dir      - the directory where Web site definitions reside    78                                 (such as /etc/apache2/sites-available)    79           * common_dir        - the directory where the Wiki configuration,    80                                 resources and instance will reside (such as    81                                 /home/www-user/mywiki)    82           * url_path          - the URL path at which the Wiki will be made    83                                 available (such as / or /mywiki)    84           * site_name         - the name of the site (such as "My Wiki")    85           * front_page_name   - the front page name for the site (such as    86                                 "FrontPage" or a specific name for the site)    87           * superuser         - the name of the site's superuser (such as    88                                 "AdminUser")    89         """    90     91         self.moin_distribution = moin_distribution    92         self.site_name = site_name    93         self.front_page_name = front_page_name    94         self.superuser = superuser    95     96         # NOTE: Support the detection of the Apache sites directory.    97     98         self.prefix, self.web_app_dir, self.web_site_dir, self.common_dir = \    99             map(abspath, (prefix, web_app_dir, web_site_dir, common_dir))   100    101         # Strip any trailing "/" from the URL path.   102    103         if url_path.endswith("/"):   104             self.url_path = url_path[:-1]   105         else:   106             self.url_path = url_path   107    108         # Define and create specific directories.   109    110         self.conf_dir = join(self.common_dir, "conf")   111         self.instance_dir = join(self.common_dir, "wikidata")   112    113         # For MoinMoin 1.8.x and earlier.   114    115         self.htdocs_dir = join(self.instance_dir, "share", "moin", "htdocs")   116    117         # Miscellaneous configuration options.   118    119         self.superuser_client_host = "127.0.0.1"   120    121         # Find the version.   122    123         self.moin_version = self.get_moin_version()   124    125     def get_moin_version(self):   126    127         "Inspect the MoinMoin package information, returning the version."   128    129         this_dir = os.getcwd()   130         os.chdir(self.moin_distribution)   131    132         f = open("PKG-INFO")   133         try:   134             for line in f.xreadlines():   135                 columns = line.split()   136                 if columns[0] == "Version:":   137                     return columns[1]   138    139             return None   140    141         finally:   142             f.close()   143             os.chdir(this_dir)   144    145     def setup(self):   146    147         "Set up the installation."   148    149         for d in (self.conf_dir, self.instance_dir, self.web_app_dir, self.web_site_dir):   150             if not exists(d):   151                 os.makedirs(d)   152    153         self.install_moin()   154         self.install_data()   155         self.configure_moin()   156         self.edit_moin_scripts()   157         self.add_superuser()   158         self.make_site_files()   159         self.make_post_install_script()   160    161     def install_moin(self):   162    163         "Enter the distribution directory and run the setup script."   164    165         # NOTE: Possibly check for an existing installation and skip repeated   166         # NOTE: installation attempts.   167    168         this_dir = os.getcwd()   169         os.chdir(self.moin_distribution)   170    171         log_filename = "install-%s.log" % split(self.common_dir)[-1]   172    173         status("Installing MoinMoin in %s..." % self.prefix)   174    175         os.system("python setup.py --quiet install --force --prefix='%s' --install-data='%s' --record='%s'" % (   176             self.prefix, self.instance_dir, log_filename))   177    178         os.chdir(this_dir)   179    180     def install_data(self):   181    182         "Install Wiki data."   183    184         # The default wikiconfig assumes data and underlay in the same directory.   185    186         status("Installing data and underlay in %s..." % self.conf_dir)   187    188         for d in ("data", "underlay"):   189             shutil.copytree(join(self.moin_distribution, "wiki", d), join(self.conf_dir, d))   190    191     def configure_moin(self):   192    193         "Edit the Wiki configuration file."   194    195         # NOTE: Single Wiki only so far.   196    197         # Static URLs seem to be different in MoinMoin 1.9.x.   198         # For earlier versions, reserve URL space alongside the Wiki.   199         # NOTE: MoinMoin usually uses an apparently common URL space associated   200         # NOTE: with the version, but more specific locations are probably   201         # NOTE: acceptable if less efficient.   202    203         if self.moin_version.startswith("1.9"):   204             self.static_url_path = self.url_path   205             url_prefix_static_sub = r"\1\2 %r + url_prefix_static" % self.static_url_path   206         else:   207             self.static_url_path = self.url_path + "-static"   208             url_prefix_static_sub = r"\1\2 %r" % self.static_url_path   209    210         # Edit the Wiki configuration file.   211    212         wikiconfig_py = join(self.moin_distribution, "wiki", "config", "wikiconfig.py")   213    214         status("Editing configuration from %s..." % wikiconfig_py)   215    216         s = readfile(wikiconfig_py)   217         s = wikiconfig_py_site_name.sub(r"\1\2 %r" % self.site_name, s)   218         s = wikiconfig_py_url_prefix_static.sub(url_prefix_static_sub, s)   219         s = wikiconfig_py_superuser.sub(r"\1\2 %r" % [self.superuser], s)   220         s = wikiconfig_py_acl_rights_before.sub(r"\1\2 %r" % (u"%s:read,write,delete,revert,admin" % self.superuser), s)   221         s = wikiconfig_py_page_front_page.sub(r"\1\2 %r" % self.front_page_name, s, count=1)   222    223         if not self.moin_version.startswith("1.9"):   224             data_dir = join(self.conf_dir, "data")   225             data_underlay_dir = join(self.conf_dir, "underlay")   226    227             s = wikiconfig_py_data_dir.sub(r"\1\2 %r" % data_dir, s)   228             s = wikiconfig_py_data_underlay_dir.sub(r"\1\2 %r" % data_underlay_dir, s)   229    230         writefile(join(self.conf_dir, "wikiconfig.py"), s)   231    232     def edit_moin_scripts(self):   233    234         "Edit the moin script and the CGI script."   235    236         moin_script = join(self.prefix, "bin", "moin")   237         prefix_site_packages = join(self.prefix, "lib", "python%s.%s" % sys.version_info[:2], "site-packages")   238    239         status("Editing moin script at %s..." % moin_script)   240    241         s = readfile(moin_script)   242         s = s.replace("#import sys", "import sys\nsys.path.insert(0, %r)" % prefix_site_packages)   243    244         writefile(moin_script, s)   245    246         # Edit and install CGI script.   247         # NOTE: CGI only so far.   248         # NOTE: Permissions should be checked.   249    250         moin_cgi = join(self.instance_dir, "share", "moin", "server", "moin.cgi")   251         moin_cgi_installed = join(self.web_app_dir, "moin.cgi")   252    253         status("Editing moin.cgi script from %s..." % moin_cgi)   254    255         s = readfile(moin_cgi)   256         s = moin_cgi_prefix.sub("sys.path.insert(0, %r)" % prefix_site_packages, s)   257         s = moin_cgi_wikiconfig.sub("sys.path.insert(0, %r)" % self.conf_dir, s)   258    259         writefile(moin_cgi_installed, s)   260         os.system("chmod a+rx '%s'" % moin_cgi_installed)   261    262     def add_superuser(self):   263    264         "Add the superuser account."   265    266         moin_script = join(self.prefix, "bin", "moin")   267    268         print "Creating superuser", self.superuser, "using..."   269         email = raw_input("E-mail address: ")   270         password = getpass("Password: ")   271    272         path = os.environ.get("PYTHONPATH", "")   273    274         if path:   275             os.environ["PYTHONPATH"] = path + ":" + self.conf_dir   276         else:   277             os.environ["PYTHONPATH"] = self.conf_dir   278    279         os.system(moin_script + " account create --name='%s' --email='%s' --password='%s'" % (self.superuser, email, password))   280    281         if path:   282             os.environ["PYTHONPATH"] = path   283         else:   284             del os.environ["PYTHONPATH"]   285    286     def make_site_files(self):   287    288         "Make the Apache site files."   289    290         # NOTE: Using local namespace for substitution.   291    292         site_def = join(self.web_site_dir, self.site_name)   293         site_def_private = join(self.web_site_dir, "%s-private" % self.site_name)   294    295         status("Writing Apache site definitions to %s and %s..." % (site_def, site_def_private))   296    297         s = apache_site % self.__dict__   298    299         if not self.moin_version.startswith("1.9"):   300             s += apache_site_extra_moin18 % self.__dict__   301    302         writefile(site_def, s)   303    304     def make_post_install_script(self):   305    306         "Write a post-install script with additional actions."   307    308         this_user = os.environ["USER"]   309         postinst_script = "moinsetup-post.sh"   310    311         s = "#!/bin/sh\n"   312    313         for d in ("data", "underlay"):   314             s += "chown -R %s.%s '%s'\n" % (this_user, self.web_group, join(self.conf_dir, d))   315             s += "chmod -R g+w '%s'\n" % join(self.conf_dir, d)   316    317         if not self.moin_version.startswith("1.9"):   318             s += "chown -R %s.%s '%s'\n" % (this_user, self.web_group, self.htdocs_dir)   319    320         writefile(postinst_script, s)   321         os.chmod(postinst_script, 0755)   322         note("Run %s as root to set file ownership and permissions." % postinst_script)   323    324 # Main program.   325    326 if __name__ == "__main__":   327    328     # Obtain as many arguments as needed for the setup function.   329    330     try:   331         n = 9 # number of Installation initialiser arguments   332         args = sys.argv[1:n+1]   333         args[n-1]   334     except (IndexError, ValueError):   335         print Installation.__init__.__doc__   336         sys.exit(1)   337    338     installation = Installation(*args)   339     installation.setup()   340    341 # vim: tabstop=4 expandtab shiftwidth=4