mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Adjust defaults for ExtractCommand
It now extracts the contents of the JAR in a folder named after the JAR without the extension. It now also checks if the folder is empty. There's a new --force option to skip those checks. The "runner.jar" is now named like the uber JAR from which the extraction has been started. See gh-38276
This commit is contained in:
parent
1e402f9f41
commit
9411a4ce99
@ -45,5 +45,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootJar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -28,5 +28,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootJar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -31,5 +31,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootJar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -62,5 +62,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootJar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -40,5 +40,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootJar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -46,5 +46,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootWar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -29,5 +29,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootWar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -32,5 +32,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootWar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -63,5 +63,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootWar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -41,5 +41,5 @@ task listLayers(type: JavaExec) {
|
||||
task extractLayers(type: JavaExec) {
|
||||
classpath = bootWar.outputs.files
|
||||
systemProperties = [ "jarmode": "tools" ]
|
||||
args "extract", "--layers", "--launcher"
|
||||
args "extract", "--layers", "--launcher", "--destination", ".", "--force"
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
@ -52,7 +53,7 @@ class ExtractCommand extends Command {
|
||||
/**
|
||||
* Option to create a launcher.
|
||||
*/
|
||||
static final Option LAUNCHER_OPTION = Option.of("launcher", null, "Whether to extract the Spring Boot launcher");
|
||||
static final Option LAUNCHER_OPTION = Option.flag("launcher", "Whether to extract the Spring Boot launcher");
|
||||
|
||||
/**
|
||||
* Option to extract layers.
|
||||
@ -63,13 +64,18 @@ class ExtractCommand extends Command {
|
||||
* Option to specify the destination to write to.
|
||||
*/
|
||||
static final Option DESTINATION_OPTION = Option.of("destination", "string",
|
||||
"Directory to extract files to. Defaults to the current working directory");
|
||||
"Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)");
|
||||
|
||||
/**
|
||||
* Option to ignore non-empty directory error.
|
||||
*/
|
||||
static final Option FORCE_OPTION = Option.flag("force", "Whether to ignore non-empty directories, extract anyway");
|
||||
|
||||
private static final Option LIBRARIES_DIRECTORY_OPTION = Option.of("libraries", "string",
|
||||
"Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/");
|
||||
|
||||
private static final Option RUNNER_FILENAME_OPTION = Option.of("runner-filename", "string",
|
||||
"Name of the runner JAR file. Only applicable when not using --launcher. Defaults to runner.jar");
|
||||
private static final Option APPLICATION_FILENAME_OPTION = Option.of("application-filename", "string",
|
||||
"Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename");
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -81,7 +87,8 @@ class ExtractCommand extends Command {
|
||||
|
||||
ExtractCommand(Context context, Layers layers) {
|
||||
super("extract", "Extract the contents from the jar", Options.of(LAUNCHER_OPTION, LAYERS_OPTION,
|
||||
DESTINATION_OPTION, LIBRARIES_DIRECTORY_OPTION, RUNNER_FILENAME_OPTION), Parameters.none());
|
||||
DESTINATION_OPTION, LIBRARIES_DIRECTORY_OPTION, APPLICATION_FILENAME_OPTION, FORCE_OPTION),
|
||||
Parameters.none());
|
||||
this.context = context;
|
||||
this.layers = layers;
|
||||
}
|
||||
@ -90,7 +97,8 @@ class ExtractCommand extends Command {
|
||||
void run(PrintStream out, Map<Option, String> options, List<String> parameters) {
|
||||
try {
|
||||
checkJarCompatibility();
|
||||
File destination = getWorkingDirectory(options);
|
||||
File destination = getDestination(options);
|
||||
checkDirectoryIsEmpty(options, destination);
|
||||
FileResolver fileResolver = getFileResolver(destination, options);
|
||||
fileResolver.createDirectories();
|
||||
if (options.containsKey(LAUNCHER_OPTION)) {
|
||||
@ -99,7 +107,7 @@ class ExtractCommand extends Command {
|
||||
else {
|
||||
JarStructure jarStructure = getJarStructure();
|
||||
extractLibraries(fileResolver, jarStructure, options);
|
||||
createRunner(jarStructure, fileResolver, options);
|
||||
createApplication(jarStructure, fileResolver, options);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
@ -108,15 +116,36 @@ class ExtractCommand extends Command {
|
||||
catch (LayersNotEnabledException ex) {
|
||||
printError(out, "Layers are not enabled");
|
||||
}
|
||||
catch (AbortException ex) {
|
||||
printError(out, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkDirectoryIsEmpty(Map<Option, String> options, File destination) {
|
||||
if (options.containsKey(FORCE_OPTION)) {
|
||||
return;
|
||||
}
|
||||
if (!destination.exists()) {
|
||||
return;
|
||||
}
|
||||
if (!destination.isDirectory()) {
|
||||
throw new AbortException(destination.getAbsoluteFile() + " already exists and is not a directory");
|
||||
}
|
||||
File[] files = destination.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
throw new AbortException(destination.getAbsoluteFile() + " already exists and is not empty");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkJarCompatibility() throws IOException {
|
||||
File file = this.context.getArchiveFile();
|
||||
try (ZipInputStream stream = new ZipInputStream(new FileInputStream(file))) {
|
||||
ZipEntry entry = stream.getNextEntry();
|
||||
Assert.state(entry != null,
|
||||
() -> "File '%s' is not compatible; ensure jar file is valid and launch script is not enabled"
|
||||
.formatted(file));
|
||||
if (entry == null) {
|
||||
throw new AbortException(
|
||||
"File '%s' is not compatible; ensure jar file is valid and launch script is not enabled"
|
||||
.formatted(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,20 +178,31 @@ class ExtractCommand extends Command {
|
||||
}
|
||||
|
||||
private FileResolver getFileResolver(File destination, Map<Option, String> options) {
|
||||
String runnerFilename = getRunnerFilename(options);
|
||||
String applicationFilename = getApplicationFilename(options);
|
||||
if (!options.containsKey(LAYERS_OPTION)) {
|
||||
return new NoLayersFileResolver(destination, runnerFilename);
|
||||
return new NoLayersFileResolver(destination, applicationFilename);
|
||||
}
|
||||
Layers layers = getLayers();
|
||||
Set<String> layersToExtract = StringUtils.commaDelimitedListToSet(options.get(LAYERS_OPTION));
|
||||
return new LayersFileResolver(destination, layers, layersToExtract, runnerFilename);
|
||||
return new LayersFileResolver(destination, layers, layersToExtract, applicationFilename);
|
||||
}
|
||||
|
||||
private File getWorkingDirectory(Map<Option, String> options) {
|
||||
private File getDestination(Map<Option, String> options) {
|
||||
if (options.containsKey(DESTINATION_OPTION)) {
|
||||
return new File(options.get(DESTINATION_OPTION));
|
||||
File destination = new File(options.get(DESTINATION_OPTION));
|
||||
if (destination.isAbsolute()) {
|
||||
return destination;
|
||||
}
|
||||
return new File(this.context.getWorkingDir(), destination.getPath());
|
||||
}
|
||||
return this.context.getWorkingDir();
|
||||
return new File(this.context.getWorkingDir(), stripExtension(this.context.getArchiveFile().getName()));
|
||||
}
|
||||
|
||||
private static String stripExtension(String name) {
|
||||
if (name.toLowerCase(Locale.ROOT).endsWith(".jar") || name.toLowerCase(Locale.ROOT).endsWith(".war")) {
|
||||
return name.substring(0, name.length() - 4);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private JarStructure getJarStructure() {
|
||||
@ -199,9 +239,9 @@ class ExtractCommand extends Command {
|
||||
return Layers.get(this.context);
|
||||
}
|
||||
|
||||
private void createRunner(JarStructure jarStructure, FileResolver fileResolver, Map<Option, String> options)
|
||||
private void createApplication(JarStructure jarStructure, FileResolver fileResolver, Map<Option, String> options)
|
||||
throws IOException {
|
||||
File file = fileResolver.resolveRunner();
|
||||
File file = fileResolver.resolveApplication();
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
@ -221,11 +261,11 @@ class ExtractCommand extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
private String getRunnerFilename(Map<Option, String> options) {
|
||||
if (options.containsKey(RUNNER_FILENAME_OPTION)) {
|
||||
return options.get(RUNNER_FILENAME_OPTION);
|
||||
private String getApplicationFilename(Map<Option, String> options) {
|
||||
if (options.containsKey(APPLICATION_FILENAME_OPTION)) {
|
||||
return options.get(APPLICATION_FILENAME_OPTION);
|
||||
}
|
||||
return "runner.jar";
|
||||
return this.context.getArchiveFile().getName();
|
||||
}
|
||||
|
||||
private static boolean isType(Entry entry, Type type) {
|
||||
@ -338,11 +378,12 @@ class ExtractCommand extends Command {
|
||||
File resolve(String originalName, String newName) throws IOException;
|
||||
|
||||
/**
|
||||
* Resolves the file for the runner.
|
||||
* @return the file for the runner or {@code null} if the runner should be skipped
|
||||
* Resolves the file for the application.
|
||||
* @return the file for the application or {@code null} if the application should
|
||||
* be skipped
|
||||
* @throws IOException if something went wrong
|
||||
*/
|
||||
File resolveRunner() throws IOException;
|
||||
File resolveApplication() throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@ -350,11 +391,11 @@ class ExtractCommand extends Command {
|
||||
|
||||
private final File directory;
|
||||
|
||||
private final String runnerFilename;
|
||||
private final String applicationFilename;
|
||||
|
||||
private NoLayersFileResolver(File directory, String runnerFilename) {
|
||||
private NoLayersFileResolver(File directory, String applicationFilename) {
|
||||
this.directory = directory;
|
||||
this.runnerFilename = runnerFilename;
|
||||
this.applicationFilename = applicationFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -367,8 +408,8 @@ class ExtractCommand extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File resolveRunner() throws IOException {
|
||||
return resolve(this.runnerFilename, this.runnerFilename);
|
||||
public File resolveApplication() throws IOException {
|
||||
return resolve(this.applicationFilename, this.applicationFilename);
|
||||
}
|
||||
|
||||
}
|
||||
@ -381,13 +422,13 @@ class ExtractCommand extends Command {
|
||||
|
||||
private final File directory;
|
||||
|
||||
private final String runnerFilename;
|
||||
private final String applicationFilename;
|
||||
|
||||
LayersFileResolver(File directory, Layers layers, Set<String> layersToExtract, String runnerFilename) {
|
||||
LayersFileResolver(File directory, Layers layers, Set<String> layersToExtract, String applicationFilename) {
|
||||
this.layers = layers;
|
||||
this.layersToExtract = layersToExtract;
|
||||
this.directory = directory;
|
||||
this.runnerFilename = runnerFilename;
|
||||
this.applicationFilename = applicationFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -410,12 +451,12 @@ class ExtractCommand extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File resolveRunner() throws IOException {
|
||||
public File resolveApplication() throws IOException {
|
||||
String layer = this.layers.getApplicationLayerName();
|
||||
if (shouldExtractLayer(layer)) {
|
||||
File directory = getLayerDirectory(layer);
|
||||
return assertFileIsContainedInDirectory(directory, new File(directory, this.runnerFilename),
|
||||
this.runnerFilename);
|
||||
return assertFileIsContainedInDirectory(directory, new File(directory, this.applicationFilename),
|
||||
this.applicationFilename);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -433,4 +474,12 @@ class ExtractCommand extends Command {
|
||||
|
||||
}
|
||||
|
||||
private static final class AbortException extends RuntimeException {
|
||||
|
||||
AbortException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,11 +58,10 @@ class ExtractLayersCommand extends Command {
|
||||
@Override
|
||||
void run(PrintStream out, Map<Option, String> options, List<String> parameters) {
|
||||
Map<Option, String> rewrittenOptions = new HashMap<>();
|
||||
if (options.containsKey(DESTINATION_OPTION)) {
|
||||
rewrittenOptions.put(ExtractCommand.DESTINATION_OPTION, options.get(DESTINATION_OPTION));
|
||||
}
|
||||
rewrittenOptions.put(ExtractCommand.DESTINATION_OPTION, options.getOrDefault(DESTINATION_OPTION, "."));
|
||||
rewrittenOptions.put(ExtractCommand.LAYERS_OPTION, StringUtils.collectionToCommaDelimitedString(parameters));
|
||||
rewrittenOptions.put(ExtractCommand.LAUNCHER_OPTION, null);
|
||||
rewrittenOptions.put(ExtractCommand.FORCE_OPTION, null);
|
||||
this.delegate.run(out, rewrittenOptions, Collections.emptyList());
|
||||
}
|
||||
|
||||
|
@ -119,46 +119,46 @@ class ExtractCommandTests extends AbstractTests {
|
||||
class Extract {
|
||||
|
||||
@Test
|
||||
void extractLibrariesAndCreatesRunner() throws IOException {
|
||||
void extractLibrariesAndCreatesApplication() throws IOException {
|
||||
run(ExtractCommandTests.this.archive);
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("lib/dependency-1.jar")
|
||||
.contains("lib/dependency-2.jar")
|
||||
.contains("lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("runner.jar")
|
||||
.doesNotContain("org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
assertThat(filenames).contains("test/lib/dependency-1.jar")
|
||||
.contains("test/lib/dependency-2.jar")
|
||||
.contains("test/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("test/test.jar")
|
||||
.doesNotContain("test/org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
}
|
||||
|
||||
@Test
|
||||
void extractLibrariesAndCreatesRunnerInDestination() throws IOException {
|
||||
void extractLibrariesAndCreatesApplicationInDestination() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--destination", file("out").getAbsolutePath());
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("out/lib/dependency-1.jar")
|
||||
.contains("out/lib/dependency-2.jar")
|
||||
.contains("out/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("out/runner.jar");
|
||||
.contains("out/test.jar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void runnerNameAndLibrariesDirectoriesCanBeCustomized() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--runner-filename", "runner-customized.jar", "--libraries",
|
||||
void applicationNameAndLibrariesDirectoriesCanBeCustomized() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--application-filename", "application-customized.jar", "--libraries",
|
||||
"dependencies");
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("dependencies/dependency-1.jar")
|
||||
.contains("dependencies/dependency-2.jar")
|
||||
.contains("dependencies/dependency-3-SNAPSHOT.jar");
|
||||
File runner = file("runner-customized.jar");
|
||||
assertThat(runner).exists();
|
||||
Map<String, String> attributes = getJarManifestAttributes(runner);
|
||||
assertThat(filenames).contains("test/dependencies/dependency-1.jar")
|
||||
.contains("test/dependencies/dependency-2.jar")
|
||||
.contains("test/dependencies/dependency-3-SNAPSHOT.jar");
|
||||
File application = file("test/application-customized.jar");
|
||||
assertThat(application).exists();
|
||||
Map<String, String> attributes = getJarManifestAttributes(application);
|
||||
assertThat(attributes).containsEntry("Class-Path",
|
||||
"dependencies/dependency-1.jar dependencies/dependency-2.jar dependencies/dependency-3-SNAPSHOT.jar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void runnerContainsManifestEntries() throws IOException {
|
||||
void applicationContainsManifestEntries() throws IOException {
|
||||
run(ExtractCommandTests.this.archive);
|
||||
File runner = file("runner.jar");
|
||||
Map<String, String> attributes = getJarManifestAttributes(runner);
|
||||
File application = file("test/test.jar");
|
||||
Map<String, String> attributes = getJarManifestAttributes(application);
|
||||
assertThat(attributes).containsEntry("Main-Class", "org.example.Main")
|
||||
.containsEntry("Class-Path", "lib/dependency-1.jar lib/dependency-2.jar lib/dependency-3-SNAPSHOT.jar")
|
||||
.containsEntry("Some-Attribute", "Some-Value")
|
||||
@ -167,27 +167,27 @@ class ExtractCommandTests extends AbstractTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void runnerContainsApplicationClassesAndResources() throws IOException {
|
||||
void applicationContainsApplicationClassesAndResources() throws IOException {
|
||||
run(ExtractCommandTests.this.archive);
|
||||
File runner = file("runner.jar");
|
||||
List<String> entryNames = getJarEntryNames(runner);
|
||||
File application = file("test/test.jar");
|
||||
List<String> entryNames = getJarEntryNames(application);
|
||||
assertThat(entryNames).contains("application.properties");
|
||||
}
|
||||
|
||||
@Test
|
||||
void appliesFileTimes() {
|
||||
run(ExtractCommandTests.this.archive);
|
||||
assertThat(file("lib/dependency-1.jar")).exists().satisfies(ExtractCommandTests.this::timeAttributes);
|
||||
assertThat(file("lib/dependency-2.jar")).exists().satisfies(ExtractCommandTests.this::timeAttributes);
|
||||
assertThat(file("lib/dependency-3-SNAPSHOT.jar")).exists()
|
||||
assertThat(file("test/lib/dependency-1.jar")).exists().satisfies(ExtractCommandTests.this::timeAttributes);
|
||||
assertThat(file("test/lib/dependency-2.jar")).exists().satisfies(ExtractCommandTests.this::timeAttributes);
|
||||
assertThat(file("test/lib/dependency-3-SNAPSHOT.jar")).exists()
|
||||
.satisfies(ExtractCommandTests.this::timeAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
void runnerDoesntContainLibraries() throws IOException {
|
||||
void applicationDoesntContainLibraries() throws IOException {
|
||||
run(ExtractCommandTests.this.archive);
|
||||
File runner = file("runner.jar");
|
||||
List<String> entryNames = getJarEntryNames(runner);
|
||||
File application = file("test/test.jar");
|
||||
List<String> entryNames = getJarEntryNames(application);
|
||||
assertThat(entryNames).doesNotContain("BOOT-INF/lib/dependency-1.jar", "BOOT-INF/lib/dependency-2.jar");
|
||||
}
|
||||
|
||||
@ -197,7 +197,42 @@ class ExtractCommandTests extends AbstractTests {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
writer.write("text");
|
||||
}
|
||||
assertThatIllegalStateException().isThrownBy(() -> run(file)).withMessageContaining("not compatible");
|
||||
TestPrintStream out = run(file);
|
||||
assertThat(out).contains("is not compatible; ensure jar file is valid and launch script is not enabled");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFailIfDirectoryIsNotEmpty() throws IOException {
|
||||
File destination = file("out");
|
||||
Files.createDirectories(destination.toPath());
|
||||
Files.createFile(new File(destination, "file.txt").toPath());
|
||||
TestPrintStream out = run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath());
|
||||
assertThat(out).contains("already exists and is not empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFailIfDirectoryExistsButIsEmpty() throws IOException {
|
||||
File destination = file("out");
|
||||
Files.createDirectories(destination.toPath());
|
||||
run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath());
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("out/lib/dependency-1.jar")
|
||||
.contains("out/lib/dependency-2.jar")
|
||||
.contains("out/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("out/test.jar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFailIfDirectoryIsNotEmptyButForceIsPassed() throws IOException {
|
||||
File destination = file("out");
|
||||
Files.createDirectories(destination.toPath());
|
||||
Files.createFile(new File(destination, "file.txt").toPath());
|
||||
run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath(), "--force");
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("out/lib/dependency-1.jar")
|
||||
.contains("out/lib/dependency-2.jar")
|
||||
.contains("out/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("out/test.jar");
|
||||
}
|
||||
|
||||
}
|
||||
@ -206,23 +241,23 @@ class ExtractCommandTests extends AbstractTests {
|
||||
class ExtractWithLayers {
|
||||
|
||||
@Test
|
||||
void extractLibrariesAndCreatesRunner() throws IOException {
|
||||
void extractLibrariesAndCreatesApplication() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--layers");
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("dependencies/lib/dependency-1.jar")
|
||||
.contains("dependencies/lib/dependency-2.jar")
|
||||
.contains("snapshot-dependencies/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("application/runner.jar");
|
||||
assertThat(filenames).contains("test/dependencies/lib/dependency-1.jar")
|
||||
.contains("test/dependencies/lib/dependency-2.jar")
|
||||
.contains("test/snapshot-dependencies/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("test/application/test.jar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void extractsOnlySelectedLayers() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--layers", "dependencies");
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("dependencies/lib/dependency-1.jar")
|
||||
.contains("dependencies/lib/dependency-2.jar")
|
||||
.doesNotContain("snapshot-dependencies/lib/dependency-3-SNAPSHOT.jar")
|
||||
.doesNotContain("application/runner.jar");
|
||||
assertThat(filenames).contains("test/dependencies/lib/dependency-1.jar")
|
||||
.contains("test/dependencies/lib/dependency-2.jar")
|
||||
.doesNotContain("test/snapshot-dependencies/lib/dependency-3-SNAPSHOT.jar")
|
||||
.doesNotContain("test/application/test.jar");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -241,14 +276,14 @@ class ExtractCommandTests extends AbstractTests {
|
||||
void extract() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--launcher");
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("META-INF/MANIFEST.MF")
|
||||
.contains("BOOT-INF/classpath.idx")
|
||||
.contains("BOOT-INF/layers.idx")
|
||||
.contains("BOOT-INF/lib/dependency-1.jar")
|
||||
.contains("BOOT-INF/lib/dependency-2.jar")
|
||||
.contains("BOOT-INF/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("BOOT-INF/classes/application.properties")
|
||||
.contains("org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
assertThat(filenames).contains("test/META-INF/MANIFEST.MF")
|
||||
.contains("test/BOOT-INF/classpath.idx")
|
||||
.contains("test/BOOT-INF/layers.idx")
|
||||
.contains("test/BOOT-INF/lib/dependency-1.jar")
|
||||
.contains("test/BOOT-INF/lib/dependency-2.jar")
|
||||
.contains("test/BOOT-INF/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("test/BOOT-INF/classes/application.properties")
|
||||
.contains("test/org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -267,14 +302,14 @@ class ExtractCommandTests extends AbstractTests {
|
||||
void extract() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--launcher", "--layers");
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).contains("application/META-INF/MANIFEST.MF")
|
||||
.contains("application/BOOT-INF/classpath.idx")
|
||||
.contains("application/BOOT-INF/layers.idx")
|
||||
.contains("dependencies/BOOT-INF/lib/dependency-1.jar")
|
||||
.contains("dependencies/BOOT-INF/lib/dependency-2.jar")
|
||||
.contains("snapshot-dependencies/BOOT-INF/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("application/BOOT-INF/classes/application.properties")
|
||||
.contains("spring-boot-loader/org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
assertThat(filenames).contains("test/application/META-INF/MANIFEST.MF")
|
||||
.contains("test/application/BOOT-INF/classpath.idx")
|
||||
.contains("test/application/BOOT-INF/layers.idx")
|
||||
.contains("test/dependencies/BOOT-INF/lib/dependency-1.jar")
|
||||
.contains("test/dependencies/BOOT-INF/lib/dependency-2.jar")
|
||||
.contains("test/snapshot-dependencies/BOOT-INF/lib/dependency-3-SNAPSHOT.jar")
|
||||
.contains("test/application/BOOT-INF/classes/application.properties")
|
||||
.contains("test/spring-boot-loader/org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -288,14 +323,14 @@ class ExtractCommandTests extends AbstractTests {
|
||||
void extractsOnlySelectedLayers() throws IOException {
|
||||
run(ExtractCommandTests.this.archive, "--launcher", "--layers", "dependencies");
|
||||
List<String> filenames = listFilenames();
|
||||
assertThat(filenames).doesNotContain("application/META-INF/MANIFEST.MF")
|
||||
.doesNotContain("application/BOOT-INF/classpath.idx")
|
||||
.doesNotContain("application/BOOT-INF/layers.idx")
|
||||
.contains("dependencies/BOOT-INF/lib/dependency-1.jar")
|
||||
.contains("dependencies/BOOT-INF/lib/dependency-2.jar")
|
||||
.doesNotContain("snapshot-dependencies/BOOT-INF/lib/dependency-3-SNAPSHOT.jar")
|
||||
.doesNotContain("application/BOOT-INF/classes/application.properties")
|
||||
.doesNotContain("spring-boot-loader/org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
assertThat(filenames).doesNotContain("test/application/META-INF/MANIFEST.MF")
|
||||
.doesNotContain("test/application/BOOT-INF/classpath.idx")
|
||||
.doesNotContain("test/application/BOOT-INF/layers.idx")
|
||||
.contains("test/dependencies/BOOT-INF/lib/dependency-1.jar")
|
||||
.contains("test/dependencies/BOOT-INF/lib/dependency-2.jar")
|
||||
.doesNotContain("test/snapshot-dependencies/BOOT-INF/lib/dependency-3-SNAPSHOT.jar")
|
||||
.doesNotContain("test/application/BOOT-INF/classes/application.properties")
|
||||
.doesNotContain("test/spring-boot-loader/org/springframework/boot/loader/launch/JarLauncher.class");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -172,9 +172,10 @@ class ExtractLayersCommandTests {
|
||||
writer.write("text");
|
||||
}
|
||||
given(this.context.getArchiveFile()).willReturn(file);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.command.run(System.out, Collections.emptyMap(), Collections.emptyList()))
|
||||
.withMessageContaining("not compatible");
|
||||
try (TestPrintStream out = new TestPrintStream(this)) {
|
||||
this.command.run(out, Collections.emptyMap(), Collections.emptyList());
|
||||
assertThat(out).contains("is not compatible");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -62,15 +62,25 @@ class TestPrintStream extends PrintStream implements AssertProvider<PrintStreamA
|
||||
|
||||
void hasSameContentAsResource(String resource) {
|
||||
try {
|
||||
InputStream stream = this.actual.testClass.getResourceAsStream(resource);
|
||||
String content = FileCopyUtils.copyToString(new InputStreamReader(stream, StandardCharsets.UTF_8));
|
||||
Assertions.assertThat(this.actual).hasToString(content);
|
||||
try (InputStream stream = this.actual.testClass.getResourceAsStream(resource)) {
|
||||
Assertions.assertThat(stream).as("Resource '%s'", resource).isNotNull();
|
||||
String content = FileCopyUtils.copyToString(new InputStreamReader(stream, StandardCharsets.UTF_8));
|
||||
hasSameContent(content);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
void hasSameContent(String content) {
|
||||
Assertions.assertThat(this.actual).hasToString(content);
|
||||
}
|
||||
|
||||
void contains(String text) {
|
||||
Assertions.assertThat(this.actual.toString()).contains(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,9 @@ Usage:
|
||||
java -Djarmode=tools -jar test.jar extract [options]
|
||||
|
||||
Options:
|
||||
--launcher Whether to extract the Spring Boot launcher
|
||||
--layers string list Layers to extract
|
||||
--destination string Directory to extract files to. Defaults to the current working directory
|
||||
--libraries string Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/
|
||||
--runner-filename string Name of the runner JAR file. Only applicable when not using --launcher. Defaults to runner.jar
|
||||
--launcher Whether to extract the Spring Boot launcher
|
||||
--layers string list Layers to extract
|
||||
--destination string Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)
|
||||
--libraries string Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/
|
||||
--application-filename string Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename
|
||||
--force Whether to ignore non-empty directories, extract anyway
|
||||
|
@ -6,8 +6,9 @@ Usage:
|
||||
java -Djarmode=tools -jar test.jar extract [options]
|
||||
|
||||
Options:
|
||||
--launcher Whether to extract the Spring Boot launcher
|
||||
--layers string list Layers to extract
|
||||
--destination string Directory to extract files to. Defaults to the current working directory
|
||||
--libraries string Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/
|
||||
--runner-filename string Name of the runner JAR file. Only applicable when not using --launcher. Defaults to runner.jar
|
||||
--launcher Whether to extract the Spring Boot launcher
|
||||
--layers string list Layers to extract
|
||||
--destination string Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)
|
||||
--libraries string Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/
|
||||
--application-filename string Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename
|
||||
--force Whether to ignore non-empty directories, extract anyway
|
||||
|
@ -4,8 +4,9 @@ Usage:
|
||||
java -Djarmode=tools -jar test.jar extract [options]
|
||||
|
||||
Options:
|
||||
--launcher Whether to extract the Spring Boot launcher
|
||||
--layers string list Layers to extract
|
||||
--destination string Directory to extract files to. Defaults to the current working directory
|
||||
--libraries string Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/
|
||||
--runner-filename string Name of the runner JAR file. Only applicable when not using --launcher. Defaults to runner.jar
|
||||
--launcher Whether to extract the Spring Boot launcher
|
||||
--layers string list Layers to extract
|
||||
--destination string Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)
|
||||
--libraries string Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/
|
||||
--application-filename string Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename
|
||||
--force Whether to ignore non-empty directories, extract anyway
|
||||
|
Loading…
Reference in New Issue
Block a user