PageRenderTime 49ms CodeModel.GetById 31ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/galaxy/webapps/community/model/migrate/check.py

https://bitbucket.org/cistrome/cistrome-harvard/
Python | 105 lines | 86 code | 6 blank | 13 comment | 5 complexity | c8ceec0b6170160ec56f84dcf5b4b008 MD5 | raw file
  1import sys, os.path, logging
  2
  3from galaxy import eggs
  4
  5import pkg_resources
  6pkg_resources.require( "sqlalchemy-migrate" )
  7
  8from migrate.versioning import repository, schema
  9from sqlalchemy import *
 10from sqlalchemy.exc import NoSuchTableError
 11
 12log = logging.getLogger( __name__ )
 13
 14# path relative to galaxy
 15migrate_repository_directory = os.path.dirname( __file__ ).replace( os.getcwd() + os.path.sep, '', 1 )
 16migrate_repository = repository.Repository( migrate_repository_directory )
 17dialect_to_egg = { 
 18    "sqlite" : "pysqlite>=2",
 19    "postgres" : "psycopg2",
 20    "mysql" : "MySQL_python"
 21}
 22
 23def create_or_verify_database( url, engine_options={} ):
 24    """
 25    Check that the database is use-able, possibly creating it if empty (this is
 26    the only time we automatically create tables, otherwise we force the
 27    user to do it using the management script so they can create backups).
 28    
 29    1) Empty database --> initialize with latest version and return
 30    2) Database older than migration support --> fail and require manual update
 31    3) Database at state where migrate support introduced --> add version control information but make no changes (might still require manual update)
 32    4) Database versioned but out of date --> fail with informative message, user must run "sh manage_db.sh upgrade"
 33    
 34    """
 35    dialect = ( url.split( ':', 1 ) )[0]
 36    try:
 37        egg = dialect_to_egg[dialect]
 38        try:
 39            pkg_resources.require( egg )
 40            log.debug( "%s egg successfully loaded for %s dialect" % ( egg, dialect ) )
 41        except:
 42            # If the module is in the path elsewhere (i.e. non-egg), it'll still load.
 43            log.warning( "%s egg not found, but an attempt will be made to use %s anyway" % ( egg, dialect ) )
 44    except KeyError:
 45        # Let this go, it could possibly work with db's we don't support
 46        log.error( "database_connection contains an unknown SQLAlchemy database dialect: %s" % dialect )
 47    # Create engine and metadata
 48    engine = create_engine( url, **engine_options )
 49    meta = MetaData( bind=engine )
 50    # Try to load dataset table
 51    try:
 52        galaxy_user_table = Table( "galaxy_user", meta, autoload=True )
 53    except NoSuchTableError:
 54        # No 'galaxy_user' table means a completely uninitialized database, which
 55        # is fine, init the database in a versioned state
 56        log.info( "No database, initializing" )
 57        # Database might or might not be versioned
 58        try:
 59            # Declare the database to be under a repository's version control
 60            db_schema = schema.ControlledSchema.create( engine, migrate_repository )
 61        except:
 62            # The database is already under version control
 63            db_schema = schema.ControlledSchema( engine, migrate_repository )
 64        # Apply all scripts to get to current version
 65        migrate_to_current_version( engine, db_schema )
 66        return
 67    try:
 68        version_table = Table( "migrate_version", meta, autoload=True )
 69    except NoSuchTableError:
 70        # The database exists but is not yet under migrate version control, so init with version 1
 71        log.info( "Adding version control to existing database" )
 72        try:
 73            metadata_file_table = Table( "metadata_file", meta, autoload=True )
 74            schema.ControlledSchema.create( engine, migrate_repository, version=2 )
 75        except NoSuchTableError:
 76            schema.ControlledSchema.create( engine, migrate_repository, version=1 )
 77    # Verify that the code and the DB are in sync
 78    db_schema = schema.ControlledSchema( engine, migrate_repository )
 79    if migrate_repository.versions.latest != db_schema.version:
 80        raise Exception( "Your database has version '%d' but this code expects version '%d'.  Please backup your database and then migrate the schema by running 'sh manage_db.sh upgrade'."
 81                            % ( db_schema.version, migrate_repository.versions.latest ) )
 82    else:
 83        log.info( "At database version %d" % db_schema.version )
 84        
 85def migrate_to_current_version( engine, schema ):
 86    # Changes to get to current version
 87    changeset = schema.changeset( None )
 88    for ver, change in changeset:
 89        nextver = ver + changeset.step
 90        log.info( 'Migrating %s -> %s... ' % ( ver, nextver ) )
 91        old_stdout = sys.stdout
 92        class FakeStdout( object ):
 93            def __init__( self ):
 94                self.buffer = []
 95            def write( self, s ):
 96                self.buffer.append( s )
 97            def flush( self ):
 98                pass
 99        sys.stdout = FakeStdout()
100        try:
101            schema.runchange( ver, change, changeset.step )
102        finally:
103            for message in "".join( sys.stdout.buffer ).split( "\n" ):
104                log.info( message )
105            sys.stdout = old_stdout