Ejemplo n.º 1
0
    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')
Ejemplo n.º 2
0
    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')
Ejemplo n.º 3
0
    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