#506 - Changes to DB Migration, support run on startup and external version numbering - suffix/subdirectory refactor

This commit is contained in:
Robin Bygrave
2016-01-05 21:21:16 +13:00
parent 2ccd8dabeb
commit 7bcf1da823
5 changed files with 230 additions and 58 deletions
@@ -18,13 +18,16 @@ public class DbMigrationConfig {
*/
protected DbPlatformName platform;
protected boolean useSubdirectories;
/**
* Set to true if the DB migration should be generated on server start.
*/
protected boolean generate;
/**
* Set to true to suppress the output of the rollback script.
*/
protected boolean suppressRollback;
/**
* The migration version name (typically FlywayDb compatible).
* <p>
@@ -50,9 +53,40 @@ public class DbMigrationConfig {
/**
* Resource path for the migration xml and sql.
* Typically you would change 'app' to be a better/more unique.
*/
protected String resourcePath = "dbmigration/app";
protected String migrationPath = "dbmigration";
/**
* Subdirectory the model xml files go into.
*/
protected String modelPath = "model";
/**
* Subdirectory the drop ddl scripts go into.
*/
protected String dropPath = "drop";
/**
* Subdirectory the rollback ddl scripts go into.
*/
protected String rollbackPath = "rollback";
/**
* Apply script suffix.
*/
protected String applySuffix = ".sql";
/**
* Default drop script suffix to ddl so that it isn't picked up by FlywayDb.
*/
protected String dropSuffix = ".drop.ddl";
/**
* Default rollback script suffix to ddl so that it isn't picked up by FlywayDb.
*/
protected String rollbackSuffix = ".rollback.ddl";
protected String modelSuffix = ".model.xml";
/**
* Return the DB platform to generate migration DDL for.
@@ -74,34 +108,132 @@ public class DbMigrationConfig {
/**
* Return the resource path for db migrations.
*/
public String getResourcePath() {
return resourcePath;
}
/**
* Return true if the 'rollback' and 'drop' scripts should be put into subdirectories.
*/
public boolean isUseSubdirectories() {
return useSubdirectories;
}
/**
* Set to true if the 'rollback' and 'drop' scripts should be put into subdirectories.
*/
public void setUseSubdirectories(boolean useSubdirectories) {
this.useSubdirectories = useSubdirectories;
public String getMigrationPath() {
return migrationPath;
}
/**
* Set the resource path for db migrations.
* <p>
* Typically this would be something like "dbmigration/myapp" where myapp gives it a
* unique resource path in the case there are multiple EbeanServer applications in the
* single classpath.
* The default of "dbmigration" is reasonable in most cases. You may look to set this
* to be something like "dbmigration/myapp" where myapp gives it a unique resource path
* in the case there are multiple EbeanServer applications in the single classpath.
* </p>
*/
public void setResourcePath(String resourcePath) {
this.resourcePath = resourcePath;
public void setMigrationPath(String migrationPath) {
this.migrationPath = migrationPath;
}
/**
* Return the relative path for the model files (defaults to model).
*/
public String getModelPath() {
return modelPath;
}
/**
* Set the relative path for the model files.
*/
public void setModelPath(String modelPath) {
this.modelPath = modelPath;
}
/**
* Return the relative path for the drop ddl scripts (defaults to drop).
*/
public String getDropPath() {
return dropPath;
}
/**
* Set the relative path for the drop ddl scripts (defaults to drop).
*/
public void setDropPath(String dropPath) {
this.dropPath = dropPath;
}
/**
* Return the relative path for the rollback ddl scripts (defaults to rollback).
*/
public String getRollbackPath() {
return rollbackPath;
}
/**
* Set the relative path for the rollback ddl scripts (defaults to rollback).
*/
public void setRollbackPath(String rollbackPath) {
this.rollbackPath = rollbackPath;
}
/**
* Return the model suffix (defaults to model.xml)
*/
public String getModelSuffix() {
return modelSuffix;
}
/**
* Set the model suffix.
*/
public void setModelSuffix(String modelSuffix) {
this.modelSuffix = modelSuffix;
}
/**
* Return true if the rollback script should not be output.
*/
public boolean isSuppressRollback() {
return suppressRollback;
}
/**
* Set to true to suppress the output of the rollback script.
*/
public void setSuppressRollback(boolean suppressRollback) {
this.suppressRollback = suppressRollback;
}
/**
* Return the apply script suffix (defaults to sql).
*/
public String getApplySuffix() {
return applySuffix;
}
/**
* Set the apply script suffix (defaults to sql).
*/
public void setApplySuffix(String applySuffix) {
this.applySuffix = applySuffix;
}
/**
* Return the drop script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public String getDropSuffix() {
return dropSuffix;
}
/**
* Set the drop script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public void setDropSuffix(String dropSuffix) {
this.dropSuffix = dropSuffix;
}
/**
* Return the rollback script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public String getRollbackSuffix() {
return rollbackSuffix;
}
/**
* Set the rollback script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
*/
public void setRollbackSuffix(String rollbackSuffix) {
this.rollbackSuffix = rollbackSuffix;
}
/**
@@ -122,16 +254,40 @@ public class DbMigrationConfig {
this.name = name;
}
/**
* Set the model, rollback and drop paths to be empty such that all the migration files are generated
* into a single directory.
*/
public void singleDirectory() {
this.dropPath = "";
this.rollbackPath = "";
this.modelPath = "";
}
/**
* Load the settings from the PropertiesWrapper.
*/
public void loadSettings(PropertiesWrapper properties) {
resourcePath = properties.get("migration.resourcePath", resourcePath);
migrationPath = properties.get("migration.migrationPath", migrationPath);
if (properties.getBoolean("migration.singleDirectory", false)) {
singleDirectory();
} else {
modelPath = properties.get("migration.modelPath", modelPath);
rollbackPath = properties.get("migration.rollbackPath", rollbackPath);
dropPath = properties.get("migration.dropPath", dropPath);
}
applySuffix = properties.get("migration.applySuffix", applySuffix);
dropSuffix = properties.get("migration.dropSuffix", dropSuffix);
rollbackSuffix = properties.get("migration.rollbackSuffix", rollbackSuffix);
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
platform = properties.getEnum(DbPlatformName.class, "migration.platform", platform);
suppressRollback = properties.getBoolean("migration.suppressRollback", suppressRollback);
generate = properties.getBoolean("migration.generate", generate);
version = properties.get("migration.version", version);
name = properties.get("migration.name", name);
useSubdirectories = properties.getBoolean("migration.useSubdirectories", useSubdirectories);
}
/**
@@ -204,9 +204,10 @@ public class DbMigration {
try {
File migrationDirectory = getMigrationDirectory();
File migrationDir = getMigrationDirectory();
File modelDir = getModelDirectory(migrationDir);
MigrationModel migrationModel = new MigrationModel(migrationDirectory);
MigrationModel migrationModel = new MigrationModel(modelDir, migrationConfig.getModelSuffix());
ModelContainer migrated = migrationModel.read();
CurrentModel currentModel = new CurrentModel(server, constraintNaming);
@@ -226,7 +227,7 @@ public class DbMigration {
String fullVersion = getFullVersion(migrationModel);
logger.info("generating migration:{}", fullVersion);
if (!writeMigrationXml(dbMigration, migrationDirectory, fullVersion)) {
if (!writeMigrationXml(dbMigration, modelDir, fullVersion)) {
logger.warn("migration already exists, not generating DDL");
} else {
@@ -235,9 +236,9 @@ public class DbMigration {
// history ddl generation (triggers, history tables etc)
DdlWrite write = new DdlWrite(new MConfiguration(), currentModel.read());
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
writer.processMigration(dbMigration, write, migrationDirectory, fullVersion);
writer.processMigration(dbMigration, write, migrationDir , fullVersion);
}
writeExtraPlatformDdl(fullVersion, currentModel, dbMigration, migrationDirectory);
writeExtraPlatformDdl(fullVersion, currentModel, dbMigration, migrationDir);
}
} finally {
@@ -290,7 +291,7 @@ public class DbMigration {
}
private PlatformDdlWriter createDdlWriter(DatabasePlatform platform, String prefix) {
return new PlatformDdlWriter(platform, serverConfig, prefix, migrationConfig.isUseSubdirectories());
return new PlatformDdlWriter(platform, serverConfig, prefix, migrationConfig);
}
/**
@@ -298,7 +299,8 @@ public class DbMigration {
*/
protected boolean writeMigrationXml(Migration dbMigration, File resourcePath, String fullVersion) {
File file = new File(resourcePath, fullVersion+".xml");
String modelFile = fullVersion + migrationConfig.getModelSuffix();
File file = new File(resourcePath, modelFile);
if (file.exists()) {
return false;
}
@@ -329,10 +331,9 @@ public class DbMigration {
// path to src/main/resources in typical maven project
File resourceRootDir = new File(pathToResources);
String resourcePath = migrationConfig.getMigrationPath();
String resourcePath = migrationConfig.getResourcePath();
// expect to be a path to something like - src/main/resources/dbmigration/myapp
// expect to be a path to something like - src/main/resources/dbmigration/model
File path = new File(resourceRootDir, resourcePath);
if (!path.exists()) {
if (!path.mkdirs()) {
@@ -342,6 +343,21 @@ public class DbMigration {
return path;
}
/**
* Return the model directory (relative to the migration directory).
*/
protected File getModelDirectory(File migrationDirectory) {
String modelPath = migrationConfig.getModelPath();
if (modelPath == null || modelPath.isEmpty()) {
return migrationDirectory;
}
File modelDir = new File(migrationDirectory, migrationConfig.getModelPath());
if (!modelDir.exists() && !modelDir.mkdirs()) {
logger.debug("Unable to ensure migration model directory exists at {}", modelDir.getAbsolutePath());
}
return modelDir;
}
/**
* Return the DatabasePlatform given the platform key.
*/
@@ -18,12 +18,15 @@ public class MigrationModel {
private final ModelContainer model = new ModelContainer();
private final File migrationDirectory;
private final File modelDirectory;
private final String modelSuffix;
private MigrationVersion lastVersion;
public MigrationModel(File migrationDirectory) {
this.migrationDirectory = migrationDirectory;
public MigrationModel(File modelDirectory, String modelSuffix) {
this.modelDirectory = modelDirectory;
this.modelSuffix = modelSuffix;
}
/**
@@ -39,10 +42,10 @@ public class MigrationModel {
private void readMigrations() {
// find all the migration xml files
File[] xmlFiles = migrationDirectory.listFiles(new FileFilter() {
File[] xmlFiles = modelDirectory.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().toLowerCase().endsWith(".xml");
return pathname.getName().toLowerCase().endsWith(modelSuffix);
}
});
@@ -1,5 +1,6 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.config.DbMigrationConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
@@ -24,13 +25,13 @@ public class PlatformDdlWriter {
private final String platformPrefix;
private final boolean useSubdirectories;
private final DbMigrationConfig config;
public PlatformDdlWriter(DatabasePlatform platform, ServerConfig serverConfig, String platformPrefix, boolean useSubdirectories) {
public PlatformDdlWriter(DatabasePlatform platform, ServerConfig serverConfig, String platformPrefix, DbMigrationConfig config) {
this.platform = platform;
this.serverConfig = serverConfig;
this.platformPrefix = platformPrefix;
this.useSubdirectories = useSubdirectories;
this.config = config;
}
/**
@@ -57,7 +58,7 @@ public class PlatformDdlWriter {
protected void writePlatformDdl(DdlWrite write, File resourcePath, String fullVersion) throws IOException {
if (!write.isApplyEmpty()) {
FileWriter applyWriter = createWriter(resourcePath, fullVersion, "");
FileWriter applyWriter = createWriter(resourcePath, fullVersion, "", config.getApplySuffix());
try {
writeApplyDdl(applyWriter, write);
applyWriter.flush();
@@ -65,8 +66,8 @@ public class PlatformDdlWriter {
applyWriter.close();
}
if (!write.isApplyRollbackEmpty()) {
FileWriter applyRollbackWriter = createWriter(resourcePath, fullVersion, "rollback");
if (!config.isSuppressRollback() && !write.isApplyRollbackEmpty()) {
FileWriter applyRollbackWriter = createWriter(resourcePath, fullVersion, config.getRollbackPath(), config.getRollbackSuffix());
try {
writeApplyRollbackDdl(applyRollbackWriter, write);
applyRollbackWriter.flush();
@@ -77,7 +78,7 @@ public class PlatformDdlWriter {
}
if (!write.isDropEmpty()) {
FileWriter dropWriter = createWriter(resourcePath, fullVersion, "drop");
FileWriter dropWriter = createWriter(resourcePath, fullVersion, config.getDropPath(), config.getDropSuffix());
try {
writeDropDdl(dropWriter, write);
dropWriter.flush();
@@ -87,25 +88,21 @@ public class PlatformDdlWriter {
}
}
protected FileWriter createWriter(File path, String fullVersion, String suffix) throws IOException {
protected FileWriter createWriter(File path, String fullVersion, String subPath, String suffix) throws IOException {
String fileName = fullVersion;
if (!platformPrefix.isEmpty()) {
fileName += "-"+platformPrefix;
}
if (!suffix.isEmpty()) {
fileName += "-"+suffix;
path = subPath(path, suffix);
if (subPath != null && !subPath.isEmpty()) {
path = subPath(path, subPath);
}
fileName += ".sql";
fileName += suffix;
File applyFile = new File(path, fileName);
return new FileWriter(applyFile);
}
protected File subPath(File path, String suffix) {
if (!useSubdirectories) {
return path;
}
File subPath = new File(path, suffix);
if (!subPath.exists()) {
subPath.mkdirs();