def execute(self, args, options): filters = {} if options.filter: if not os.path.exists(options.filter): self.parser().error('filter: unable to open for reading') filters = create_filter(options.filter, options.include_tags, options.exclude_tags) input, output = args # load the source state saved_state = None for provider in PROVIDERS: if provider.can_load(input): saved_state = provider.load(input, filters) break else: self.parser().error('source: unable to open for reading') # (re)name it if applicable if options.name: saved_state.name = options.name elif saved_state.setdefault('name') is None: saved_state.name = get_uuid4() # save it to target state for provider in PROVIDERS: if provider.can_save(output): provider.save(saved_state, output, options.comment) break else: self.parser().error('target: unable to open for writing')
def run(self, options, base_dir): # setup directory configuration self.config_dir = os.path.join(base_dir, 'config') self.migration_dir = os.path.join(base_dir, 'migration') self.filter_config = os.path.join(self.config_dir, 'schema.ini') self.migration_conf = os.path.join(self.migration_dir, 'migration.ini') self.changelog = os.path.join(base_dir, 'changes.txt') self.change_report = os.path.join(base_dir, 'change_report.html') self.change_commit = os.path.join(base_dir, 'change_report.txt') self.current_state = os.path.join(base_dir, 'current.state') self.latest_state = self.tempfile(ext='.state') self.execute_cmd('getting current version', ['dvs', 'name', self.current_state]) self.current_version = self.output self.next_version = get_uuid4() self.execute_ddl('getting state version from database', GETVERSION_SQL) match = re.match(r'SCHEMA_VERSION\s+\-+\s+([\w\-]+)\s*', self.output) if not match: self.message('cannot find schema version') print self.output self.quit(SQLERR) self.db_version = match.group(1) if self.db_version != self.current_version: new_opt = optparse.Values() new_opt.no_comment = False new_opt.wrap = False new_opt.include_tags = options.include_tags new_opt.exclude_tags = options.exclude_tags self.migrate = MigrateDb() self.migrate.connectString = self.connectString self.migrate.target_version = self.current_version self.migrate.source_version = self.db_version self.migrate.start_version = self.db_version self.migrate.setup_migrations(self.migration_dir) if self.migrate.migration_path: self.message('pushing changes to the database (unsaved changes may be lost)') self.message('', None) return self.migrate.run(new_opt, self.current_state, self.filter_config, self.migration_dir) self.execute_cmd('extracting latest database state', ['dvs', 'copy', '-f', self.filter_config, '-n', self.next_version, '-i', options.include_tags, '-x', options.exclude_tags, 'oracle:'+self.connectString, self.latest_state]) differ = DiffDb() status = differ.run(self.current_state, self.latest_state) if status == 0: self.message('no changes detected') return 0 elif status == 1: self.message('changes detected, skipping migration check') self.generate_diff(self.current_state, self.latest_state) # mark that this requires no migration migration_file = open(self.migration_conf, 'a') migration_file.write('%s = %s\n' % (self.current_version, self.next_version)) migration_file.close() elif status == 2: self.message('changes detected, performing migration check') if not self.check_migration(options): self.message('', None) self.message('migration check failed, migrations may be incomplete or invalid.') self.generate_diff(self.latest_state, self.migrate.migration_check) return 1 self.message('', None) self.message('migration check succeeded') # update SQL files with the correct version for migration in glob.glob(self.migration_dir+'/*.sql'): data = self.read_file(migration) match = MIGRATION_REGEX.match(data) if not match: continue source, target, description = match.groups() if target == 'next-version': self.write_file(migration, data.replace('next-version', self.next_version)) self.generate_diff(self.current_state, self.latest_state) cleaner = CleanDb() cleaner.connectString = self.tempConnectString cleaner.run() self.execute_sql('synchronizing version numbers', UPDATESCHEMA_SQL % (self.next_version, '** migrations tested **')) self.message('updating the change log') migration_changes = [] if hasattr(self, 'migrate') and self.migrate and self.migrate.migration_path: for i in range(len(self.migrate.migration_path)-1): s, t = self.migrate.migration_path[i], self.migrate.migration_path[i+1] migration_changes.append('- ' + self.migrate.migrations[s][t][0]) current_date = datetime.datetime.now().strftime('[%Y-%m-%d %H:%M] ') text = current_date + self.next_version + '\n%s\n\n' % ('=' * 55) if migration_changes: text += 'Migrations:\n\n' + '\n'.join(migration_changes) + '\n\n' text += 'Schema Changes:\n\n' + differ.output + '\n\n\n\n' previous_changelog = self.read_file(self.changelog) self.write_file(self.changelog, text + previous_changelog) self.write_file(self.change_commit, "build $ver$: %s => %s\n\n%s" % \ (self.current_version, self.next_version, differ.output)) self.message('updating the current state with latest version') os.remove(self.current_state) os.rename(self.latest_state, self.current_state) self.rewrite_schema() return 0