Code

use config.DATABASE in cases where 'db' was still hard-coded
[roundup.git] / roundup / init.py
index b41561c4d1e4dd53e022d8e951230ea896751a29..d4afecc9e8a50da5e33c7fc7d0dee6a3ff4e6918 100644 (file)
 # FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
-# 
-# $Id: init.py,v 1.15 2001-08-07 00:24:42 richard Exp $
+#
+# $Id: init.py,v 1.36 2005-12-03 11:22:50 a1s Exp $
+
+"""Init (create) a roundup instance.
+"""
+__docformat__ = 'restructuredtext'
 
-import os, shutil, sys, errno
+import os, errno, rfc822
 
-import roundup.instance
+from roundup import install_util, password
+from roundup.configuration import CoreConfig
+from roundup.i18n import _
 
 def copytree(src, dst, symlinks=0):
-    """Recursively copy a directory tree using copy2().
+    """Recursively copy a directory tree using copyDigestedFile().
 
-    The destination directory os allowed to exist.
+    The destination directory is allowed to exist.
 
     If the optional symlinks flag is true, symbolic links in the
     source tree result in symbolic links in the destination tree; if
     it is false, the contents of the files pointed to by symbolic
     links are copied.
 
-    XXX copied from shutil.py in std lib
-
+    This was copied from shutil.py in std lib.
     """
-    names = os.listdir(src)
+
+    # Prevent 'hidden' files (those starting with '.') from being considered.
+    names = [f for f in os.listdir(src) if not f.startswith('.')]
     try:
         os.mkdir(dst)
     except OSError, error:
@@ -48,111 +55,139 @@ def copytree(src, dst, symlinks=0):
         elif os.path.isdir(srcname):
             copytree(srcname, dstname, symlinks)
         else:
-            shutil.copy2(srcname, dstname)
+            install_util.copyDigestedFile(srcname, dstname)
 
-def init(instance_home, template, backend, adminpw):
-    '''Initialise an instance using the named template and backend.
+def install(instance_home, template, settings={}):
+    '''Install an instance using the named template and backend.
 
-    instance_home - the directory to place the instance data in
-    template - the template to use in creating the instance data
-    backend - the database to use to store the instance data
-    adminpw - the password for the "admin" user
+    'instance_home'
+       the directory to place the instance data in
+    'template'
+       the directory holding the template to use in creating the instance data
+    'settings'
+       config.ini setting overrides (dictionary)
 
     The instance_home directory will be created using the files found in
-    the named template (roundup.templates.<name>). A standard instance_home
+    the named template (roundup.templates.<name>). A usual instance_home
     contains:
-        . instance_config.py
-          - simple configuration of things like the email address for the
-            mail gateway, the mail domain, the mail host, ...
-        . dbinit.py and select_db.py
-          - defines the schema for the hyperdatabase and indicates which
-            backend to use.
-        . interfaces.py
-          - defines the CGI Client and mail gateway MailGW classes that are
-            used by roundup.cgi, roundup-server and roundup-mailgw.
-        . __init__.py
-          - ties together all the instance information into one interface
-        . db/
-          - the actual database that stores the instance's data
-        . html/
-          - the html templates that are used by the CGI Client
-        . detectors/
-          - the auditor and reactor modules for this instance
-
-    The html directory is typically extracted from the htmlbase module in
-    the template.
-    '''
-    # first, copy the template dir over
-    import roundup.templatebuilder
 
-    template_dir = os.path.split(__file__)[0]
-    template_name = template
-    template = os.path.join(template_dir, 'templates', template)
+    config.ini
+      tracker configuration file
+    schema.py
+      database schema definition
+    initial_data.py
+      database initialization script, used to populate the database
+      with 'roundup-admin init' command
+    interfaces.py
+      (optional, not installed from standard templates) defines
+      the CGI Client and mail gateway MailGW classes that are
+      used by roundup.cgi, roundup-server and roundup-mailgw.
+    db/
+      the actual database that stores the instance's data
+    html/
+      the html templates that are used by the CGI Client
+    detectors/
+      the auditor and reactor modules for this instance
+    extensions/
+      code extensions to Roundup
+    '''
+    # At the moment, it's just a copy
     copytree(template, instance_home)
 
-    roundup.templatebuilder.installHtmlBase(template_name, instance_home)
+    # rename the tempate in the TEMPLATE-INFO.txt file
+    ti = loadTemplateInfo(instance_home)
+    ti['name'] = ti['name'] + '-' + os.path.split(instance_home)[1]
+    saveTemplateInfo(instance_home, ti)
 
-    # now select database
-    db = '''# WARNING: DO NOT EDIT THIS FILE!!!
-from roundup.backends.back_%s import Database'''%backend
-    open(os.path.join(instance_home, 'select_db.py'), 'w').write(db)
+    # if there is no config.ini or old-style config.py
+    # installed from the template, write default config text
+    config_ini_file = os.path.join(instance_home, CoreConfig.INI_FILE)
+    if not os.path.isfile(config_ini_file):
+        config = CoreConfig(settings=settings)
+        config.save(config_ini_file)
 
-    # now import the instance and call its init
-    instance = roundup.instance.open(instance_home)
-    instance.init(adminpw)
 
-#
-# $Log: not supported by cvs2svn $
-# Revision 1.14  2001/08/07 00:15:51  richard
-# Added the copyright/license notice to (nearly) all files at request of
-# Bizar Software.
-#
-# Revision 1.13  2001/08/06 01:20:00  richard
-# Added documentaion.
-#
-# Revision 1.12  2001/08/05 07:43:52  richard
-# Instances are now opened by a special function that generates a unique
-# module name for the instances on import time.
-#
-# Revision 1.11  2001/08/04 22:42:43  richard
-# Fixed sf.net bug #447671 - typo
-#
-# Revision 1.10  2001/08/03 01:28:33  richard
-# Used the much nicer load_package, pointed out by Steve Majewski.
-#
-# Revision 1.9  2001/08/03 00:59:34  richard
-# Instance import now imports the instance using imp.load_module so that
-# we can have instance homes of "roundup" or other existing python package
-# names.
-#
-# Revision 1.8  2001/07/29 07:01:39  richard
-# Added vim command to all source so that we don't get no steenkin' tabs :)
-#
-# Revision 1.7  2001/07/28 07:59:53  richard
-# Replaced errno integers with their module values.
-# De-tabbed templatebuilder.py
-#
-# Revision 1.6  2001/07/24 11:18:25  anthonybaxter
-# oops. left a print in
-#
-# Revision 1.5  2001/07/24 10:54:11  anthonybaxter
-# oops. Html.
-#
-# Revision 1.4  2001/07/24 10:46:22  anthonybaxter
-# Added templatebuilder module. two functions - one to pack up the html base,
-# one to unpack it. Packed up the two standard templates into htmlbases.
-# Modified __init__ to install them.
-#
-# __init__.py magic was needed for the rather high levels of wierd import magic.
-# Reducing level of import magic == (good, future)
-#
-# Revision 1.3  2001/07/23 08:45:28  richard
-# ok, so now "./roundup-admin init" will ask questions in an attempt to get a
-# workable instance_home set up :)
-# _and_ anydbm has had its first test :)
-#
-# Revision 1.2  2001/07/22 12:09:32  richard
-# Final commit of Grande Splite
-#
-#
-# vim: set filetype=python ts=4 sw=4 et si
+def listTemplates(dir):
+    ''' List all the Roundup template directories in a given directory.
+
+        Find all the dirs that contain a TEMPLATE-INFO.txt and parse it.
+
+        Return a list of dicts of info about the templates.
+    '''
+    ret = {}
+    for idir in os.listdir(dir):
+        idir = os.path.join(dir, idir)
+        ti = loadTemplateInfo(idir)
+        if ti:
+            ret[ti['name']] = ti
+    return ret
+
+def loadTemplateInfo(dir):
+    ''' Attempt to load a Roundup template from the indicated directory.
+
+        Return None if there's no template, otherwise a template info
+        dictionary.
+    '''
+    ti = os.path.join(dir, 'TEMPLATE-INFO.txt')
+    if not os.path.exists(ti):
+        return None
+
+    if os.path.exists(os.path.join(dir, 'config.py')):
+        print _("WARNING: directory '%s'\n"
+            "\tcontains old-style template - ignored"
+            ) % os.path.abspath(dir)
+        return None
+
+    # load up the template's information
+    f = open(ti)
+    try:
+        m = rfc822.Message(open(ti))
+        ti = {}
+        ti['name'] = m['name']
+        ti['description'] = m['description']
+        ti['intended-for'] = m['intended-for']
+        ti['path'] = dir
+    finally:
+        f.close()
+    return ti
+
+def writeHeader(name, value):
+    ''' Write an rfc822-compatible header line, making it wrap reasonably
+    '''
+    out = [name.capitalize() + ':']
+    n = len(out[0])
+    for word in value.split():
+        if len(word) + n > 74:
+            out.append('\n')
+            n = 0
+        out.append(' ' + word)
+        n += len(out[-1])
+    return ''.join(out) + '\n'
+
+def saveTemplateInfo(dir, info):
+    ''' Save the template info (dict of values) to the TEMPLATE-INFO.txt
+        file in the indicated directory.
+    '''
+    ti = os.path.join(dir, 'TEMPLATE-INFO.txt')
+    f = open(ti, 'w')
+    try:
+        for name in 'name description intended-for path'.split():
+            f.write(writeHeader(name, info[name]))
+    finally:
+        f.close()
+
+def write_select_db(instance_home, backend, dbdir = 'db'):
+    ''' Write the file that selects the backend for the tracker
+    '''
+    # dbdir may be a relative pathname, os.path.join does the right
+    # thing when the second component of a join is an absolute path
+    dbdir = os.path.join (instance_home, dbdir)
+    if not os.path.exists(dbdir):
+        os.makedirs(dbdir)
+    f = open(os.path.join(dbdir, 'backend_name'), 'w')
+    f.write(backend+'\n')
+    f.close()
+
+
+
+# vim: set filetype=python sts=4 sw=4 et si :