Guest User

Untitled

a guest
Feb 7th, 2018
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.42 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. """
  3. Run migrations on the servatrice database.
  4.  
  5. Reads migrations from `servatrice/migrations/` and runs them
  6. on the database in order.
  7.  
  8. Only runs migrations if they are nedded. This is determined using
  9. the cockatrice_schema_version table.
  10.  
  11. Stops running migrations if any fail for any reason.
  12. """
  13.  
  14. import os
  15.  
  16. from argparse import ArgumentParser
  17.  
  18. import pymysql
  19. import pymysql.cursors
  20.  
  21. SQL_CONTROLLER = None
  22.  
  23.  
  24. def run_sql_command(sql: str) -> str:
  25. """Run a SQL command."""
  26. SQL_CONTROLLER.execute(sql)
  27. result = SQL_CONTROLLER.fetchall()
  28. return result
  29.  
  30.  
  31. def get_all_migrations(args) -> list:
  32. """Get a list of all available migrations."""
  33. files = os.listdir(args.migration_directory)
  34. migrations = [f'{args.migration_directory}/{x}' for x in files if x.endswith('.sql')]
  35. migrations.sort()
  36. return migrations
  37.  
  38.  
  39. def get_schema_version() -> int:
  40. """Get the schema version of the servatrice database."""
  41. command = 'SELECT version FROM cockatrice_schema_version;'
  42. result = run_sql_command(command)
  43. result = result[0]['version']
  44. return int(result)
  45.  
  46.  
  47. def valid_migrations(migrations: list, schema_version: int) -> list:
  48. """Retrun a list of valid migrations."""
  49. valid = []
  50. for migration in migrations:
  51. parts = migration.split('_')
  52. if schema_version <= int(parts[1]):
  53. valid.append(migration)
  54. valid.sort()
  55. return valid
  56.  
  57.  
  58. def run_migration(migration: str) -> dict:
  59. """Load a migration from disk and run it."""
  60. with open(migration, 'r') as f:
  61. sql = f.read()
  62. # print(SQL_CONTROLLER.mogrify(sql))
  63. # exit()
  64. try:
  65. result = run_sql_command(sql)
  66. status = {
  67. 'success': True,
  68. 'result': result
  69. }
  70. except pymysql.err.MySQLError as exception:
  71. status = {
  72. 'success': False,
  73. 'error': exception
  74. }
  75. return status
  76.  
  77.  
  78. def main() -> None:
  79. """Run the migrations."""
  80. global SQL_CONTROLLER
  81. parser = ArgumentParser(
  82. description='Run migrations on a servatrice database.',
  83. epilog='Be sure to manually verify migrations _before_ running them!'
  84. )
  85.  
  86. mysql_group = parser.add_argument_group('MySql Server Args')
  87. mysql_group.add_argument('-u', '--user', required=True)
  88. mysql_group.add_argument('-p', '--password', '--pass', required=True)
  89. mysql_group.add_argument('-H', '--host', default='127.0.0.1')
  90. mysql_group.add_argument('-d', '--database', default='servatrice')
  91. mysql_group.add_argument('-P', '--port', type=int, default=3306)
  92.  
  93. script_group = parser.add_argument_group('Script Args')
  94. script_group.add_argument('-D', '--migration-directory', default='./migrations')
  95. script_group.add_argument('--safe-mode', type=bool, default=True)
  96.  
  97. args = parser.parse_args()
  98.  
  99. connection = pymysql.connect(
  100. host=args.host, user=args.user, password=args.password,
  101. db=args.database, charset='utf8mb4',
  102. cursorclass=pymysql.cursors.DictCursor)
  103. SQL_CONTROLLER = connection.cursor()
  104.  
  105. migrations = get_all_migrations(args)
  106. schema_version = get_schema_version()
  107.  
  108. migrations = valid_migrations(migrations, schema_version)
  109.  
  110. for migration in migrations:
  111. status = run_migration(migration)
  112. if not status['success']:
  113. exc = status['error']
  114. print(exc)
  115. break
  116. # TODO handle ctlaltca's concerns from #2969
  117.  
  118.  
  119. if __name__ == '__main__':
  120. main()
Add Comment
Please, Sign In to add comment