|
|
@ -14,7 +14,7 @@
|
|
|
|
* limitations under the License.
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
package org.springframework.boot.cli.command.jar;
|
|
|
|
package org.springframework.boot.cli.command.archive;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileInputStream;
|
|
|
@ -38,10 +38,12 @@ import org.codehaus.groovy.ast.expr.ConstantExpression;
|
|
|
|
import org.codehaus.groovy.control.SourceUnit;
|
|
|
|
import org.codehaus.groovy.control.SourceUnit;
|
|
|
|
import org.codehaus.groovy.transform.ASTTransformation;
|
|
|
|
import org.codehaus.groovy.transform.ASTTransformation;
|
|
|
|
import org.springframework.boot.cli.app.SpringApplicationLauncher;
|
|
|
|
import org.springframework.boot.cli.app.SpringApplicationLauncher;
|
|
|
|
|
|
|
|
import org.springframework.boot.cli.archive.PackagedSpringApplicationLauncher;
|
|
|
|
import org.springframework.boot.cli.command.Command;
|
|
|
|
import org.springframework.boot.cli.command.Command;
|
|
|
|
import org.springframework.boot.cli.command.OptionParsingCommand;
|
|
|
|
import org.springframework.boot.cli.command.OptionParsingCommand;
|
|
|
|
import org.springframework.boot.cli.command.jar.ResourceMatcher.MatchedResource;
|
|
|
|
import org.springframework.boot.cli.command.archive.ResourceMatcher.MatchedResource;
|
|
|
|
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
|
|
|
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
|
|
|
|
|
|
|
import org.springframework.boot.cli.command.options.OptionHandler;
|
|
|
|
import org.springframework.boot.cli.command.options.OptionSetGroovyCompilerConfiguration;
|
|
|
|
import org.springframework.boot.cli.command.options.OptionSetGroovyCompilerConfiguration;
|
|
|
|
import org.springframework.boot.cli.command.options.SourceOptions;
|
|
|
|
import org.springframework.boot.cli.command.options.SourceOptions;
|
|
|
|
import org.springframework.boot.cli.command.status.ExitStatus;
|
|
|
|
import org.springframework.boot.cli.command.status.ExitStatus;
|
|
|
@ -49,8 +51,8 @@ import org.springframework.boot.cli.compiler.GroovyCompiler;
|
|
|
|
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
|
|
|
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
|
|
|
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
|
|
|
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
|
|
|
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
|
|
|
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
|
|
|
import org.springframework.boot.cli.jar.PackagedSpringApplicationLauncher;
|
|
|
|
|
|
|
|
import org.springframework.boot.loader.tools.JarWriter;
|
|
|
|
import org.springframework.boot.loader.tools.JarWriter;
|
|
|
|
|
|
|
|
import org.springframework.boot.loader.tools.Layout;
|
|
|
|
import org.springframework.boot.loader.tools.Libraries;
|
|
|
|
import org.springframework.boot.loader.tools.Libraries;
|
|
|
|
import org.springframework.boot.loader.tools.Library;
|
|
|
|
import org.springframework.boot.loader.tools.Library;
|
|
|
|
import org.springframework.boot.loader.tools.LibraryCallback;
|
|
|
|
import org.springframework.boot.loader.tools.LibraryCallback;
|
|
|
@ -65,51 +67,66 @@ import joptsimple.OptionSet;
|
|
|
|
import joptsimple.OptionSpec;
|
|
|
|
import joptsimple.OptionSpec;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* {@link Command} to create a self-contained executable jar file from a CLI application.
|
|
|
|
* Abstract {@link Command} to create a self-contained executable archive file from a CLI
|
|
|
|
|
|
|
|
* application.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @author Andy Wilkinson
|
|
|
|
* @author Andy Wilkinson
|
|
|
|
* @author Phillip Webb
|
|
|
|
* @author Phillip Webb
|
|
|
|
|
|
|
|
* @author Andrey Stolyarov
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public class JarCommand extends OptionParsingCommand {
|
|
|
|
abstract class ArchiveCommand extends OptionParsingCommand {
|
|
|
|
|
|
|
|
|
|
|
|
public JarCommand() {
|
|
|
|
protected ArchiveCommand(String name, String description,
|
|
|
|
super("jar",
|
|
|
|
OptionHandler optionHandler) {
|
|
|
|
"Create a self-contained "
|
|
|
|
super(name, description, optionHandler);
|
|
|
|
+ "executable jar file from a Spring Groovy script",
|
|
|
|
|
|
|
|
new JarOptionHandler());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public String getUsageHelp() {
|
|
|
|
public String getUsageHelp() {
|
|
|
|
return "[options] <jar-name> <files>";
|
|
|
|
return "[options] <" + getName() + "-name> <files>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static final class JarOptionHandler extends CompilerOptionHandler {
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Abstract base {@link CompilerOptionHandler} for archive commands.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected abstract static class ArchiveOptionHandler extends CompilerOptionHandler {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final String type;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Layout layout;
|
|
|
|
|
|
|
|
|
|
|
|
private OptionSpec<String> includeOption;
|
|
|
|
private OptionSpec<String> includeOption;
|
|
|
|
|
|
|
|
|
|
|
|
private OptionSpec<String> excludeOption;
|
|
|
|
private OptionSpec<String> excludeOption;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ArchiveOptionHandler(String type, Layout layout) {
|
|
|
|
|
|
|
|
this.type = type;
|
|
|
|
|
|
|
|
this.layout = layout;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
protected void doOptions() {
|
|
|
|
protected void doOptions() {
|
|
|
|
this.includeOption = option("include",
|
|
|
|
this.includeOption = option("include",
|
|
|
|
"Pattern applied to directories on the classpath to find files to include in the resulting jar")
|
|
|
|
"Pattern applied to directories on the classpath to find files to "
|
|
|
|
.withRequiredArg().withValuesSeparatedBy(",").defaultsTo("");
|
|
|
|
+ "include in the resulting ").withRequiredArg()
|
|
|
|
|
|
|
|
.withValuesSeparatedBy(",").defaultsTo("");
|
|
|
|
this.excludeOption = option("exclude",
|
|
|
|
this.excludeOption = option("exclude",
|
|
|
|
"Pattern applied to directories on the classpath to find files to exclude from the resulting jar")
|
|
|
|
"Pattern applied to directories on the classpath to find files to "
|
|
|
|
.withRequiredArg().withValuesSeparatedBy(",").defaultsTo("");
|
|
|
|
+ "exclude from the resulting " + this.type).withRequiredArg()
|
|
|
|
|
|
|
|
.withValuesSeparatedBy(",").defaultsTo("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
protected ExitStatus run(OptionSet options) throws Exception {
|
|
|
|
protected ExitStatus run(OptionSet options) throws Exception {
|
|
|
|
List<?> nonOptionArguments = new ArrayList<Object>(
|
|
|
|
List<?> nonOptionArguments = new ArrayList<Object>(
|
|
|
|
options.nonOptionArguments());
|
|
|
|
options.nonOptionArguments());
|
|
|
|
Assert.isTrue(nonOptionArguments.size() >= 2,
|
|
|
|
Assert.isTrue(nonOptionArguments.size() >= 2, "The name of the resulting "
|
|
|
|
"The name of the resulting jar and at least one source file must be specified");
|
|
|
|
+ this.type + " and at least one source file must be specified");
|
|
|
|
|
|
|
|
|
|
|
|
File output = new File((String) nonOptionArguments.remove(0));
|
|
|
|
File output = new File((String) nonOptionArguments.remove(0));
|
|
|
|
Assert.isTrue(output.getName().toLowerCase().endsWith(".jar"),
|
|
|
|
Assert.isTrue(output.getName().toLowerCase().endsWith("." + this.type),
|
|
|
|
"The output '" + output + "' is not a JAR file.");
|
|
|
|
"The output '" + output + "' is not a " + this.type.toUpperCase()
|
|
|
|
|
|
|
|
+ " file.");
|
|
|
|
deleteIfExists(output);
|
|
|
|
deleteIfExists(output);
|
|
|
|
|
|
|
|
|
|
|
|
GroovyCompiler compiler = createCompiler(options);
|
|
|
|
GroovyCompiler compiler = createCompiler(options);
|
|
|
@ -196,7 +213,7 @@ public class JarCommand extends OptionParsingCommand {
|
|
|
|
List<Library> libraries = new ArrayList<Library>();
|
|
|
|
List<Library> libraries = new ArrayList<Library>();
|
|
|
|
for (URL dependency : dependencies) {
|
|
|
|
for (URL dependency : dependencies) {
|
|
|
|
File file = new File(dependency.toURI());
|
|
|
|
File file = new File(dependency.toURI());
|
|
|
|
libraries.add(new Library(file, LibraryScope.COMPILE));
|
|
|
|
libraries.add(new Library(file, getLibraryScope(file)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return libraries;
|
|
|
|
return libraries;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -220,7 +237,7 @@ public class JarCommand extends OptionParsingCommand {
|
|
|
|
return builder.toString();
|
|
|
|
return builder.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void addCliClasses(JarWriter writer) throws IOException {
|
|
|
|
protected void addCliClasses(JarWriter writer) throws IOException {
|
|
|
|
addClass(writer, PackagedSpringApplicationLauncher.class);
|
|
|
|
addClass(writer, PackagedSpringApplicationLauncher.class);
|
|
|
|
addClass(writer, SpringApplicationLauncher.class);
|
|
|
|
addClass(writer, SpringApplicationLauncher.class);
|
|
|
|
Resource[] resources = new PathMatchingResourcePatternResolver()
|
|
|
|
Resource[] resources = new PathMatchingResourcePatternResolver()
|
|
|
@ -232,10 +249,19 @@ public class JarCommand extends OptionParsingCommand {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void addClass(JarWriter writer, Class<?> sourceClass) throws IOException {
|
|
|
|
protected final void addClass(JarWriter writer, Class<?> sourceClass)
|
|
|
|
String name = sourceClass.getName().replace(".", "/") + ".class";
|
|
|
|
throws IOException {
|
|
|
|
InputStream stream = sourceClass.getResourceAsStream("/" + name);
|
|
|
|
addClass(writer, sourceClass.getClassLoader(), sourceClass.getName());
|
|
|
|
writer.writeEntry(name, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected final void addClass(JarWriter writer, ClassLoader classLoader,
|
|
|
|
|
|
|
|
String sourceClass) throws IOException {
|
|
|
|
|
|
|
|
if (classLoader == null) {
|
|
|
|
|
|
|
|
classLoader = Thread.currentThread().getContextClassLoader();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
String name = sourceClass.replace(".", "/") + ".class";
|
|
|
|
|
|
|
|
InputStream stream = classLoader.getResourceAsStream(name);
|
|
|
|
|
|
|
|
writer.writeEntry(this.layout.getClassesLocation() + name, stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void addResource(JarWriter writer, Resource resource, String name)
|
|
|
|
private void addResource(JarWriter writer, Resource resource, String name)
|
|
|
@ -259,6 +285,8 @@ public class JarCommand extends OptionParsingCommand {
|
|
|
|
return libraries;
|
|
|
|
return libraries;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected abstract LibraryScope getLibraryScope(File file);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|