diff -r 000000000000 -r b97547f5f1fa server/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/__init__.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,192 @@ +"""Server subcube of cubicweb : defines objects used only on the server +(repository) side + +This module contains functions to initialize a new repository. + +:organization: Logilab +:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +import sys +from os.path import join, exists + +from logilab.common.modutils import LazyObject + +# server debugging flag +DEBUG = False + +def init_repository(config, interactive=True, drop=False, vreg=None): + """initialise a repository database by creating tables add filling them + with the minimal set of entities (ie at least the schema, base groups and + a initial user) + """ + from glob import glob + from cubicweb.schema import BASEGROUPS + from cubicweb.dbapi import in_memory_cnx + from cubicweb.server.repository import Repository + from cubicweb.server.utils import manager_userpasswd + from cubicweb.server.sqlutils import sqlexec, sqlschema, sqldropschema + # configuration to avoid db schema loading and user'state checking + # on connection + read_application_schema = config.read_application_schema + bootstrap_schema = config.bootstrap_schema + config.read_application_schema = False + config.creating = True + config.bootstrap_schema = True + config.consider_user_state = False + config.set_language = False + # only enable the system source at initialization time + admin which is not + # an actual source but contains initial manager account information + config.enabled_sources = ('system', 'admin') + repo = Repository(config, vreg=vreg) + assert len(repo.sources) == 1, repo.sources + schema = repo.schema + sourcescfg = config.sources() + print 'creating necessary tables into the system source' + source = sourcescfg['system'] + driver = source['db-driver'] + sqlcnx = repo.system_source.get_connection() + sqlcursor = sqlcnx.cursor() + def execute(sql, args=None): + repo.system_source.doexec(sqlcursor, sql, args) + if drop: + dropsql = sqldropschema(schema, driver) + try: + sqlexec(dropsql, execute) + except Exception, ex: + print 'drop failed, skipped (%s)' % ex + sqlcnx.rollback() + # schema entities and relations tables + # can't skip entities table even if system source doesn't support them, + # they are used sometimes by generated sql. Keeping them empty is much + # simpler than fixing this... + if sqlcnx.logged_user != source['db-user']: + schemasql = sqlschema(schema, driver, user=source['db-user']) + else: + schemasql = sqlschema(schema, driver) + #skip_entities=[str(e) for e in schema.entities() + # if not repo.system_source.support_entity(str(e))]) + sqlexec(schemasql, execute) + # install additional driver specific sql files + for fpath in glob(join(config.schemas_lib_dir(), '*.sql.%s' % driver)): + print 'install', fpath + sqlexec(open(fpath).read(), execute, False, delimiter=';;') + for directory in config.cubes_path(): + for fpath in glob(join(directory, 'schema', '*.sql.%s' % driver)): + print 'install', fpath + sqlexec(open(fpath).read(), execute, False, delimiter=';;') + sqlcursor.close() + sqlcnx.commit() + sqlcnx.close() + session = repo.internal_session() + try: + login = unicode(sourcescfg['admin']['login']) + pwd = sourcescfg['admin']['password'] + except KeyError: + if interactive: + msg = 'enter login and password of the initial manager account' + login, pwd = manager_userpasswd(msg=msg, confirm=True) + else: + login, pwd = unicode(source['db-user']), source['db-password'] + print 'inserting default user and groups' + needisfix = [] + for group in BASEGROUPS: + rset = session.execute('INSERT EGroup X: X name %(name)s', + {'name': unicode(group)}) + needisfix.append( (rset.rows[0][0], rset.description[0][0]) ) + rset = session.execute('INSERT EUser X: X login %(login)s, X upassword %(pwd)s', + {'login': login, 'pwd': pwd}) + needisfix.append( (rset.rows[0][0], rset.description[0][0]) ) + session.execute('SET U in_group G WHERE G name "managers"') + session.commit() + # reloging using the admin user + config._cubes = None # avoid assertion error + repo, cnx = in_memory_cnx(config, login, pwd) + assert len(repo.sources) == 1, repo.sources + handler = config.migration_handler(schema, interactive=False, + cnx=cnx, repo=repo) + initialize_schema(config, schema, handler) + # admin user and groups have been added before schema entities, fix the 'is' + # relation + for eid, etype in needisfix: + handler.session.unsafe_execute('SET X is E WHERE X eid %(x)s, E name %(name)s', + {'x': eid, 'name': etype}, 'x') + # insert versions + handler.cmd_add_entity('EProperty', pkey=u'system.version.cubicweb', + value=unicode(config.cubicweb_version())) + for cube in config.cubes(): + handler.cmd_add_entity('EProperty', + pkey=u'system.version.%s' % cube.lower(), + value=unicode(config.cube_version(cube))) + # yoo ! + cnx.commit() + config.enabled_sources = None + for uri, source_config in config.sources().items(): + if uri in ('admin', 'system'): + # not an actual source or init_creating already called + continue + source = repo.get_source(uri, source_config) + source.init_creating() + cnx.commit() + cnx.close() + session.close() + # restore initial configuration + config.creating = False + config.read_application_schema = read_application_schema + config.bootstrap_schema = bootstrap_schema + config.consider_user_state = True + config.set_language = True + print 'application %s initialized' % config.appid + + +def initialize_schema(config, schema, mhandler, event='create'): + from cubicweb.server.schemaserial import serialize_schema + paths = [p for p in config.cubes_path() + [config.apphome] + if exists(join(p, 'migration'))] + # execute cubicweb's pre script + mhandler.exec_event_script('pre%s' % event) + # execute cubes pre script if any + for path in reversed(paths): + mhandler.exec_event_script('pre%s' % event, path) + # enter application'schema into the database + serialize_schema(mhandler.rqlcursor, schema) + # execute cubicweb's post script + mhandler.exec_event_script('post%s' % event) + # execute cubes'post script if any + for path in reversed(paths): + mhandler.exec_event_script('post%s' % event, path) + +def set_debug(debugmode): + global DEBUG + DEBUG = debugmode + +def debugged(func): + """decorator to activate debug mode""" + def wrapped(*args, **kwargs): + global DEBUG + DEBUG = True + try: + return func(*args, **kwargs) + finally: + DEBUG = False + return wrapped + +# sqlite'stored procedures have to be registered at connexion opening time +SQL_CONNECT_HOOKS = {} + +# add to this set relations which should have their add security checking done +# *BEFORE* adding the actual relation (done after by default) +BEFORE_ADD_RELATIONS = set(('owned_by',)) + +# add to this set relations which should have their add security checking done +# *at COMMIT TIME* (done after by default) +ON_COMMIT_ADD_RELATIONS = set(()) + +# available sources registry +SOURCE_TYPES = {'native': LazyObject('cubicweb.server.sources.native', 'NativeSQLSource'), + # XXX private sources installed by an external cube + 'pyrorql': LazyObject('cubicweb.server.sources.pyrorql', 'PyroRQLSource'), + 'ldapuser': LazyObject('cubicweb.server.sources.ldapuser', 'LDAPUserSource'), + }