Edgewall Software

TracMultipleProjects/ComprehensiveSolution: migrate.py

File migrate.py, 7.0 kB (added by Dave Abrahams <dave@…>, 13 months ago)

The script I used to migrate my SQLite DBs to PostgreSQL. Requires trachacks:SqliteToPgScript

Line 
1# Copyright David Abrahams 2007. Distributed under the Boost
2# Software License, Version 1.0. (See accompanying
3# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5import sys
6import os
7from trac.config import Configuration
8
9parent_dir = '/usr/local/share/tracs'
10old_trac_dir = parent_dir
11new_trac_dir = '/usr/local/share/trac'
12repospath = '/usr/local/svnroot/main'
13
14dbname = 'trac'
15master_user = 'trac'
16
17def system(cmd):
18    sys.stderr.flush()
19    if noact:
20        print '--------------------------not executing:---------------------------'
21        print cmd
22        return
23    elif verbose:
24        print '--------------------------executing:---------------------------'
25        print cmd
26        sys.stdout.flush()
27       
28    status = os.system(cmd)
29    if status:
30        raise SystemError, "Exit status %s\n%r" % (status, cmd)
31    return
32
33### Read arguments and options ###
34class Args(set):
35    def __contains__(self, x):
36        super_in = super(Args,self).__contains__
37        if not x.startswith('-') and super_in('ALL'):
38            return True
39        else:
40            return super_in(x)
41   
42args = Args(sys.argv[1:])
43verbose = '-v' in args
44noact = '-n' in args
45passwd = [ x for x in args if x.startswith('-p') ][0][2:]
46if not passwd:
47    raise TypeError, 'password required in the form -pPASSWORD'
48
49### Find Tracs to Operate On ###
50children = set(os.listdir(old_trac_dir))
51tracspec = set([ o[:-1] for o in args if o.endswith(':') ])
52if tracspec:
53    children &= tracspec
54tracs = [ d for d in [ os.path.join(parent_dir,f) for f in children ]
55          if os.path.isdir(d) ]
56
57### Create Directory Structure ###
58backup_dir = os.path.join(new_trac_dir, 'projects')
59try:
60    os.makedirs(backup_dir)
61except OSError: pass
62
63for d in 'conf', 'templates', 'plugins':
64    try:
65        os.makedirs(os.path.join(new_trac_dir,'global',d))
66    except OSError: pass
67   
68### Upgrade and Backup ###
69newtracs = [ os.path.join(backup_dir, os.path.split(t)[1]) for t in tracs ]
70for t,n in zip(tracs, newtracs):
71    if 'upgrade' in args:
72        system('trac-admin "%s" upgrade' % t)
73        system('trac-admin "%s" wiki upgrade' % t)
74
75    if 'backup' in args:
76        system('trac-admin "%s" hotcopy "%s"' % (t, n))
77       
78### Adjust Paths to Point at Backups ###
79tracs = newtracs
80parent_dir = backup_dir
81
82### Create PostGreSQL Database ###
83if 'createdb' in args:
84   
85    # could be smarter about quoting passwd
86    system(
87        '''psql -d postgres -v "tracpass='%s'" -f create_multitrac_db.sql''' 
88        % passwd
89        );
90
91global_conf = os.path.join(new_trac_dir,'global','conf')
92project_trac_ini = os.path.join(global_conf, 'project-trac.ini')
93
94config_specifics = {
95    'project': ['descr', 'name', 'url'], 
96    'trac': ['base_url', 'database'],
97    }
98
99### Create Master Trac Instance ###
100if 'createmaster' in args:
101    master_env = os.path.join(parent_dir, 'master')
102    system('''trac-admin %(master_env)s initenv master'''
103           ''' "postgres://trac_instance_master:%(passwd)s'''
104           '''@localhost/%(dbname)s'''
105           '''?schema=trac_instance_master"'''
106           ''' svn "%(repospath)s"'''
107               % locals())
108
109    base_trac_ini = os.path.join(global_conf, 'base-trac.ini')
110    master_trac_ini = os.path.join(master_env,'conf','trac.ini')
111
112    # Move the master project's trac.ini into the base file
113    if not noact:
114        if verbose:
115            print 'renaming %s => %s' % (master_trac_ini, base_trac_ini)
116        os.rename(master_trac_ini, base_trac_ini)
117
118    # Make a new master config file, and move any project specifics from the
119    # base file back into it.
120    base_config = Configuration(base_trac_ini)
121    master_config = Configuration(master_trac_ini)
122    for section,names in config_specifics.items():
123        for name in names:
124            master_config.set(section,name, base_config.get(section,name))
125            base_config.remove(section, name)
126           
127    # inherit everything else from the base config file
128    master_config.set('inherit', 'file', base_trac_ini)
129
130    # set up tracforge and account manager components
131    master_components = master_config['components']
132    master_components.set('acct_mgr.*', 'enabled')
133    master_components.set('multiple_project_query_filter', 'enabled')
134    master_components.set('tracforge.*', 'enabled')
135    master_components.set('tracforge.linker.*', 'disabled')
136    master_components.set('tracforge.linker.auth.tracforgecookiemunger', 'enabled')
137    master_components.set('tracforge.subscriptions', 'disabled')
138    if not noact:
139        master_config.save()
140
141    # We're not using tracforge subscriptions
142    base_config.set('components', 'tracforge.subscriptions', 'disabled')
143
144    # Prepare global plugins and templates directories
145    base_config.set('inherit', 'templates_dir', os.path.join(new_trac_dir,'global','templates'))
146    base_config.set('inherit', 'plugins_dir', os.path.join(new_trac_dir,'global','plugins'))
147    if not noact:
148        base_config.save()
149
150    # set up a config file for individual projects
151    project_config = Configuration(project_trac_ini)
152    project_config.set('inherit', 'file', base_trac_ini)
153    project_components = project_config['components']
154    project_components.set('acct_mgr.*', 'disabled')
155    project_components.set('web.auth.loginmodule', 'disabled')
156    project_components.set('tracforge.admin.perm.*', 'enabled')
157    project_components.set('tracforge.linker.*', 'enabled')
158    project_components.set('tracforge.perms.*', 'enabled')
159    if not noact:
160        project_config.save()
161       
162### Create PostGreSQL users and translate the databases ###
163for t in tracs:
164    project = os.path.split(t)[1]
165
166    username = 'trac_instance_' + project
167
168    if 'createuser' in args:
169        system('''psql -d %(dbname)s -U %(master_user)s<<EOF
170CREATE ROLE %(username)s PASSWORD '%(passwd)s'
171  IN ROLE trac_instance LOGIN;
172 
173-- Give the master trac instance all the same
174-- permissions that this one has.
175GRANT %(username)s TO trac_instance_master;
176EOF
177''' % locals()
178               )
179
180    dbstring = ('postgres://'
181               '%(username)s:%(passwd)s'
182               '@localhost/%(dbname)s'
183               '?schema=%(username)s'
184                % locals())
185
186    if 'translate' in args:
187        system('python ./sqlite2pg -t "%(parent_dir)s"'
188               ' -p "%(dbstring)s"'
189               ' %(project)s'
190               % locals()
191           );
192
193    if 'newini' in args:
194        conf = os.path.join(parent_dir, project, 'conf')
195        new_ini = os.path.join(conf, 'trac.ini')
196        old_ini = os.path.join(conf, 'trac.bak.ini')
197        if not noact:
198            os.rename(new_ini, old_ini)
199       
200        old_config = Configuration(old_ini)
201        new_config = Configuration(new_ini)
202       
203        new_config.set('inherit','file',project_trac_ini)
204        for section,names in config_specifics.items():
205            for name in names:
206                new_config.set(section, name, old_config.get(section,name))
207               
208        if not noact:
209            new_config.save()
210           
211    if 'upgrade' in args:
212        system('trac-admin "%s" upgrade --no-backup' % t)
213       
214print 'done.'
215