|
1 """Server subcube of cubicweb : defines objects used only on the server |
|
2 (repository) side |
|
3 |
|
4 This module contains functions to initialize a new repository. |
|
5 |
|
6 :organization: Logilab |
|
7 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
8 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
9 """ |
|
10 __docformat__ = "restructuredtext en" |
|
11 |
|
12 import sys |
|
13 from os.path import join, exists |
|
14 |
|
15 from logilab.common.modutils import LazyObject |
|
16 |
|
17 # server debugging flag |
|
18 DEBUG = False |
|
19 |
|
20 def init_repository(config, interactive=True, drop=False, vreg=None): |
|
21 """initialise a repository database by creating tables add filling them |
|
22 with the minimal set of entities (ie at least the schema, base groups and |
|
23 a initial user) |
|
24 """ |
|
25 from glob import glob |
|
26 from cubicweb.schema import BASEGROUPS |
|
27 from cubicweb.dbapi import in_memory_cnx |
|
28 from cubicweb.server.repository import Repository |
|
29 from cubicweb.server.utils import manager_userpasswd |
|
30 from cubicweb.server.sqlutils import sqlexec, sqlschema, sqldropschema |
|
31 # configuration to avoid db schema loading and user'state checking |
|
32 # on connection |
|
33 read_application_schema = config.read_application_schema |
|
34 bootstrap_schema = config.bootstrap_schema |
|
35 config.read_application_schema = False |
|
36 config.creating = True |
|
37 config.bootstrap_schema = True |
|
38 config.consider_user_state = False |
|
39 config.set_language = False |
|
40 # only enable the system source at initialization time + admin which is not |
|
41 # an actual source but contains initial manager account information |
|
42 config.enabled_sources = ('system', 'admin') |
|
43 repo = Repository(config, vreg=vreg) |
|
44 assert len(repo.sources) == 1, repo.sources |
|
45 schema = repo.schema |
|
46 sourcescfg = config.sources() |
|
47 print 'creating necessary tables into the system source' |
|
48 source = sourcescfg['system'] |
|
49 driver = source['db-driver'] |
|
50 sqlcnx = repo.system_source.get_connection() |
|
51 sqlcursor = sqlcnx.cursor() |
|
52 def execute(sql, args=None): |
|
53 repo.system_source.doexec(sqlcursor, sql, args) |
|
54 if drop: |
|
55 dropsql = sqldropschema(schema, driver) |
|
56 try: |
|
57 sqlexec(dropsql, execute) |
|
58 except Exception, ex: |
|
59 print 'drop failed, skipped (%s)' % ex |
|
60 sqlcnx.rollback() |
|
61 # schema entities and relations tables |
|
62 # can't skip entities table even if system source doesn't support them, |
|
63 # they are used sometimes by generated sql. Keeping them empty is much |
|
64 # simpler than fixing this... |
|
65 if sqlcnx.logged_user != source['db-user']: |
|
66 schemasql = sqlschema(schema, driver, user=source['db-user']) |
|
67 else: |
|
68 schemasql = sqlschema(schema, driver) |
|
69 #skip_entities=[str(e) for e in schema.entities() |
|
70 # if not repo.system_source.support_entity(str(e))]) |
|
71 sqlexec(schemasql, execute) |
|
72 # install additional driver specific sql files |
|
73 for fpath in glob(join(config.schemas_lib_dir(), '*.sql.%s' % driver)): |
|
74 print 'install', fpath |
|
75 sqlexec(open(fpath).read(), execute, False, delimiter=';;') |
|
76 for directory in config.cubes_path(): |
|
77 for fpath in glob(join(directory, 'schema', '*.sql.%s' % driver)): |
|
78 print 'install', fpath |
|
79 sqlexec(open(fpath).read(), execute, False, delimiter=';;') |
|
80 sqlcursor.close() |
|
81 sqlcnx.commit() |
|
82 sqlcnx.close() |
|
83 session = repo.internal_session() |
|
84 try: |
|
85 login = unicode(sourcescfg['admin']['login']) |
|
86 pwd = sourcescfg['admin']['password'] |
|
87 except KeyError: |
|
88 if interactive: |
|
89 msg = 'enter login and password of the initial manager account' |
|
90 login, pwd = manager_userpasswd(msg=msg, confirm=True) |
|
91 else: |
|
92 login, pwd = unicode(source['db-user']), source['db-password'] |
|
93 print 'inserting default user and groups' |
|
94 needisfix = [] |
|
95 for group in BASEGROUPS: |
|
96 rset = session.execute('INSERT EGroup X: X name %(name)s', |
|
97 {'name': unicode(group)}) |
|
98 needisfix.append( (rset.rows[0][0], rset.description[0][0]) ) |
|
99 rset = session.execute('INSERT EUser X: X login %(login)s, X upassword %(pwd)s', |
|
100 {'login': login, 'pwd': pwd}) |
|
101 needisfix.append( (rset.rows[0][0], rset.description[0][0]) ) |
|
102 session.execute('SET U in_group G WHERE G name "managers"') |
|
103 session.commit() |
|
104 # reloging using the admin user |
|
105 config._cubes = None # avoid assertion error |
|
106 repo, cnx = in_memory_cnx(config, login, pwd) |
|
107 assert len(repo.sources) == 1, repo.sources |
|
108 handler = config.migration_handler(schema, interactive=False, |
|
109 cnx=cnx, repo=repo) |
|
110 initialize_schema(config, schema, handler) |
|
111 # admin user and groups have been added before schema entities, fix the 'is' |
|
112 # relation |
|
113 for eid, etype in needisfix: |
|
114 handler.session.unsafe_execute('SET X is E WHERE X eid %(x)s, E name %(name)s', |
|
115 {'x': eid, 'name': etype}, 'x') |
|
116 # insert versions |
|
117 handler.cmd_add_entity('EProperty', pkey=u'system.version.cubicweb', |
|
118 value=unicode(config.cubicweb_version())) |
|
119 for cube in config.cubes(): |
|
120 handler.cmd_add_entity('EProperty', |
|
121 pkey=u'system.version.%s' % cube.lower(), |
|
122 value=unicode(config.cube_version(cube))) |
|
123 # yoo ! |
|
124 cnx.commit() |
|
125 config.enabled_sources = None |
|
126 for uri, source_config in config.sources().items(): |
|
127 if uri in ('admin', 'system'): |
|
128 # not an actual source or init_creating already called |
|
129 continue |
|
130 source = repo.get_source(uri, source_config) |
|
131 source.init_creating() |
|
132 cnx.commit() |
|
133 cnx.close() |
|
134 session.close() |
|
135 # restore initial configuration |
|
136 config.creating = False |
|
137 config.read_application_schema = read_application_schema |
|
138 config.bootstrap_schema = bootstrap_schema |
|
139 config.consider_user_state = True |
|
140 config.set_language = True |
|
141 print 'application %s initialized' % config.appid |
|
142 |
|
143 |
|
144 def initialize_schema(config, schema, mhandler, event='create'): |
|
145 from cubicweb.server.schemaserial import serialize_schema |
|
146 paths = [p for p in config.cubes_path() + [config.apphome] |
|
147 if exists(join(p, 'migration'))] |
|
148 # execute cubicweb's pre<event> script |
|
149 mhandler.exec_event_script('pre%s' % event) |
|
150 # execute cubes pre<event> script if any |
|
151 for path in reversed(paths): |
|
152 mhandler.exec_event_script('pre%s' % event, path) |
|
153 # enter application'schema into the database |
|
154 serialize_schema(mhandler.rqlcursor, schema) |
|
155 # execute cubicweb's post<event> script |
|
156 mhandler.exec_event_script('post%s' % event) |
|
157 # execute cubes'post<event> script if any |
|
158 for path in reversed(paths): |
|
159 mhandler.exec_event_script('post%s' % event, path) |
|
160 |
|
161 def set_debug(debugmode): |
|
162 global DEBUG |
|
163 DEBUG = debugmode |
|
164 |
|
165 def debugged(func): |
|
166 """decorator to activate debug mode""" |
|
167 def wrapped(*args, **kwargs): |
|
168 global DEBUG |
|
169 DEBUG = True |
|
170 try: |
|
171 return func(*args, **kwargs) |
|
172 finally: |
|
173 DEBUG = False |
|
174 return wrapped |
|
175 |
|
176 # sqlite'stored procedures have to be registered at connexion opening time |
|
177 SQL_CONNECT_HOOKS = {} |
|
178 |
|
179 # add to this set relations which should have their add security checking done |
|
180 # *BEFORE* adding the actual relation (done after by default) |
|
181 BEFORE_ADD_RELATIONS = set(('owned_by',)) |
|
182 |
|
183 # add to this set relations which should have their add security checking done |
|
184 # *at COMMIT TIME* (done after by default) |
|
185 ON_COMMIT_ADD_RELATIONS = set(()) |
|
186 |
|
187 # available sources registry |
|
188 SOURCE_TYPES = {'native': LazyObject('cubicweb.server.sources.native', 'NativeSQLSource'), |
|
189 # XXX private sources installed by an external cube |
|
190 'pyrorql': LazyObject('cubicweb.server.sources.pyrorql', 'PyroRQLSource'), |
|
191 'ldapuser': LazyObject('cubicweb.server.sources.ldapuser', 'LDAPUserSource'), |
|
192 } |