Polish "Add support for Maven resources"

See gh-967
This commit is contained in:
Stephane Nicoll
2019-08-23 15:03:05 +02:00
parent df62424c0e
commit b711ac73c9
7 changed files with 437 additions and 189 deletions

View File

@@ -16,13 +16,9 @@
package io.spring.initializr.generator.buildsystem.maven;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import io.spring.initializr.generator.buildsystem.Build;
import io.spring.initializr.generator.buildsystem.BuildItemResolver;
@@ -31,6 +27,7 @@ import io.spring.initializr.generator.buildsystem.BuildItemResolver;
* Maven build for a project.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class MavenBuild extends Build {
@@ -46,9 +43,11 @@ public class MavenBuild extends Build {
private final Map<String, String> properties = new TreeMap<>();
private MavenPluginContainer plugins = new MavenPluginContainer();
private final MavenResourceContainer resources = new MavenResourceContainer();
private final Map<String, ResourceBuilder> resources = new LinkedHashMap<>();
private final MavenResourceContainer testResources = new MavenResourceContainer();
private MavenPluginContainer plugins = new MavenPluginContainer();
private String packaging;
@@ -109,6 +108,14 @@ public class MavenBuild extends Build {
this.testSourceDirectory = testSourceDirectory;
}
public MavenResourceContainer resources() {
return this.resources;
}
public MavenResourceContainer testResources() {
return this.testResources;
}
public MavenPluginContainer plugins() {
return this.plugins;
}
@@ -121,110 +128,4 @@ public class MavenBuild extends Build {
return this.packaging;
}
public void resource(String directory, Consumer<ResourceBuilder> customizer) {
customizer.accept(this.resources.computeIfAbsent(directory, (key) -> new ResourceBuilder(directory)));
}
public List<Resource> getResources() {
return this.resources.values().stream().map(ResourceBuilder::build).collect(Collectors.toList());
}
/**
*
* Builder to create a {@link Resource}.
*
*
*/
public static final class ResourceBuilder {
private String directory;
private String targetPath;
private boolean filtering;
private List<String> includes = new ArrayList<>();
private List<String> excludes = new ArrayList<>();
public ResourceBuilder(String directory) {
this.directory = directory;
}
Resource build() {
return new Resource(this.directory, this.targetPath, this.filtering, this.includes, this.excludes);
}
public ResourceBuilder include(String... includes) {
this.includes = Arrays.asList(includes);
return this;
}
public ResourceBuilder targetPath(String targetPath) {
this.targetPath = targetPath;
return this;
}
public ResourceBuilder filtering(Boolean filtering) {
this.filtering = filtering;
return this;
}
public ResourceBuilder excludes(String... excludes) {
this.excludes = Arrays.asList(excludes);
return this;
}
}
/**
*
* An {@code <resource>} of a {@link MavenBuild}.
*
*
*/
public static final class Resource {
private String directory;
private String targetPath;
private boolean filtering;
private List<String> includes = new ArrayList<>();
private List<String> excludes = new ArrayList<>();
public Resource(String directory, String targetPath, boolean filtering, List<String> includes,
List<String> excludes) {
super();
this.directory = directory;
this.targetPath = targetPath;
this.filtering = filtering;
this.includes = includes;
this.excludes = excludes;
}
public String getDirectory() {
return this.directory;
}
public List<String> getIncludes() {
return this.includes;
}
public String getTargetPath() {
return this.targetPath;
}
public boolean isFiltering() {
return this.filtering;
}
public List<String> getExcludes() {
return this.excludes;
}
}
}

View File

@@ -33,7 +33,6 @@ import io.spring.initializr.generator.buildsystem.DependencyComparator;
import io.spring.initializr.generator.buildsystem.DependencyContainer;
import io.spring.initializr.generator.buildsystem.DependencyScope;
import io.spring.initializr.generator.buildsystem.MavenRepository;
import io.spring.initializr.generator.buildsystem.maven.MavenBuild.Resource;
import io.spring.initializr.generator.buildsystem.maven.MavenPlugin.Configuration;
import io.spring.initializr.generator.buildsystem.maven.MavenPlugin.Execution;
import io.spring.initializr.generator.buildsystem.maven.MavenPlugin.Setting;
@@ -241,8 +240,8 @@ public class MavenBuildWriter {
}
private void writeBuild(IndentingWriter writer, MavenBuild build) {
if (build.getSourceDirectory() == null && build.getTestSourceDirectory() == null && build.plugins().isEmpty()
&& build.getResources().isEmpty()) {
if (build.getSourceDirectory() == null && build.getTestSourceDirectory() == null && build.resources().isEmpty()
&& build.testResources().isEmpty() && build.plugins().isEmpty()) {
return;
}
writer.println();
@@ -256,19 +255,39 @@ public class MavenBuildWriter {
}
private void writeResources(IndentingWriter writer, MavenBuild build) {
if (build.getResources().isEmpty()) {
return;
if (!build.resources().isEmpty()) {
writeElement(writer, "resources", () -> writeCollection(writer,
build.resources().values().collect(Collectors.toList()), this::writeResource));
}
if (!build.testResources().isEmpty()) {
writeElement(writer, "testResources", () -> writeCollection(writer,
build.testResources().values().collect(Collectors.toList()), this::writeTestResource));
}
writeElement(writer, "resources", () -> writeCollection(writer, build.getResources(), this::writeResource));
}
private void writeResource(IndentingWriter writer, Resource resource) {
writeElement(writer, "resource", () -> {
private void writeResource(IndentingWriter writer, MavenResource resource) {
writeResource(writer, resource, "resource");
}
private void writeTestResource(IndentingWriter writer, MavenResource resource) {
writeResource(writer, resource, "testResource");
}
private void writeResource(IndentingWriter writer, MavenResource resource, String resourceName) {
writeElement(writer, resourceName, () -> {
writeSingleElement(writer, "directory", resource.getDirectory());
writeSingleElement(writer, "targetPath", resource.getTargetPath());
if (resource.isFiltering()) {
writeSingleElement(writer, "filtering", "true");
}
if (!resource.getIncludes().isEmpty()) {
writeElement(writer, "includes",
() -> writeCollection(writer, resource.getIncludes(), this::writeResourceInclude));
}
if (!resource.getExcludes().isEmpty()) {
writeElement(writer, "excludes",
() -> writeCollection(writer, resource.getExcludes(), this::writeResourceExclude));
}
});
}
@@ -276,6 +295,10 @@ public class MavenBuildWriter {
writeSingleElement(writer, "include", include);
}
private void writeResourceExclude(IndentingWriter writer, String exclude) {
writeSingleElement(writer, "exclude", exclude);
}
private void writePlugins(IndentingWriter writer, MavenBuild build) {
if (build.plugins().isEmpty()) {
return;

View File

@@ -0,0 +1,138 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.generator.buildsystem.maven;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A resource of a {@link MavenBuild}.
*
* @author Stephane Nicoll
*/
public class MavenResource {
private final String directory;
private final String targetPath;
private final boolean filtering;
private final List<String> includes;
private final List<String> excludes;
public MavenResource(Builder builder) {
this.directory = builder.directory;
this.targetPath = builder.targetPath;
this.filtering = builder.filtering;
this.includes = builder.includes;
this.excludes = builder.excludes;
}
/**
* Return the directory where resources are to be found. Can use regular maven token
* such as {@code ${basedir}/src/main}.
* @return the resources directory
*/
public String getDirectory() {
return this.directory;
}
/**
* Return the directory structure to place the set of resources from a build. Return
* {@code null} by default which represents the root directory.
* @return the target path or {@code null}
*/
public String getTargetPath() {
return this.targetPath;
}
/**
* Specify if filtering is enabled when copying resources.
* @return {@code true} if filtering is enabled
*/
public boolean isFiltering() {
return this.filtering;
}
/**
* Return files patterns which specify the files to include as resources under that
* specified directory. Can use {@code *} for all.
* @return the include patterns
*/
public List<String> getIncludes() {
return this.includes;
}
/**
* Return files patterns which specify the files to ignore as resources under that
* specified directory. In conflicts between {@code include} and {@code exclude},
* {@code exclude} wins.
* @return the exclude patterns
*/
public List<String> getExcludes() {
return this.excludes;
}
/**
* Builder for a resource.
*/
public static class Builder {
private final String directory;
private String targetPath;
private boolean filtering;
private List<String> includes = new ArrayList<>();
private List<String> excludes = new ArrayList<>();
public Builder(String directory) {
this.directory = directory;
}
public Builder targetPath(String targetPath) {
this.targetPath = targetPath;
return this;
}
public Builder filtering(Boolean filtering) {
this.filtering = filtering;
return this;
}
public Builder includes(String... includes) {
this.includes = Arrays.asList(includes);
return this;
}
public Builder excludes(String... excludes) {
this.excludes = Arrays.asList(excludes);
return this;
}
public MavenResource build() {
return new MavenResource(this);
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.generator.buildsystem.maven;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* A container for {@link MavenResource}s.
*
* @author Stephane Nicoll
*/
public class MavenResourceContainer {
private final Map<String, MavenResource.Builder> resources = new LinkedHashMap<>();
/**
* Specify if this container is empty.
* @return {@code true} if no {@link MavenResource} is added
*/
public boolean isEmpty() {
return this.resources.isEmpty();
}
/**
* Specify if this container has a resource the specified {@code directory}.
* @param directory the resource directory
* @return {@code true} if an item for the specified {@code directory} exists
*/
public boolean has(String directory) {
return this.resources.containsKey(directory);
}
/**
* Returns a {@link Stream} of registered {@link MavenResource}s.
* @return a stream of {@link MavenResource}s
*/
public Stream<MavenResource> values() {
return this.resources.values().stream().map(MavenResource.Builder::build);
}
/**
* Add a resource with default settings for the specified {@code directory}.
* @param directory the directory to add
*/
public void add(String directory) {
this.resources.computeIfAbsent(directory, (key) -> new MavenResource.Builder(directory));
}
/**
* Add a resource with default settings for the specified {@code directory} and
* {@link Consumer} to customize the resource. If the resource has already been added,
* the consumer can be used to further tune the existing resource configuration.
* @param directory the directory to add
* @param resource a {@link Consumer} to customize the {@link MavenResource}
*/
public void add(String directory, Consumer<MavenResource.Builder> resource) {
resource.accept(this.resources.computeIfAbsent(directory, (key) -> new MavenResource.Builder(directory)));
}
/**
* Remove the resource with the specified {@code directory}.
* @param directory the directory to remove
* @return {@code true} if such a resource was registered, {@code false} otherwise
*/
public boolean remove(String directory) {
return this.resources.remove(directory) != null;
}
}

View File

@@ -16,13 +16,9 @@
package io.spring.initializr.generator.buildsystem.maven;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.junit.jupiter.api.Test;
import io.spring.initializr.generator.buildsystem.maven.MavenBuild.Resource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MavenBuild}.
@@ -32,6 +28,35 @@ import io.spring.initializr.generator.buildsystem.maven.MavenBuild.Resource;
*/
class MavenBuildTests {
@Test
void mavenResourcesEmptyByDefault() {
MavenBuild build = new MavenBuild();
assertThat(build.resources().isEmpty()).isTrue();
assertThat(build.testResources().isEmpty()).isTrue();
}
@Test
void mavenResourcesCanBeConfigured() {
MavenBuild build = new MavenBuild();
build.resources().add("src/main/custom", (resource) -> resource.filtering(true));
assertThat(build.resources().values()).hasOnlyOneElementSatisfying((resource) -> {
assertThat(resource.getDirectory()).isEqualTo("src/main/custom");
assertThat(resource.isFiltering()).isTrue();
});
assertThat(build.testResources().isEmpty()).isTrue();
}
@Test
void mavenTestResourcesCanBeConfigured() {
MavenBuild build = new MavenBuild();
build.testResources().add("src/test/custom", (resource) -> resource.excludes("**/*.gen"));
assertThat(build.resources().isEmpty()).isTrue();
assertThat(build.testResources().values()).hasOnlyOneElementSatisfying((resource) -> {
assertThat(resource.getDirectory()).isEqualTo("src/test/custom");
assertThat(resource.getExcludes()).containsExactly("**/*.gen");
});
}
@Test
void mavenPluginCanBeConfigured() {
MavenBuild build = new MavenBuild();
@@ -114,52 +139,4 @@ class MavenBuildTests {
.hasOnlyOneElementSatisfying((testPlugin) -> assertThat(testPlugin.isExtensions()).isTrue());
}
@Test
void mavenResourcesCanBeLoaded() {
MavenBuild build = new MavenBuild();
build.resource("src/main/resources", (resource) -> {
resource.include("**/*.yml");
resource.filtering(true);
resource.targetPath("targetPath");
resource.excludes("**/*.properties");
});
Resource resource = build.getResources().get(0);
assertThat(resource.getIncludes().get(0)).isEqualTo("**/*.yml");
assertThat(resource.getExcludes().get(0)).isEqualTo("**/*.properties");
assertThat(resource.isFiltering()).isTrue();
assertThat(resource.getTargetPath()).isEqualTo("targetPath");
assertThat(resource.getDirectory()).isEqualTo("src/main/resources");
}
@Test
void mavenResourcesFilteringFalseByDefault() {
MavenBuild build = new MavenBuild();
build.resource("src/main/resources", (resource) -> {
});
Resource resource = build.getResources().get(0);
assertThat(resource.isFiltering()).isFalse();
}
@Test
void mavenResourcesNotLoadedByDefault() {
MavenBuild build = new MavenBuild();
build.plugin("com.example", "test-plugin");
List<Resource> resources = build.getResources();
assertThat(resources).isEmpty();
}
}

View File

@@ -344,6 +344,38 @@ class MavenBuildWriterTests {
assertThat(firstBom).textAtPath("scope").isEqualTo("import");
}
@Test
void pomWithResources() throws Exception {
MavenBuild build = new MavenBuild();
build.resources().add("src/main/custom", (resource) -> resource.includes("**/*.properties"));
generatePom(build, (pom) -> {
assertThat(pom).textAtPath("/project/build/resources/resource/directory").isEqualTo("src/main/custom");
assertThat(pom).textAtPath("/project/build/resources/resource/targetPath").isNullOrEmpty();
assertThat(pom).textAtPath("/project/build/resources/resource/filtering").isNullOrEmpty();
assertThat(pom).textAtPath("/project/build/resources/resource/includes/include")
.isEqualTo("**/*.properties");
assertThat(pom).textAtPath("/project/build/resources/resource/excludes").isNullOrEmpty();
assertThat(pom).textAtPath("/project/build/testResources").isNullOrEmpty();
});
}
@Test
void pomWithTestResources() throws Exception {
MavenBuild build = new MavenBuild();
build.testResources().add("src/test/custom",
(resource) -> resource.excludes("**/*.gen").filtering(true).targetPath("test"));
generatePom(build, (pom) -> {
assertThat(pom).textAtPath("/project/build/resources").isNullOrEmpty();
assertThat(pom).textAtPath("/project/build/testResources/testResource/directory")
.isEqualTo("src/test/custom");
assertThat(pom).textAtPath("/project/build/testResources/testResource/targetPath").isEqualTo("test");
assertThat(pom).textAtPath("/project/build/testResources/testResource/filtering").isEqualTo("true");
assertThat(pom).textAtPath("/project/build/testResources/testResource/includes").isNullOrEmpty();
assertThat(pom).textAtPath("/project/build/testResources/testResource/excludes/exclude")
.isEqualTo("**/*.gen");
});
}
@Test
void pomWithPlugin() throws Exception {
MavenBuild build = new MavenBuild();
@@ -444,6 +476,14 @@ class MavenBuildWriterTests {
});
}
@Test
void pomWithEmptyBuild() throws Exception {
MavenBuild build = new MavenBuild();
build.setGroup("com.example.demo");
build.setArtifact("demo");
generatePom(build, (pom) -> assertThat(pom).textAtPath("/project/build/").isNullOrEmpty());
}
@Test
void pomWithMavenCentral() throws Exception {
MavenBuild build = new MavenBuild();
@@ -546,22 +586,6 @@ class MavenBuildWriterTests {
generatePom(build, (pom) -> assertThat(pom).textAtPath("/project/version").isEqualTo("1.2.4.RELEASE"));
}
@Test
void pomWithResources() throws Exception {
MavenBuild build = new MavenBuild();
build.resource("src/main/resources", (resource) -> resource.include("**/*.properties"));
generatePom(build, (pom) -> {
assertThat(pom).textAtPath("/project/build/resources/resource/includes/include")
.isEqualTo("**/*.properties");
assertThat(pom).textAtPath("/project/build/resources/resource/directory").isEqualTo("src/main/resources");
});
}
private void generatePom(MavenBuild mavenBuild, Consumer<NodeAssert> consumer) throws Exception {
MavenBuildWriter writer = new MavenBuildWriter();
StringWriter out = new StringWriter();

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.generator.buildsystem.maven;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MavenResourceContainer}.
*
* @author Stephane Nicoll
*/
class MavenResourceContainerTests {
@Test
void mavenResourceCanBeConfigured() {
MavenResourceContainer container = new MavenResourceContainer();
container.add("src/main/resources", (resource) -> {
resource.targetPath("targetPath");
resource.filtering(true);
resource.includes("**/*.yml");
resource.excludes("**/*.properties");
});
assertThat(container.values()).hasOnlyOneElementSatisfying((resource) -> {
assertThat(resource.getDirectory()).isEqualTo("src/main/resources");
assertThat(resource.getTargetPath()).isEqualTo("targetPath");
assertThat(resource.isFiltering()).isTrue();
assertThat(resource.getIncludes()).containsExactly("**/*.yml");
assertThat(resource.getExcludes()).containsExactly("**/*.properties");
});
}
@Test
void mavenResourceCanBeAmended() {
MavenResourceContainer container = new MavenResourceContainer();
container.add("src/main/resources", (resource) -> {
resource.filtering(true);
resource.includes("**/*.yml");
});
container.add("src/main/resources", (resource) -> {
resource.includes("**/*.yaml");
resource.excludes("**/*.properties");
});
assertThat(container.values()).hasOnlyOneElementSatisfying((resource) -> {
assertThat(resource.getDirectory()).isEqualTo("src/main/resources");
assertThat(resource.getTargetPath()).isNull();
assertThat(resource.isFiltering()).isTrue();
assertThat(resource.getIncludes()).containsExactly("**/*.yaml");
assertThat(resource.getExcludes()).containsExactly("**/*.properties");
});
assertThat(container.isEmpty()).isFalse();
}
@Test
void mavenResourceDefaultValues() {
MavenResourceContainer container = new MavenResourceContainer();
container.add("src/main/custom");
assertThat(container.values()).hasOnlyOneElementSatisfying((resource) -> {
assertThat(resource.getDirectory()).isEqualTo("src/main/custom");
assertThat(resource.getTargetPath()).isNull();
assertThat(resource.isFiltering()).isFalse();
assertThat(resource.getIncludes()).isEmpty();
assertThat(resource.getExcludes()).isEmpty();
});
}
@Test
void mavenResourceCanBeSearched() {
MavenResourceContainer container = new MavenResourceContainer();
assertThat(container.has("src/main/test")).isFalse();
container.add("src/main/test");
assertThat(container.has("src/main/test")).isTrue();
}
@Test
void mavenResourceCanBeRemoved() {
MavenResourceContainer container = new MavenResourceContainer();
container.add("src/main/test");
assertThat(container.has("src/main/test")).isTrue();
assertThat(container.remove("src/main/test")).isTrue();
assertThat(container.has("src/main/test")).isFalse();
}
}