Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: scripts can now implement integrations #1634

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions itests/integration.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Feature: integration

Scenario: integration success
* command('jbang integration/inttest.java')
* match err !contains 'Integration... (out)'
* match err contains 'Integration... (err)'
* match out contains "Integration test"

Scenario: integration success, verbose
* command('jbang --verbose integration/inttest.java')
* match err contains 'Integration... (out)'
* match err contains 'Integration... (err)'
* match out contains "Integration test"

Scenario: integration failure
* command('jbang -Dfailintegration=1 integration/inttest.java')
* match err !contains 'Integration... (out)'
* match err contains 'Integration... (err)'
* match err contains 'Issue running postBuild()'
* match err !contains 'Failing integration...'
* match exit == 1

Scenario: integration failure, verbose
* command('jbang -Dfailintegration=1 --verbose integration/inttest.java')
* match err contains 'Integration... (out)'
* match err contains 'Integration... (err)'
* match err contains 'Issue running postBuild()'
* match err contains 'Failing integration...'
* match exit == 1
23 changes: 23 additions & 0 deletions itests/integration/IntegrationTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class IntegrationTest {
public static Map<String, Object> postBuild(Path temporaryJar,
Path pomFile,
List<Map.Entry<String, String>> repositories,
List<Map.Entry<String, Path>> dependencies,
List<String> comments,
boolean nativeImage) {
System.out.println("Integration... (out)");
System.err.println("Integration... (err)");
if (System.getProperty("failintegration") != null) {
throw new RuntimeException("Failing integration...");
} else {
System.out.println("Integration OK (out)");
System.err.println("Integration OK (err)");
return Collections.emptyMap();
}
}
}
9 changes: 9 additions & 0 deletions itests/integration/inttest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

//SOURCES IntegrationTest.java
//FILES META-INF/jbang-integration.list=jb-int.list

class inttest {
public static void main(String... args) {
System.out.println("Integration test");
}
}
1 change: 1 addition & 0 deletions itests/integration/jb-int.list
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
IntegrationTest
4 changes: 3 additions & 1 deletion src/main/java/dev/jbang/spi/IntegrationInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ public class IntegrationInput {
public final List<String> comments;
@SerializedName(value = "native")
public final boolean nativeRequested;
public final boolean verbose;

public IntegrationInput(String integrationClassName, Path source, Path classes, Path pom,
Map<String, String> repositories, Map<String, Path> dependencies, List<String> comments,
boolean nativeRequested) {
boolean nativeRequested, boolean verbose) {
this.integrationClassName = integrationClassName;
this.source = source;
this.classes = classes;
Expand All @@ -29,5 +30,6 @@ public IntegrationInput(String integrationClassName, Path source, Path classes,
this.dependencies = dependencies;
this.comments = comments;
this.nativeRequested = nativeRequested;
this.verbose = verbose;
}
}
31 changes: 24 additions & 7 deletions src/main/java/dev/jbang/spi/IntegrationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
Expand All @@ -25,6 +26,7 @@
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Nonnull;

Expand Down Expand Up @@ -78,7 +80,7 @@ public static IntegrationResult runIntegrations(Project prj, Path tmpJarDir, Pat
ClassLoader old = Thread.currentThread().getContextClassLoader();
PrintStream oldout = System.out;
try {
URLClassLoader integrationCl = getClassLoader(deps.values());
URLClassLoader integrationCl = getClassLoader(tmpJarDir, deps.values());
Thread.currentThread().setContextClassLoader(integrationCl);
String requestedJavaVersion = prj.getJavaVersion();
Set<String> classNames = loadIntegrationClassNames(integrationCl);
Expand All @@ -87,8 +89,7 @@ public static IntegrationResult runIntegrations(Project prj, Path tmpJarDir, Pat
? source.getResourceRef().getFile().toAbsolutePath()
: null;
IntegrationInput input = new IntegrationInput(className, srcPath, tmpJarDir, pomPath, repos, deps,
comments,
prj.isNativeImage());
comments, prj.isNativeImage(), Util.isVerbose());
IntegrationResult ir = requestedJavaVersion == null || JavaUtil.satisfiesRequestedVersion(
requestedJavaVersion, JavaUtil.getCurrentMajorJavaVersion())
? runIntegrationEmbedded(input, integrationCl)
Expand All @@ -112,8 +113,9 @@ public static IntegrationResult runIntegrations(Project prj, Path tmpJarDir, Pat
}

@Nonnull
private static URLClassLoader getClassLoader(Collection<Path> deps) {
URL[] urls = deps.stream().map(path -> {
private static URLClassLoader getClassLoader(Path classes, Collection<Path> deps) {
Stream<Path> paths = Stream.concat(Stream.of(classes), deps.stream());
URL[] urls = paths.map(path -> {
try {
return path.toUri().toURL();
} catch (MalformedURLException e) {
Expand Down Expand Up @@ -221,8 +223,19 @@ private static IntegrationResult runIntegrationExternal(IntegrationInput input,
for (Map.Entry<String, String> entry : properties.entrySet()) {
args.add("-D" + entry.getKey() + "=" + entry.getValue());
}

Path jbangJar = Util.getJarLocation();
args.add("-cp");
args.add(Util.getJarLocation().toString());
if (jbangJar.toString().endsWith(".jar")) {
args.add(jbangJar.toString());
} else {
// We will assume that we're running inside an IDE or
// some kind of test environment and need to manually
// add the Gson dependency
Path gsonJar = Util.getJarLocation(Gson.class);
args.add(jbangJar + File.pathSeparator + gsonJar);
}

args.add("dev.jbang.spi.IntegrationManager");

if (Util.isVerbose()) {
Expand Down Expand Up @@ -267,10 +280,11 @@ public static void main(String... args) {
IntegrationInput input = parser.fromJson(new InputStreamReader(System.in), IntegrationInput.class);
ClassLoader old = Thread.currentThread().getContextClassLoader();
PrintStream oldout = System.out;
Util.setVerbose(input.verbose);
String output = "";
boolean ok = false;
try {
URLClassLoader integrationCl = getClassLoader(input.dependencies.values());
URLClassLoader integrationCl = getClassLoader(input.classes, input.dependencies.values());
Thread.currentThread().setContextClassLoader(integrationCl);
IntegrationResult result = runIntegrationEmbedded(input, integrationCl);
output = parser.toJson(result);
Expand All @@ -281,6 +295,9 @@ public static void main(String... args) {
output = "Integration class missing method with signature public static Map<String, byte[]> postBuild(Path classesDir, Path pomFile, List<Map.Entry<String, Path>> dependencies)";
} catch (Exception e) {
output = "Issue running postBuild()";
if (input.verbose) {
e.printStackTrace(System.err);
}
} finally {
Thread.currentThread().setContextClassLoader(old);
System.setOut(oldout);
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/dev/jbang/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -1689,8 +1689,17 @@ public static boolean runningManagedJBang() {
* @return An actual Path if it was found, or an empty path if it was not
*/
public static Path getJarLocation() {
return getJarLocation(VersionChecker.class);
}

/**
* Determines the path to the JAR that contains the given class
*
* @return An actual Path if it was found, or an empty path if it was not
*/
public static Path getJarLocation(Class<?> klazz) {
try {
File jarFile = new File(VersionChecker.class.getProtectionDomain().getCodeSource().getLocation().toURI());
File jarFile = new File(klazz.getProtectionDomain().getCodeSource().getLocation().toURI());
return jarFile.toPath();
} catch (URISyntaxException e) {
// ignore
Expand Down
3 changes: 1 addition & 2 deletions src/test/java/dev/jbang/cli/TestJdk.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import java.nio.file.Path;
import java.util.Arrays;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -442,14 +441,14 @@ private void createMockJdk(int jdkVersion, BiConsumer<Path, String> init) {
}
}


private void initMockJdkDirRuntime(Path jdkPath, String version) {
initMockJdkDir(jdkPath, version, "JAVA_RUNTIME_VERSION");
}

private void initMockJdkDir(Path jdkPath, String version) {
initMockJdkDir(jdkPath, version, "JAVA_VERSION");
}

private void initMockJdkDir(Path jdkPath, String version, String key) {
Util.mkdirs(jdkPath);
String rawJavaVersion = key + "=\"" + version + "\"";
Expand Down