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

https://bitbucket.org/cistrome/cistrome-harvard/ · Python · 105 lines · 76 code · 7 blank · 22 comment · 16 complexity · c8ceec0b6170160ec56f84dcf5b4b008 MD5 · raw file

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