Skip to content
Closed
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
Expand Up @@ -16,12 +16,12 @@

package org.springframework.boot.autoconfigure.flyway;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

Expand Down Expand Up @@ -104,6 +104,8 @@ public static class FlywayConfiguration {

private List<FlywayCallback> flywayCallbacks;

private static final String VENDOR_PLACEHOLDER = "{vendor}";

public FlywayConfiguration(FlywayProperties properties,
ResourceLoader resourceLoader, ObjectProvider<DataSource> dataSource,
@FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
Expand All @@ -117,28 +119,6 @@ public FlywayConfiguration(FlywayProperties properties,
this.flywayCallbacks = flywayCallbacks.getIfAvailable(Collections::emptyList);
}

@PostConstruct
public void checkLocationExists() {
if (this.properties.isCheckLocation()) {
Assert.state(!this.properties.getLocations().isEmpty(),
"Migration script locations not configured");
boolean exists = hasAtLeastOneLocation();
Assert.state(exists,
() -> "Cannot find migrations location in: " + this.properties
.getLocations()
+ " (please add migrations or check your Flyway configuration)");
}
}

private boolean hasAtLeastOneLocation() {
for (String location : this.properties.getLocations()) {
if (this.resourceLoader.getResource(location).exists()) {
return true;
}
}
return false;
}

@Bean
@ConfigurationProperties(prefix = "spring.flyway")
public Flyway flyway() {
Expand All @@ -156,10 +136,61 @@ else if (this.flywayDataSource != null) {
}
flyway.setCallbacks(this.flywayCallbacks
.toArray(new FlywayCallback[this.flywayCallbacks.size()]));
flyway.setLocations(this.properties.getLocations().toArray(new String[0]));
String[] locations = resolveLocations(this.properties.getLocations().toArray(new String[0]), flyway.getDataSource());
checkLocationExists(locations);
flyway.setLocations(locations);
return flyway;
}

private static String[] resolveLocations(String[] locations, DataSource dataSource) {
if (usesVendorLocation(locations)) {
try {
String url = (String) JdbcUtils
.extractDatabaseMetaData(dataSource, "getURL");
DatabaseDriver vendor = DatabaseDriver.fromJdbcUrl(url);
if (vendor != DatabaseDriver.UNKNOWN) {
for (int i = 0; i < locations.length; i++) {
locations[i] = locations[i].replace(VENDOR_PLACEHOLDER,
vendor.getId());
}
}
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException(ex);
}
}
return locations;
}

private static boolean usesVendorLocation(String... locations) {
for (String location : locations) {
if (location.contains(VENDOR_PLACEHOLDER)) {
return true;
}
}
return false;
}

private void checkLocationExists(String... locations) {
if (this.properties.isCheckLocation()) {
Assert.state(locations.length != 0,
"Migration script locations not configured");
boolean exists = hasAtLeastOneLocation(locations);
Assert.state(exists,
() -> "Cannot find migrations location in: " + Arrays.asList(locations)
+ " (please add migrations or check your Flyway configuration)");
}
}

private boolean hasAtLeastOneLocation(String... locations) {
for (String location : locations) {
if (this.resourceLoader.getResource(location).exists()) {
return true;
}
}
return false;
}

@Bean
@ConditionalOnMissingBean
public FlywayMigrationInitializer flywayInitializer(Flyway flyway) {
Expand Down Expand Up @@ -202,38 +233,13 @@ public FlywayJpaDependencyConfiguration() {

private static class SpringBootFlyway extends Flyway {

private static final String VENDOR_PLACEHOLDER = "{vendor}";

@Override
public void setLocations(String... locations) {
if (usesVendorLocation(locations)) {
try {
String url = (String) JdbcUtils
.extractDatabaseMetaData(getDataSource(), "getURL");
DatabaseDriver vendor = DatabaseDriver.fromJdbcUrl(url);
if (vendor != DatabaseDriver.UNKNOWN) {
for (int i = 0; i < locations.length; i++) {
locations[i] = locations[i].replace(VENDOR_PLACEHOLDER,
vendor.getId());
}
}
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException(ex);
}
}
locations = FlywayConfiguration.resolveLocations(locations,
getDataSource());
super.setLocations(locations);
}

private boolean usesVendorLocation(String... locations) {
for (String location : locations) {
if (location.contains(VENDOR_PLACEHOLDER)) {
return true;
}
}
return false;
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,17 @@ public void useVendorDirectory() {
});
}

@Test
public void useOneLocationWithVendorDirectory() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.locations=classpath:db/vendors/{vendor}")
.run((context) -> {
assertThat(context).hasSingleBean(Flyway.class);
Flyway flyway = context.getBean(Flyway.class);
assertThat(flyway.getLocations()).containsExactly("classpath:db/vendors/h2");
});
}

@Test
public void callbacksAreConfiguredAndOrdered() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
Expand Down