module Scrivito module Migrations class Migrator class << self def migrations_path Rails.root + Scrivito::Configuration.migration_path end def determine_migrations(paths) paths = Array(paths) files = Dir[*paths.map { |path| "#{path}/**/[0-9]*_*.rb" }] splitter = /([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ migrations = files.map do |filename| version, name, scope = filename.scan(splitter).first unless version raise ScrivitoError.new("Illegal name for migration file: #{filename}\n\t (only lower case letters, numbers, and '_' allowed)") end version = version name = name.camelize require(File.expand_path(filename)) name.constantize.new(name, version, filename, scope) end migrations.sort_by(&:version) end end attr_reader :migrations attr_reader :workspace_lock def initialize(migration_store=nil, workspace_lock=nil) @migrations = determine_migrations @migration_store = migration_store || MigrationStore.instance @workspace_lock = workspace_lock || WorkspaceLock.instance validate end def migrate workspace.as_current do runnable.each do |migration| migration.migrate @migration_store.add_version(migration.version) end end end def needs_migration? runnable.present? end def publish remove_workspace_with do CmsRestApi.put("workspaces/#{workspace.id}/publish", {}) end end def abort remove_workspace_with do CmsRestApi.delete("workspaces/#{workspace.id}") end end private def workspace workspace = migration_workspace if workspace if workspace_lock.exists? workspace_lock.validate(workspace) end else workspace = Workspace.create(title: 'Migration Working Copy', id: 'rtc') workspace_lock.write(workspace) end workspace end def migration_workspace Workspace.find('rtc') rescue ResourceNotFound end def remove_workspace_with(&block) workspace = migration_workspace if workspace workspace_lock.validate(workspace) yield workspace_lock.remove else raise ScrivitoError.new('Migration workspace does not exist') end end def determine_migrations self.class.determine_migrations(self.class.migrations_path) end def runnable migrations.reject do |migration| migrated_versions.include?(migration.version) end end def migrated_versions @migration_store.versions end def validate name, _ = migrations.group_by(&:name).find { |_, value| value.length > 1 } if name raise ScrivitoError.new("Multiple migrations have the name #{name}") end version, _ = migrations.group_by(&:version).find { |_, value| value.length > 1 } if version raise ScrivitoError.new("Multiple migrations have the version number #{version}") end end end end end