Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] NEW: DefaultDbMigration is configurable from properties #3152

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.ebeaninternal.dbmigration;

import java.io.IOException;

import io.ebean.plugin.Plugin;
import io.ebean.plugin.SpiServer;

/**
* Plugin to generate db-migration scripts automatically.
* @author Roland Praml, FOCONIS AG
*/
public class DbMigrationPlugin implements Plugin {

private DefaultDbMigration dbMigration;

private static String lastMigration;
private static String lastInit;

@Override
public void configure(SpiServer server) {
dbMigration = new DefaultDbMigration();
dbMigration.setServer(server);
}

@Override
public void online(boolean online) {
try {
lastInit = null;
lastMigration = null;
if (dbMigration.generate) {
String tmp = lastMigration = dbMigration.generateMigration();
if (tmp == null) {
return;
}
}
if (dbMigration.generateInit) {
lastInit = dbMigration.generateInitMigration();
}
} catch (IOException e) {
throw new RuntimeException("Error while generating migration", e);
}
}

@Override
public void shutdown() {
dbMigration = null;
}

public static String getLastInit() {
return lastInit;
}

public static String getLastMigration() {
return lastMigration;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.ebeaninternal.dbmigration;

import io.avaje.applog.AppLog;
import io.avaje.classpath.scanner.core.Location;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.DatabaseBuilder;
Expand All @@ -10,6 +11,7 @@
import io.ebean.config.dbplatform.DatabasePlatformProvider;
import io.ebean.dbmigration.DbMigration;
import io.ebean.util.IOUtils;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
Expand All @@ -24,10 +26,7 @@
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.*;

import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
import static java.lang.System.Logger.Level.*;
Expand Down Expand Up @@ -59,8 +58,8 @@ public class DefaultDbMigration implements DbMigration {
private static final String initialVersion = "1.0";
private static final String GENERATED_COMMENT = "THIS IS A GENERATED FILE - DO NOT MODIFY";

private final List<DatabasePlatformProvider> platformProviders = new ArrayList<>();
protected final boolean online;
private List<DatabasePlatformProvider> platformProviders = new ArrayList<>();
protected boolean online;
private boolean logToSystemOut = true;
protected SpiEbeanServer server;
protected String pathToResources = "src/main/resources";
Expand All @@ -75,8 +74,10 @@ public class DefaultDbMigration implements DbMigration {
protected List<Pair> platforms = new ArrayList<>();
protected DatabaseBuilder.Settings databaseBuilder;
protected DbConstraintNaming constraintNaming;
@Deprecated
protected Boolean strictMode;
protected Boolean includeGeneratedFileComment;
protected boolean includeGeneratedFileComment;
@Deprecated
protected String header;
protected String applyPrefix = "";
protected String version;
Expand All @@ -86,6 +87,9 @@ public class DefaultDbMigration implements DbMigration {
private int lockTimeoutSeconds;
protected boolean includeBuiltInPartitioning = true;
protected boolean includeIndex;
protected boolean generate = false;
protected boolean generateInit = false;
private boolean keepLastInit = true;

/**
* Create for offline migration generation.
Expand Down Expand Up @@ -122,12 +126,66 @@ public void setServerConfig(DatabaseBuilder builder) {
if (constraintNaming == null) {
this.constraintNaming = databaseBuilder.getConstraintNaming();
}
if (databasePlatform == null) {
this.databasePlatform = databaseBuilder.getDatabasePlatform();
}
Properties properties = config.getProperties();
if (properties != null) {
PropertiesWrapper props = new PropertiesWrapper("ebean", config.getName(), properties, null);
PropertiesWrapper props = new PropertiesWrapper("ebean", config.getName(), properties, config.getClassLoadConfig());
migrationPath = props.get("migration.migrationPath", migrationPath);
migrationInitPath = props.get("migration.migrationInitPath", migrationInitPath);
pathToResources = props.get("migration.pathToResources", pathToResources);
addForeignKeySkipCheck = props.getBoolean("migration.addForeignKeySkipCheck", addForeignKeySkipCheck);
applyPrefix = props.get("migration.applyPrefix", applyPrefix);
databasePlatform = props.createInstance(DatabasePlatform.class, "migration.databasePlatform", databasePlatform);
generatePendingDrop = props.get("migration.generatePendingDrop", generatePendingDrop);
includeBuiltInPartitioning = props.getBoolean("migration.includeBuiltInPartitioning", includeBuiltInPartitioning);
includeGeneratedFileComment = props.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
includeIndex = props.getBoolean("migration.includeIndex", includeIndex);
lockTimeoutSeconds = props.getInt("migration.lockTimeoutSeconds", lockTimeoutSeconds);
logToSystemOut = props.getBoolean("migration.logToSystemOut", logToSystemOut);
modelPath = props.get("migration.modelPath", modelPath);
modelSuffix = props.get("migration.modelSuffix", modelSuffix);
name = props.get("migration.name", name);
online = props.getBoolean("migration.online", online);
vanillaPlatform = props.getBoolean("migration.vanillaPlatform", vanillaPlatform);
version = props.get("migration.version", version);
generate = props.getBoolean("migration.generate", generate);
generateInit = props.getBoolean("migration.generateInit", generateInit);
// header & strictMode must be configured at DatabaseConfig level
parsePlatforms(props, config);
}
}

protected void parsePlatforms(PropertiesWrapper props, DatabaseBuilder.Settings config) {
String platforms = props.get("migration.platforms");
if (platforms == null || platforms.isEmpty()) {
return;
}
String[] tmp = StringHelper.splitNames(platforms);
for (String plat : tmp) {
DatabasePlatform dbPlatform;
String platformName = plat;
String platformPrefix = null;
int pos = plat.indexOf('=');
if (pos != -1) {
platformName = plat.substring(0, pos);
platformPrefix = plat.substring(pos + 1);
}

if (platformName.indexOf('.') == -1) {
// parse platform as enum value
Platform platform = Enum.valueOf(Platform.class, platformName.toUpperCase());
dbPlatform = platform(platform);
} else {
// parse platform as class
dbPlatform = (DatabasePlatform) config.getClassLoadConfig().newInstance(platformName);
}
if (platformPrefix == null) {
platformPrefix = dbPlatform.platform().name().toLowerCase();
}

addDatabasePlatform(dbPlatform, platformPrefix);
}
}

Expand Down Expand Up @@ -318,7 +376,18 @@ private String generateMigrationFor(boolean initMigration) throws IOException {
}

String pendingVersion = generatePendingDrop();
if (pendingVersion != null) {
if ("auto".equals(pendingVersion)) {
StringJoiner sj = new StringJoiner(",");
String diff = generateDiff(request);
if (diff != null) {
sj.add(diff);
request = createRequest(initMigration);
}
for (String pendingDrop : request.getPendingDrops()) {
sj.add(generatePendingDrop(request, pendingDrop));
}
return sj.length() == 0 ? null : sj.toString();
} else if (pendingVersion != null) {
return generatePendingDrop(request, pendingVersion);
} else {
return generateDiff(request);
Expand Down Expand Up @@ -553,7 +622,7 @@ private String generateMigration(Request request, Migration dbMigration, String
return null;
} else {
if (!platforms.isEmpty()) {
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir, request.initMigration && keepLastInit);

} else if (databasePlatform != null) {
// writer needs the current model to provide table/column details for
Expand Down Expand Up @@ -633,12 +702,17 @@ private String toUnderScore(String name) {
/**
* Write any extra platform ddl.
*/
private void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel, Migration dbMigration, File writePath) throws IOException {
private void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel, Migration dbMigration, File writePath, boolean clear) throws IOException {
DdlOptions options = new DdlOptions(addForeignKeySkipCheck);
for (Pair pair : platforms) {
DdlWrite writer = new DdlWrite(new MConfiguration(), currentModel.read(), options);
PlatformDdlWriter platformWriter = createDdlWriter(pair.platform);
File subPath = platformWriter.subPath(writePath, pair.prefix);
if (clear) {
for (File existing : subPath.listFiles()) {
existing.delete();
}
}
platformWriter.processMigration(dbMigration, writer, subPath, fullVersion);
}
}
Expand All @@ -656,7 +730,7 @@ private boolean writeMigrationXml(Migration dbMigration, File resourcePath, Stri
if (file.exists()) {
return false;
}
String comment = Boolean.TRUE.equals(includeGeneratedFileComment) ? GENERATED_COMMENT : null;
String comment = includeGeneratedFileComment ? GENERATED_COMMENT : null;
MigrationXmlWriter xmlWriter = new MigrationXmlWriter(comment);
xmlWriter.write(dbMigration, file);
return true;
Expand All @@ -674,11 +748,14 @@ private void setDefaults() {
databasePlatform = server.databasePlatform();
}
if (databaseBuilder != null) {
// FIXME: StrictMode and header may be defined HERE and in DatabaseConfig.
// We shoild change either DefaultDbMigration or databaseConfig, so that it is only
// defined on one place
if (strictMode != null) {
databaseBuilder.setDdlStrictMode(strictMode);
databaseBuilder.ddlStrictMode(strictMode);
}
if (header != null) {
databaseBuilder.setDdlHeader(header);
databaseBuilder.ddlHeader(header);
}
}
}
Expand Down Expand Up @@ -748,15 +825,20 @@ public File migrationDirectory() {
* Return the file path to write the xml and sql to.
*/
File migrationDirectory(boolean initMigration) {
// path to src/main/resources in typical maven project
File resourceRootDir = new File(pathToResources);
if (!resourceRootDir.exists()) {
String msg = String.format("Error - path to resources %s does not exist. Absolute path is %s", pathToResources, resourceRootDir.getAbsolutePath());
throw new UnknownResourcePathException(msg);
}
String resourcePath = migrationPath(initMigration);
Location resourcePath = migrationPath(initMigration);
// expect to be a path to something like - src/main/resources/dbmigration
File path = new File(resourceRootDir, resourcePath);
File path;
if (resourcePath.isClassPath()) {
// path to src/main/resources in typical maven project
File resourceRootDir = new File(pathToResources);
if (!resourceRootDir.exists()) {
String msg = String.format("Error - path to resources %s does not exist. Absolute path is %s", pathToResources, resourceRootDir.getAbsolutePath());
throw new UnknownResourcePathException(msg);
}
path = new File(resourceRootDir, resourcePath.path());
} else {
path = new File(resourcePath.path());
}
if (!path.exists()) {
if (!path.mkdirs()) {
logInfo("Warning - Unable to ensure migration directory exists at %s", path.getAbsolutePath());
Expand All @@ -765,8 +847,9 @@ File migrationDirectory(boolean initMigration) {
return path;
}

private String migrationPath(boolean initMigration) {
return initMigration ? migrationInitPath : migrationPath;
private Location migrationPath(boolean initMigration) {
// remove classpath: or filesystem: prefix
return new Location(initMigration ? migrationInitPath : migrationPath);
}

/**
Expand Down
1 change: 1 addition & 0 deletions ebean-ddl-generator/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module io.ebean.ddl.generator {

uses io.ebean.plugin.Plugin;
exports io.ebean.dbmigration;

provides io.ebean.dbmigration.DbMigration with io.ebeaninternal.dbmigration.DefaultDbMigration;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.ebeaninternal.dbmigration.DbMigrationPlugin
24 changes: 0 additions & 24 deletions ebean-ddl-generator/src/test/resources/application-test.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,3 @@ datasource.h2.url=jdbc:h2:mem:h2AutoTune
datasource.pg.username=sa
datasource.pg.password=
datasource.pg.url=jdbc:h2:mem:h2AutoTune

# parameters for migration test
datasource.migrationtest.username=SA
datasource.migrationtest.password=SA
datasource.migrationtest.url=jdbc:h2:mem:migration
ebean.migrationtest.applyPrefix=V
ebean.migrationtest.ddl.generate=false
ebean.migrationtest.ddl.run=false
ebean.migrationtest.ddl.header=-- Migrationscripts for ebean unittest
ebean.migrationtest.migration.appName=migrationtest
ebean.migrationtest.migration.migrationPath=dbmigration/migrationtest
ebean.migrationtest.migration.strict=true

# parameters for migration test
datasource.migrationtest-history.username=SA
datasource.migrationtest-history.password=SA
datasource.migrationtest-history.url=jdbc:h2:mem:migration
ebean.migrationtest-history.applyPrefix=V
ebean.migrationtest-history.ddl.generate=false
ebean.migrationtest-history.ddl.run=false
ebean.migrationtest-history.ddl.header=-- Migrationscripts for ebean unittest DbMigrationDropHistoryTest
ebean.migrationtest-history.migration.appName=migrationtest-history
ebean.migrationtest-history.migration.migrationPath=dbmigration/migrationtest-history
ebean.migrationtest-history.migration.strict=true
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,11 @@ public static void main(String[] args) throws IOException {
List<String> pendingDrops = migration.getPendingDrops();
assertThat(pendingDrops).contains("1.1");

//System.setProperty("ddl.migration.pendingDropsFor", "1.1");
migration.setGeneratePendingDrop("1.1");
assertThat(migration.generateMigration()).isEqualTo("1.2__dropsFor_1.1");
assertThatThrownBy(()->migration.generateMigration())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("No 'pendingDrops'"); // subsequent call
System.clearProperty("ddl.migration.pendingDropsFor");

server.shutdown();
logger.info("end");
Expand Down
Loading