diff --git a/docs/src/main/asciidoc/spring-cloud-config.adoc b/docs/src/main/asciidoc/spring-cloud-config.adoc index 22166cc0..744b94b0 100644 --- a/docs/src/main/asciidoc/spring-cloud-config.adoc +++ b/docs/src/main/asciidoc/spring-cloud-config.adoc @@ -39,10 +39,11 @@ Git, but just loads the config files from the local classpath (or anywhere else you want to point to with "spring.cloud.config.server.locations"). To use the native profile just launch the Config Server with "spring.profiles.active=native". In -the native profile the repository only has the "current" set of -configuration files, so the "label" specification in the HTTP -resources is ignored (i.e. it's like always pulling from "master" in -the Git implementation). +the native profile the repository the "label" specification in the +HTTP resources is added to the search path, so properties files are +loaded from each search location *and* a subdirectory with the same +name as the label (the labelled properties take precedence in the +Spring Environment). === Security diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java index ff55cf89..eb34958f 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java @@ -177,7 +177,7 @@ public class JGitEnvironmentRepository implements EnvironmentRepository { pull(git, label, ref); } environment.setSearchLocations(getSearchLocations(basedir)); - return clean(environment.findOne(application, profile, label)); + return clean(environment.findOne(application, profile, "")); } private String[] getSearchLocations(File dir) { diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepository.java index 83e24d03..b74f4a03 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepository.java @@ -23,11 +23,11 @@ import java.util.List; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.config.Environment; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.StandardEnvironment; -import org.springframework.cloud.config.Environment; import org.springframework.util.StringUtils; /** @@ -46,6 +46,9 @@ public class SpringApplicationEnvironmentRepository implements EnvironmentReposi private boolean failOnError = false; + private static final String[] DEFAULT_LOCATIONS = new String[] { "classpath:/", + "classpath:/config/", "file:./", "file:./config/" }; + /** * Strategy to determine how to handle exceptions during decryption. * @@ -62,12 +65,12 @@ public class SpringApplicationEnvironmentRepository implements EnvironmentReposi ConfigurableEnvironment environment = getEnvironment(profile); builder.environment(environment); builder.web(false).showBanner(false); - String[] args = getArgs(config); + String[] args = getArgs(config, label); ConfigurableApplicationContext context = builder.run(args); environment.getPropertySources().remove("profiles"); try { - return new NativeEnvironmentRepository(environment).findOne( - config, profile, label); + return new NativeEnvironmentRepository(environment).findOne(config, profile, + label); } finally { context.close(); @@ -84,7 +87,7 @@ public class SpringApplicationEnvironmentRepository implements EnvironmentReposi return environment; } - private String[] getArgs(String config) { + private String[] getArgs(String config, String label) { List list = new ArrayList(); if (!config.startsWith("application")) { config = "application," + config; @@ -93,22 +96,41 @@ public class SpringApplicationEnvironmentRepository implements EnvironmentReposi list.add("--spring.cloud.bootstrap.enabled=false"); list.add("--encrypt.failOnError=" + failOnError); if (locations != null) { - list.add("--spring.config.location=" - + StringUtils.arrayToCommaDelimitedString(locations)); + list.add("--spring.config.location=" + getLocations(this.locations, label)); + } + else { + list.add("--spring.config.location=" + getLocations(DEFAULT_LOCATIONS, label)); } return list.toArray(new String[0]); } + private String getLocations(String[] locations, String label) { + List output = new ArrayList(); + for (String location : locations) { + output.add(location); + } + for (String location : locations) { + if (isDirectory(location) && StringUtils.hasText(label)) { + output.add(location + label.trim() + "/"); + } + } + return StringUtils.collectionToCommaDelimitedString(output); + } + public void setSearchLocations(String... locations) { this.locations = locations; for (int i = 0; i < locations.length; i++) { String location = locations[i]; - if (!location.endsWith(".properties") && !location.endsWith(".yml") - && !location.endsWith(".yaml") && !location.endsWith("/")) { + if (isDirectory(location)&& !location.endsWith("/")) { location = location + "/"; } locations[i] = location; } } + private boolean isDirectory(String location) { + return !location.endsWith(".properties") && !location.endsWith(".yml") + && !location.endsWith(".yaml"); + } + } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepositoryTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepositoryTests.java index 25043488..f46a5a31 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepositoryTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SpringApplicationEnvironmentRepositoryTests.java @@ -56,4 +56,13 @@ public class SpringApplicationEnvironmentRepositoryTests { assertEquals(3, environment.getPropertySources().size()); } + @Test + public void labelled() { + repository.setSearchLocations("classpath:/test"); + Environment environment = repository.findOne("foo", "development", "dev"); + assertEquals(4, environment.getPropertySources().size()); + // position 1 because it has higher precendence than anything except the foo-development.properties + assertEquals("dev_bar", environment.getPropertySources().get(1).getSource().get("foo")); + } + } diff --git a/spring-cloud-config-server/src/test/resources/test/dev/foo.properties b/spring-cloud-config-server/src/test/resources/test/dev/foo.properties new file mode 100644 index 00000000..469386bf --- /dev/null +++ b/spring-cloud-config-server/src/test/resources/test/dev/foo.properties @@ -0,0 +1 @@ +foo: dev_bar \ No newline at end of file