def ensure_setup(): try: config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) wd.config_validate() except RuntimeError as e: raise SystemExit(e) except ValueError as e: raise SystemExit(e)
def ensure_init(): ensure_setup() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) try: ctx = create_migration_ctx(wd.get_migration_ctx_config()) head = ctx.head except: raise SystemExit("Error: mroll not initialized! Run init command first.")
def test_migr_ctx_head(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) ctx.create_revisions_tbl() self.assertIsNone(ctx.head) conn = pymonetdb.connect(self.db_name) sql = """insert into sys.mroll_revisions values ('{}', '{}', '{}')""".format( gen_rev_id(), "bla bla", datetime.now()) conn.execute(sql) conn.commit() self.assertIsNotNone(ctx.head)
def test_ctx_revisions(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) ctx.create_revisions_tbl() self.assertTrue(len(ctx.revisions) == 0) conn = pymonetdb.connect(self.db_name) sql = """insert into sys.mroll_revisions values ('{}', '{}', '{}'), ('{}', '{}', '{}');""".format( gen_rev_id(), "revision 1", datetime.now(), gen_rev_id(), "revision 2", datetime.now()) conn.execute(sql) conn.commit() self.assertTrue(len(ctx.revisions) == 2)
def revision(message): """ Creates new revision from a template. """ ensure_setup() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) ts = datetime.now().isoformat() id_ = gen_rev_id() description = message or '' wd.add_revision(Revision(id_, description, ts)) kebab = description.strip().replace(' ', '_') fn = os.path.join(wd.path, 'versions', '{}_{}.sql'.format(id_, kebab)) assert os.path.exists(fn) print('ok')
def rollback(step, rev_id): """ Downgrades to previous revision by default. """ ensure_init() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) if migr_ctx.head is None: raise SystemExit('Nothing to do!') # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is not None, wd.revisions)) count = 0 buff=[] for rev in reversed(working_set): if rev_id is None and count==step: break if rev_id is not None: if rev.id == rev_id: buff.append(rev) break buff.append(rev) count+=1 working_set: List[Revision] = [] + buff # insure idempotency for rev in working_set: if rev.downgrade_sql is None: msg=""" Error: No downgrade sql script @{}! """.format(rev.id) if rev.upgrade_sql is not None: msg=""" Error: No downgrade sql script @{}, while there is a upgrade sql: {} Scripts should be idempotent. """.format(rev.id, rev.upgrade_sql) raise SystemExit(msg) try: migr_ctx.remove_revisions(working_set) except RevisionOperationError as e: raise SystemExit(repr(e)) print('Done')
def pending_revisions(show_patch=False): """ Shows pending revisions not yet applied. """ config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is None, wd.revisions)) for r in working_set: if show_patch: print(r.serialize()) else: print(r)
def applied_revisions(show_patch=False): config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) if migr_ctx.head is None: print('No revisions have being applied yet!') return # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is not None, wd.revisions)) for rev in working_set: if show_patch: print(rev.serialize()) else: print(rev)
def all_revisions(show_patch=False): config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) for rev in wd.revisions: if show_patch: print(rev.serialize()) else: print(rev)
def test_ctx_add_revisions(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) ctx.create_revisions_tbl() self.assertTrue(len(ctx.revisions) == 0) revisions = [ Revision(gen_rev_id(), "adding table foo", datetime.now(), upgrade_sql="create table test.foo (a string);", downgrade_sql="drop table test.foo;"), Revision(gen_rev_id(), "adding table bar", datetime.now(), upgrade_sql="create table test.bar (a string);", downgrade_sql="drop table test.bar;") ] ctx.add_revisions(revisions) self.assertTrue(len(ctx.revisions) == 2)
def init(): """ Creates mroll_revisions tbl. Should be run once. """ ensure_setup() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx_config = wd.get_migration_ctx_config() migr_ctx = create_migration_ctx(migr_ctx_config) try: # if following succeeds then mroll revisons tbl exist. migr_ctx.head return print("Nothing to do! Mroll revisions table already exist.") except: pass try: migr_ctx.create_revisions_tbl() except Exception as e: raise SystemExit(e) print('{} table created'.format(migr_ctx_config.tbl_name)) print('Done')
def upgrade(step): """ Applies revisions in work dir not yet applied. """ ensure_init() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is None, wd.revisions)) ptr = step or len(working_set) # adjust working set working_set = working_set[:ptr] # ensure idempotency for rev in working_set: if rev.upgrade_sql is None: msg=""" Error: No upgrade sql script @{}! """.format(rev.id) if rev.downgrade_sql is not None: msg=""" Error: No upgrade sql script @{}, while there is a downgrade sql: {} Scripts should be idempotent. """.format(rev.id, rev.downgrade_sql) raise SystemExit(msg) # execute try: migr_ctx.add_revisions(working_set) except RevisionOperationError as e: raise SystemExit(repr(e)) print('Done')
def test_create_migr_ctx(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNotNone(ctx)
def set_config_db_name(self, db_name): wd = WorkDirectory(path=self.work_dir) wd._set_config('db', 'db_name', db_name)