Minimize and centralize assumptions about build output

Closes gh-15471
This commit is contained in:
Andy Wilkinson
2018-12-14 17:50:20 +00:00
parent 7d0a7a65c8
commit 61d04db0d7
57 changed files with 778 additions and 337 deletions

View File

@@ -41,7 +41,7 @@ public class ResourceHandlingApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ResourceHandlingApplication.class)
.properties("server.port:0")
.listeners(new WebServerPortFileWriter("target/server.port")).run(args);
.listeners(new WebServerPortFileWriter(args[0])).run(args);
}
@Bean

View File

@@ -26,6 +26,7 @@ import java.util.List;
import org.junit.rules.ExternalResource;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
@@ -40,12 +41,16 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
private final ApplicationBuilder applicationBuilder;
private final BuildOutput buildOutput;
private Process process;
private int httpPort;
protected AbstractApplicationLauncher(ApplicationBuilder applicationBuilder) {
protected AbstractApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
this.applicationBuilder = applicationBuilder;
this.buildOutput = buildOutput;
}
@Override
@@ -62,7 +67,7 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
return this.httpPort;
}
protected abstract List<String> getArguments(File archive);
protected abstract List<String> getArguments(File archive, File serverPortFile);
protected abstract File getWorkingDirectory();
@@ -70,14 +75,12 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
private Process startApplication() throws Exception {
File workingDirectory = getWorkingDirectory();
File serverPortFile = (workingDirectory != null)
? new File(workingDirectory, "target/server.port")
: new File("target/server.port");
File serverPortFile = new File(this.buildOutput.getRootLocation(), "server.port");
serverPortFile.delete();
File archive = this.applicationBuilder.buildApplication();
List<String> arguments = new ArrayList<>();
arguments.add(System.getProperty("java.home") + "/bin/java");
arguments.addAll(getArguments(archive));
arguments.addAll(getArguments(archive, serverPortFile));
ProcessBuilder processBuilder = new ProcessBuilder(
StringUtils.toStringArray(arguments));
if (workingDirectory != null) {

View File

@@ -26,6 +26,7 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResponseErrorHandler;
@@ -48,6 +49,9 @@ public abstract class AbstractEmbeddedServletContainerIntegrationTests {
};
public static final BuildOutput buildOutput = new BuildOutput(
AbstractEmbeddedServletContainerIntegrationTests.class);
@Rule
public final AbstractApplicationLauncher launcher;
@@ -70,8 +74,9 @@ public abstract class AbstractEmbeddedServletContainerIntegrationTests {
for (Class<? extends AbstractApplicationLauncher> launcherClass : applicationLaunchers) {
try {
AbstractApplicationLauncher launcher = launcherClass
.getDeclaredConstructor(ApplicationBuilder.class)
.newInstance(applicationBuilder);
.getDeclaredConstructor(ApplicationBuilder.class,
BuildOutput.class)
.newInstance(applicationBuilder, buildOutput);
String name = StringUtils.capitalize(container) + ": "
+ launcher.getDescription(packaging);
parameters.add(new Object[] { name, launcher });

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@@ -27,6 +27,7 @@ import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
@@ -40,14 +41,16 @@ import org.springframework.util.StringUtils;
*/
class BootRunApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/run");
private final File exploded;
BootRunApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
BootRunApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
this.exploded = new File(buildOutput.getRootLocation(), "run");
}
@Override
protected List<String> getArguments(File archive) {
protected List<String> getArguments(File archive, File serverPortFile) {
try {
explodeArchive(archive);
deleteLauncherClasses();
@@ -64,7 +67,8 @@ class BootRunApplicationLauncher extends AbstractApplicationLauncher {
return Arrays.asList("-cp",
StringUtils.collectionToDelimitedString(classpath,
File.pathSeparator),
"com.example.ResourceHandlingApplication");
"com.example.ResourceHandlingApplication",
serverPortFile.getAbsolutePath());
}
catch (IOException ex) {
throw new RuntimeException(ex);
@@ -76,12 +80,12 @@ class BootRunApplicationLauncher extends AbstractApplicationLauncher {
}
private File populateTargetClasses(File archive) throws IOException {
File targetClasses = new File(this.exploded, "target/classes");
targetClasses.mkdirs();
File builtClasses = new File(this.exploded, "built/classes");
builtClasses.mkdirs();
File source = new File(this.exploded, getClassesPath(archive));
FileSystemUtils.copyRecursively(source, targetClasses);
FileSystemUtils.copyRecursively(source, builtClasses);
FileSystemUtils.deleteRecursively(source);
return targetClasses;
return builtClasses;
}
private File populateDependencies(File archive) throws IOException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@@ -22,9 +22,11 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
@@ -36,15 +38,17 @@ import org.springframework.util.StreamUtils;
*/
class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/exploded");
private final Supplier<File> exploded;
ExplodedApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
ExplodedApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
this.exploded = () -> new File(buildOutput.getRootLocation(), "exploded");
}
@Override
protected File getWorkingDirectory() {
return this.exploded;
return this.exploded.get();
}
@Override
@@ -53,13 +57,14 @@ class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
}
@Override
protected List<String> getArguments(File archive) {
protected List<String> getArguments(File archive, File serverPortFile) {
String mainClass = (archive.getName().endsWith(".war")
? "org.springframework.boot.loader.WarLauncher"
: "org.springframework.boot.loader.JarLauncher");
try {
explodeArchive(archive);
return Arrays.asList("-cp", this.exploded.getAbsolutePath(), mainClass);
return Arrays.asList("-cp", this.exploded.get().getAbsolutePath(), mainClass,
serverPortFile.getAbsolutePath());
}
catch (IOException ex) {
throw new RuntimeException(ex);
@@ -67,12 +72,12 @@ class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
}
private void explodeArchive(File archive) throws IOException {
FileSystemUtils.deleteRecursively(this.exploded);
FileSystemUtils.deleteRecursively(this.exploded.get());
JarFile jarFile = new JarFile(archive);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
File extracted = new File(this.exploded, jarEntry.getName());
File extracted = new File(this.exploded.get(), jarEntry.getName());
if (jarEntry.isDirectory()) {
extracted.mkdirs();
}

View File

@@ -27,6 +27,7 @@ import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
@@ -40,10 +41,12 @@ import org.springframework.util.StringUtils;
*/
class IdeApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/the+ide application");
private final File exploded;
IdeApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
IdeApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
this.exploded = new File(buildOutput.getRootLocation(), "the+ide application");
}
@Override
@@ -57,18 +60,18 @@ class IdeApplicationLauncher extends AbstractApplicationLauncher {
}
@Override
protected List<String> getArguments(File archive) {
protected List<String> getArguments(File archive, File serverPortFile) {
try {
explodeArchive(archive, this.exploded);
deleteLauncherClasses();
File targetClasses = populateTargetClasses(archive);
File builtClasses = populateBuiltClasses(archive);
File dependencies = populateDependencies(archive);
File resourcesProject = explodedResourcesProject(dependencies);
if (archive.getName().endsWith(".war")) {
populateSrcMainWebapp();
}
List<String> classpath = new ArrayList<>();
classpath.add(targetClasses.getAbsolutePath());
classpath.add(builtClasses.getAbsolutePath());
for (File dependency : dependencies.listFiles()) {
classpath.add(dependency.getAbsolutePath());
}
@@ -76,20 +79,21 @@ class IdeApplicationLauncher extends AbstractApplicationLauncher {
return Arrays.asList("-cp",
StringUtils.collectionToDelimitedString(classpath,
File.pathSeparator),
"com.example.ResourceHandlingApplication");
"com.example.ResourceHandlingApplication",
serverPortFile.getAbsolutePath());
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private File populateTargetClasses(File archive) throws IOException {
File targetClasses = new File(this.exploded, "target/classes");
targetClasses.mkdirs();
private File populateBuiltClasses(File archive) throws IOException {
File builtClasses = new File(this.exploded, "built/classes");
builtClasses.mkdirs();
File source = new File(this.exploded, getClassesPath(archive));
FileSystemUtils.copyRecursively(source, targetClasses);
FileSystemUtils.copyRecursively(source, builtClasses);
FileSystemUtils.deleteRecursively(source);
return targetClasses;
return builtClasses;
}
private File populateDependencies(File archive) throws IOException {
@@ -108,7 +112,7 @@ class IdeApplicationLauncher extends AbstractApplicationLauncher {
private File explodedResourcesProject(File dependencies) throws IOException {
File resourcesProject = new File(this.exploded,
"resources-project/target/classes");
"resources-project/built/classes");
File resourcesJar = new File(dependencies, "resources-1.0.jar");
explodeArchive(resourcesJar, resourcesProject);
resourcesJar.delete();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@@ -20,6 +20,8 @@ import java.io.File;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.testsupport.BuildOutput;
/**
* {@link AbstractApplicationLauncher} that launches a packaged Spring Boot application
* using {@code java -jar}.
@@ -28,8 +30,9 @@ import java.util.List;
*/
class PackagedApplicationLauncher extends AbstractApplicationLauncher {
PackagedApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
PackagedApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
}
@Override
@@ -43,8 +46,9 @@ class PackagedApplicationLauncher extends AbstractApplicationLauncher {
}
@Override
protected List<String> getArguments(File archive) {
return Arrays.asList("-jar", archive.getAbsolutePath());
protected List<String> getArguments(File archive, File serverPortFile) {
return Arrays.asList("-jar", archive.getAbsolutePath(),
serverPortFile.getAbsolutePath());
}
}