Code

svn repository setup
[roundup.git] / roundup / init.py
1 #
2 # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
6 #
7 # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
8 # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
9 # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
10 # POSSIBILITY OF SUCH DAMAGE.
11 #
12 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17 #
18 # $Id: init.py,v 1.36 2005-12-03 11:22:50 a1s Exp $
20 """Init (create) a roundup instance.
21 """
22 __docformat__ = 'restructuredtext'
24 import os, errno, rfc822
26 from roundup import install_util, password
27 from roundup.configuration import CoreConfig
28 from roundup.i18n import _
30 def copytree(src, dst, symlinks=0):
31     """Recursively copy a directory tree using copyDigestedFile().
33     The destination directory os allowed to exist.
35     If the optional symlinks flag is true, symbolic links in the
36     source tree result in symbolic links in the destination tree; if
37     it is false, the contents of the files pointed to by symbolic
38     links are copied.
40     This was copied from shutil.py in std lib.
41     """
42     names = os.listdir(src)
43     try:
44         os.mkdir(dst)
45     except OSError, error:
46         if error.errno != errno.EEXIST: raise
47     for name in names:
48         srcname = os.path.join(src, name)
49         dstname = os.path.join(dst, name)
50         if symlinks and os.path.islink(srcname):
51             linkto = os.readlink(srcname)
52             os.symlink(linkto, dstname)
53         elif os.path.isdir(srcname):
54             copytree(srcname, dstname, symlinks)
55         else:
56             install_util.copyDigestedFile(srcname, dstname)
58 def install(instance_home, template, settings={}):
59     '''Install an instance using the named template and backend.
61     'instance_home'
62        the directory to place the instance data in
63     'template'
64        the directory holding the template to use in creating the instance data
65     'settings'
66        config.ini setting overrides (dictionary)
68     The instance_home directory will be created using the files found in
69     the named template (roundup.templates.<name>). A usual instance_home
70     contains:
72     config.ini
73       tracker configuration file
74     schema.py
75       database schema definition
76     initial_data.py
77       database initialization script, used to populate the database
78       with 'roundup-admin init' command
79     interfaces.py
80       (optional, not installed from standard templates) defines
81       the CGI Client and mail gateway MailGW classes that are
82       used by roundup.cgi, roundup-server and roundup-mailgw.
83     db/
84       the actual database that stores the instance's data
85     html/
86       the html templates that are used by the CGI Client
87     detectors/
88       the auditor and reactor modules for this instance
89     extensions/
90       code extensions to Roundup
91     '''
92     # At the moment, it's just a copy
93     copytree(template, instance_home)
95     # rename the tempate in the TEMPLATE-INFO.txt file
96     ti = loadTemplateInfo(instance_home)
97     ti['name'] = ti['name'] + '-' + os.path.split(instance_home)[1]
98     saveTemplateInfo(instance_home, ti)
100     # if there is no config.ini or old-style config.py
101     # installed from the template, write default config text
102     config_ini_file = os.path.join(instance_home, CoreConfig.INI_FILE)
103     if not os.path.isfile(config_ini_file):
104         config = CoreConfig(settings=settings)
105         config.save(config_ini_file)
108 def listTemplates(dir):
109     ''' List all the Roundup template directories in a given directory.
111         Find all the dirs that contain a TEMPLATE-INFO.txt and parse it.
113         Return a list of dicts of info about the templates.
114     '''
115     ret = {}
116     for idir in os.listdir(dir):
117         idir = os.path.join(dir, idir)
118         ti = loadTemplateInfo(idir)
119         if ti:
120             ret[ti['name']] = ti
121     return ret
123 def loadTemplateInfo(dir):
124     ''' Attempt to load a Roundup template from the indicated directory.
126         Return None if there's no template, otherwise a template info
127         dictionary.
128     '''
129     ti = os.path.join(dir, 'TEMPLATE-INFO.txt')
130     if not os.path.exists(ti):
131         return None
133     if os.path.exists(os.path.join(dir, 'config.py')):
134         print _("WARNING: directory '%s'\n"
135             "\tcontains old-style template - ignored"
136             ) % os.path.abspath(dir)
137         return None
139     # load up the template's information
140     f = open(ti)
141     try:
142         m = rfc822.Message(open(ti))
143         ti = {}
144         ti['name'] = m['name']
145         ti['description'] = m['description']
146         ti['intended-for'] = m['intended-for']
147         ti['path'] = dir
148     finally:
149         f.close()
150     return ti
152 def writeHeader(name, value):
153     ''' Write an rfc822-compatible header line, making it wrap reasonably
154     '''
155     out = [name.capitalize() + ':']
156     n = len(out[0])
157     for word in value.split():
158         if len(word) + n > 74:
159             out.append('\n')
160             n = 0
161         out.append(' ' + word)
162         n += len(out[-1])
163     return ''.join(out) + '\n'
165 def saveTemplateInfo(dir, info):
166     ''' Save the template info (dict of values) to the TEMPLATE-INFO.txt
167         file in the indicated directory.
168     '''
169     ti = os.path.join(dir, 'TEMPLATE-INFO.txt')
170     f = open(ti, 'w')
171     try:
172         for name in 'name description intended-for path'.split():
173             f.write(writeHeader(name, info[name]))
174     finally:
175         f.close()
177 def write_select_db(instance_home, backend):
178     ''' Write the file that selects the backend for the tracker
179     '''
180     dbdir = os.path.join(instance_home, 'db')
181     if not os.path.exists(dbdir):
182         os.makedirs(dbdir)
183     f = open(os.path.join(dbdir, 'backend_name'), 'w')
184     f.write(backend+'\n')
185     f.close()
189 # vim: set filetype=python sts=4 sw=4 et si :