server/__init__.py
changeset 0 b97547f5f1fa
child 480 71376fda9b36
--- /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<event> script
+    mhandler.exec_event_script('pre%s' % event)
+    # execute cubes pre<event> 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<event> script
+    mhandler.exec_event_script('post%s' % event)
+    # execute cubes'post<event> 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'),
+                }