Skip to content

Commit

Permalink
Better native export handing and native Window fix (#1406)
Browse files Browse the repository at this point in the history
  • Loading branch information
quintesse authored Aug 1, 2022
1 parent d6bf941 commit 074eb53
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 126 deletions.
6 changes: 5 additions & 1 deletion src/main/java/dev/jbang/cli/BaseBuildCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public abstract class BaseBuildCommand extends BaseCommand {
@CommandLine.Mixin
BuildMixin buildMixin;

@CommandLine.Option(names = {
"-n", "--native" }, description = "Build using native-image")
boolean nativeImage;

@CommandLine.Mixin
DependencyInfoMixin dependencyInfoMixin;

Expand All @@ -33,7 +37,7 @@ RunContext getRunContext() {
ctx.setCatalog(scriptMixin.catalog);
ctx.setJavaVersion(buildMixin.javaVersion);
ctx.setMainClass(buildMixin.main);
ctx.setNativeImage(buildMixin.nativeImage);
ctx.setNativeImage(nativeImage);
return ctx;
}
}
4 changes: 0 additions & 4 deletions src/main/java/dev/jbang/cli/BuildMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,4 @@ void setJavaVersion(String javaVersion) {
@CommandLine.Option(names = { "-m",
"--main" }, description = "Main class to use when running. Used primarily for running jar's.")
String main;

@CommandLine.Option(names = {
"-n", "--native" }, description = "Build using native-image")
boolean nativeImage;
}
206 changes: 97 additions & 109 deletions src/main/java/dev/jbang/cli/Export.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dev.jbang.cli;

import static dev.jbang.cli.Export.handle;
import static dev.jbang.source.builders.BaseBuilder.getImageName;
import static dev.jbang.util.JavaUtil.resolveInJavaHome;

Expand Down Expand Up @@ -29,40 +28,14 @@
import picocli.CommandLine.Command;

@Command(name = "export", description = "Export the result of a build.", subcommands = { ExportPortable.class,
ExportLocal.class, ExportMavenPublish.class })
ExportLocal.class, ExportMavenPublish.class, ExportNative.class })
public class Export {

static int handle(ExportMixin exportMixin,
Exporter style) throws IOException {
exportMixin.scriptMixin.validate();

RunContext ctx = getRunContext(exportMixin);
Code code = ctx.forResource(exportMixin.scriptMixin.scriptOrFile).builder(ctx).build();
return style.apply(exportMixin, code, ctx);
}

static RunContext getRunContext(ExportMixin exportMixin) {
RunContext ctx = new RunContext();
ctx.setProperties(exportMixin.dependencyInfoMixin.getProperties());
ctx.setAdditionalDependencies(exportMixin.dependencyInfoMixin.getDependencies());
ctx.setAdditionalRepositories(exportMixin.dependencyInfoMixin.getRepositories());
ctx.setAdditionalClasspaths(exportMixin.dependencyInfoMixin.getClasspaths());
ctx.setAdditionalSources(exportMixin.scriptMixin.sources);
ctx.setAdditionalResources(exportMixin.scriptMixin.resources);
ctx.setForceType(exportMixin.scriptMixin.forceType);
ctx.setCatalog(exportMixin.scriptMixin.catalog);
ctx.setJavaVersion(exportMixin.buildMixin.javaVersion);
ctx.setMainClass(exportMixin.buildMixin.main);
ctx.setNativeImage(exportMixin.buildMixin.nativeImage);
return ctx;
}
}

interface Exporter {
int apply(ExportMixin exportMixin, Code code, RunContext ctx) throws IOException;
}
abstract class BaseExportCommand extends BaseCommand {

abstract class BaseExporter extends BaseCommand implements Exporter {
@CommandLine.Mixin
ExportMixin exportMixin;

protected void updateJarManifest(Path jar, Path manifest, String javaVersion) throws IOException {
List<String> optionList = new ArrayList<>();
Expand Down Expand Up @@ -99,23 +72,41 @@ protected Path createManifest(String newPath) throws IOException {
}
return tempManifest;
}
}

@Command(name = "local", description = "Exports jar with classpath referring to local machine dependent locations")
class ExportLocal extends BaseExporter {
@Override
public Integer doCall() throws IOException {
exportMixin.scriptMixin.validate();
RunContext ctx = getRunContext(exportMixin);
Code code = ctx.forResource(exportMixin.scriptMixin.scriptOrFile).builder(ctx).build();
return apply(code, ctx);
}

@CommandLine.Mixin
ExportMixin exportMixin;
abstract int apply(Code code, RunContext ctx) throws IOException;

public int apply(ExportMixin exportMixin, Code code, RunContext ctx) throws IOException {
protected RunContext getRunContext(ExportMixin exportMixin) {
RunContext ctx = new RunContext();
ctx.setProperties(exportMixin.dependencyInfoMixin.getProperties());
ctx.setAdditionalDependencies(exportMixin.dependencyInfoMixin.getDependencies());
ctx.setAdditionalRepositories(exportMixin.dependencyInfoMixin.getRepositories());
ctx.setAdditionalClasspaths(exportMixin.dependencyInfoMixin.getClasspaths());
ctx.setAdditionalSources(exportMixin.scriptMixin.sources);
ctx.setAdditionalResources(exportMixin.scriptMixin.resources);
ctx.setForceType(exportMixin.scriptMixin.forceType);
ctx.setCatalog(exportMixin.scriptMixin.catalog);
ctx.setJavaVersion(exportMixin.buildMixin.javaVersion);
ctx.setMainClass(exportMixin.buildMixin.main);
return ctx;
}
}

Path outputPath = exportMixin.getFileOutputPath();
// Copy the JAR or native binary
Path source = code.getJarFile();
if (exportMixin.buildMixin.nativeImage) {
source = getImageName(source);
}
@Command(name = "local", description = "Exports jar with classpath referring to local machine dependent locations")
class ExportLocal extends BaseExportCommand {

@Override
int apply(Code code, RunContext ctx) throws IOException {
// Copy the JAR
Path source = code.getJarFile();
Path outputPath = exportMixin.getJarOutputPath();
if (outputPath.toFile().exists()) {
if (exportMixin.force) {
outputPath.toFile().delete();
Expand All @@ -124,51 +115,35 @@ public int apply(ExportMixin exportMixin, Code code, RunContext ctx) throws IOEx
return EXIT_INVALID_INPUT;
}
}

Files.copy(source, outputPath);

if (!exportMixin.buildMixin.nativeImage) {
// Update the JAR's MANIFEST.MF Class-Path to point to
// its dependencies
String newPath = ctx.resolveClassPath(code).getManifestPath();
if (!newPath.isEmpty()) {
Path tempManifest = createManifest(newPath);

String javaVersion = exportMixin.buildMixin.javaVersion != null
? exportMixin.buildMixin.javaVersion
: code.getJavaVersion();
updateJarManifest(outputPath, tempManifest, javaVersion);
}
// Update the JAR's MANIFEST.MF Class-Path to point to
// its dependencies
String newPath = ctx.resolveClassPath(code).getManifestPath();
if (!newPath.isEmpty()) {
Path tempManifest = createManifest(newPath);

String javaVersion = exportMixin.buildMixin.javaVersion != null
? exportMixin.buildMixin.javaVersion
: code.getJavaVersion();
updateJarManifest(outputPath, tempManifest, javaVersion);
}

Util.infoMsg("Exported to " + outputPath);
return EXIT_OK;
}

@Override
public Integer doCall() throws IOException {
return handle(exportMixin, this);
}
}

@Command(name = "portable", description = "Exports jar together with dependencies in way that makes it portable")
class ExportPortable extends BaseExporter {
class ExportPortable extends BaseExportCommand {

public static final String LIB = "lib";

@CommandLine.Mixin
ExportMixin exportMixin;

public int apply(ExportMixin exportMixin, Code code, RunContext ctx) throws IOException {

Path outputPath = exportMixin.getFileOutputPath();

// Copy the JAR or native binary
@Override
int apply(Code code, RunContext ctx) throws IOException {
// Copy the JAR
Path source = code.getJarFile();
if (exportMixin.buildMixin.nativeImage) {
source = getImageName(source);
}

Path outputPath = exportMixin.getJarOutputPath();
if (outputPath.toFile().exists()) {
if (exportMixin.force) {
outputPath.toFile().delete();
Expand All @@ -179,41 +154,31 @@ public int apply(ExportMixin exportMixin, Code code, RunContext ctx) throws IOEx
}

Files.copy(source, outputPath);
if (!exportMixin.buildMixin.nativeImage) {
List<ArtifactInfo> deps = ctx.resolveClassPath(code).getArtifacts();
if (!deps.isEmpty()) {
// Copy dependencies to "./lib" dir
Path libDir = outputPath.getParent().resolve(LIB);
Util.mkdirs(libDir);
StringBuilder newPath = new StringBuilder();
for (ArtifactInfo dep : deps) {
Files.copy(dep.getFile(), libDir.resolve(dep.getFile().getFileName()));
newPath.append(" " + LIB + "/" + dep.getFile().getFileName());
}

Path tempManifest = createManifest(newPath.toString());

String javaVersion = exportMixin.buildMixin.javaVersion != null
? exportMixin.buildMixin.javaVersion
: code.getJavaVersion();
updateJarManifest(outputPath, tempManifest, javaVersion);
List<ArtifactInfo> deps = ctx.resolveClassPath(code).getArtifacts();
if (!deps.isEmpty()) {
// Copy dependencies to "./lib" dir
Path libDir = outputPath.getParent().resolve(LIB);
Util.mkdirs(libDir);
StringBuilder newPath = new StringBuilder();
for (ArtifactInfo dep : deps) {
Files.copy(dep.getFile(), libDir.resolve(dep.getFile().getFileName()));
newPath.append(" " + LIB + "/" + dep.getFile().getFileName());
}

Path tempManifest = createManifest(newPath.toString());

String javaVersion = exportMixin.buildMixin.javaVersion != null
? exportMixin.buildMixin.javaVersion
: code.getJavaVersion();
updateJarManifest(outputPath, tempManifest, javaVersion);
}
Util.infoMsg("Exported to " + outputPath);
return EXIT_OK;
}

@Override
public Integer doCall() throws IOException {
return handle(exportMixin, this);
}
}

@Command(name = "mavenrepo", description = "Exports directory that can be used to publish as a maven repository")
class ExportMavenPublish extends BaseExporter {

@CommandLine.Mixin
ExportMixin exportMixin;
class ExportMavenPublish extends BaseExportCommand {

@CommandLine.Option(names = { "--group", "-g" }, description = "The group ID to use for the generated POM.")
String group;
Expand All @@ -224,17 +189,15 @@ class ExportMavenPublish extends BaseExporter {
@CommandLine.Option(names = { "--version", "-v" }, description = "The version to use for the generated POM.")
String version;

public int apply(ExportMixin exportMixin, Code code, RunContext ctx) throws IOException {
@Override
int apply(Code code, RunContext ctx) throws IOException {
Path outputPath = exportMixin.outputFile;

if (outputPath == null) {
outputPath = Settings.getLocalMavenRepo();
}
// Copy the JAR or native binary
// Copy the JAR
Path source = code.getJarFile();
if (exportMixin.buildMixin.nativeImage) {
source = getImageName(source);
}

if (!outputPath.toFile().isDirectory()) {
if (outputPath.toFile().exists()) {
Expand Down Expand Up @@ -322,9 +285,34 @@ public int apply(ExportMixin exportMixin, Code code, RunContext ctx) throws IOEx
Util.infoMsg("Exported to " + outputPath);
return EXIT_OK;
}
}

@Command(name = "native", description = "Exports native executable")
class ExportNative extends BaseExportCommand {

@Override
public Integer doCall() throws IOException {
return handle(exportMixin, this);
int apply(Code code, RunContext ctx) throws IOException {
// Copy the native binary
Path source = getImageName(code.getJarFile());
Path outputPath = exportMixin.getNativeOutputPath();
if (outputPath.toFile().exists()) {
if (exportMixin.force) {
outputPath.toFile().delete();
} else {
Util.warnMsg("Cannot export as " + outputPath + " already exists. Use --force to overwrite.");
return EXIT_INVALID_INPUT;
}
}
Files.copy(source, outputPath);

Util.infoMsg("Exported to " + outputPath);
return EXIT_OK;
}

@Override
protected RunContext getRunContext(ExportMixin exportMixin) {
RunContext ctx = super.getRunContext(exportMixin);
ctx.setNativeImage(true);
return ctx;
}
}
}
27 changes: 19 additions & 8 deletions src/main/java/dev/jbang/cli/ExportMixin.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package dev.jbang.cli;

import static dev.jbang.source.builders.BaseBuilder.getImageName;

import java.nio.file.Path;
import java.nio.file.Paths;

Expand Down Expand Up @@ -32,19 +30,32 @@ public class ExportMixin {
public ExportMixin() {
}

Path getFileOutputPath() {
Path getJarOutputPath() {
Path outputPath = getOutputPath();
// Ensure the file ends in `.jar`
if (!outputPath.toString().endsWith(".jar")) {
outputPath = Paths.get(outputPath + ".jar");
}
return outputPath;
}

Path getNativeOutputPath() {
Path outputPath = getOutputPath();
// Ensure that on Windows the file ends in `.exe`
if (Util.isWindows() && !outputPath.toString().endsWith(".exe")) {
outputPath = Paths.get(outputPath + ".exe");
}
return outputPath;
}

private Path getOutputPath() {
// Determine the output file location and name
Path cwd = Util.getCwd();
Path outputPath;
if (outputFile != null) {
outputPath = outputFile;
} else {
String outName = CatalogUtil.nameFromRef(scriptMixin.scriptOrFile);
if (buildMixin.nativeImage) {
outName = getImageName(Paths.get(outName)).getFileName().toString();
} else {
outName += ".jar";
}
outputPath = Paths.get(outName);
}
outputPath = cwd.resolve(outputPath);
Expand Down
Loading

0 comments on commit 074eb53

Please sign in to comment.