diff --git a/itests/extending/Bar.java b/itests/extending/Bar.java new file mode 100644 index 000000000..646cb496d --- /dev/null +++ b/itests/extending/Bar.java @@ -0,0 +1,3 @@ +package extending; + +public class Bar {} \ No newline at end of file diff --git a/itests/extending/Foo.java b/itests/extending/Foo.java new file mode 100644 index 000000000..0779b49a0 --- /dev/null +++ b/itests/extending/Foo.java @@ -0,0 +1,10 @@ +///usr/bin/env jbang "$0" "$@" ; exit $? +///DEPS com.github.lalyos:jfiglet:0.0.9 + +package extending; + +public class Foo extends Bar { + public static void main(String... args) { + System.out.println("hello JBang"); + } +} diff --git a/itests/test_suite.sh b/itests/test_suite.sh index 84253ffb5..957811dd9 100755 --- a/itests/test_suite.sh +++ b/itests/test_suite.sh @@ -47,7 +47,7 @@ assert_stderr(){ export NL=$'\n' echo "Cleaning JBANG_CACHE" -rm -rf ~/.jbang/cache +rm -rf ~/.jbang/cache/{jars,urls,scripts,stdins} echo Testing with `which jbang` @@ -61,6 +61,12 @@ assert_raises "rm $SCRATCH/test.java" 0 assert "jbang helloworld.java jbangtest" "Hello jbangtest" +echo "JAVA::::" +java -version +echo $JAVA_HOME +which java +which jshell + java -version 2>&1 >/dev/null| grep version | grep "1.8" >/dev/null JAVA8=$? diff --git a/src/main/java/dev/jbang/dependencies/ModularClassPath.java b/src/main/java/dev/jbang/dependencies/ModularClassPath.java index 32d6fecc0..580d14af4 100644 --- a/src/main/java/dev/jbang/dependencies/ModularClassPath.java +++ b/src/main/java/dev/jbang/dependencies/ModularClassPath.java @@ -50,12 +50,16 @@ public List getClassPaths() { public String getClassPath() { if (classPath == null) { - classPath = String.join(CP_SEPARATOR, getClassPaths()); + classPath = toClassPath(getClassPaths()); } return classPath; } + public static String toClassPath(List pathElements) { + return String.join(CP_SEPARATOR, pathElements); + } + public String getManifestPath() { if (manifestPath == null) { manifestPath = artifacts.stream() diff --git a/src/main/java/dev/jbang/source/ResourceRef.java b/src/main/java/dev/jbang/source/ResourceRef.java index 130698df6..fe830a186 100644 --- a/src/main/java/dev/jbang/source/ResourceRef.java +++ b/src/main/java/dev/jbang/source/ResourceRef.java @@ -35,6 +35,10 @@ public boolean isStdin() { return originalResource != null && isStdin(originalResource); } + public boolean isFile() { + return originalResource != null && Util.isValidPath(originalResource); + } + @Nullable public Path getFile() { return file; diff --git a/src/main/java/dev/jbang/source/Source.java b/src/main/java/dev/jbang/source/Source.java index 11afc377a..69909cc17 100644 --- a/src/main/java/dev/jbang/source/Source.java +++ b/src/main/java/dev/jbang/source/Source.java @@ -1,6 +1,8 @@ package dev.jbang.source; +import java.nio.file.Path; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -8,6 +10,7 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import dev.jbang.cli.BaseCommand; import dev.jbang.cli.ExitException; @@ -87,6 +90,29 @@ public ResourceRef getResourceRef() { return resourceRef; } + @Nullable + public ResourceRef getSourceDirRef() { + if (contents != null && resourceRef.isFile()) { + Path parent = getResourceRef().getFile().getParent(); + Optional pkg = getJavaPackage(); + if (pkg.isPresent()) { + String[] elems = pkg.get().split("\\."); + Collections.reverse(Arrays.asList(elems)); + for (String elem : elems) { + if (parent != null && !elem.equals(parent.getFileName().toString())) { + // if path doesn't match package we return null + return null; + } + parent = parent.getParent(); + } + } + return ResourceRef.forFile(parent); + } else { + // If the resource isn't a local file we return null + return null; + } + } + public Optional getJavaPackage() { if (contents != null) { return Util.getSourcePackage(contents); @@ -145,6 +171,10 @@ public Project updateProject(Project prj, ResourceResolver resolver) { if (!prj.getMainSourceSet().getSources().contains(getResourceRef())) { SourceSet ss = prj.getMainSourceSet(); ss.addSource(this.getResourceRef()); + ResourceRef srcDir = getSourceDirRef(); + if (srcDir != null) { + ss.addSourceDir(srcDir); + } ss.addResources(tagReader.collectFiles(resourceRef, new SiblingResourceResolver(resourceRef, ResourceResolver.forResources()))); ss.addDependencies(collectDependencies()); diff --git a/src/main/java/dev/jbang/source/SourceSet.java b/src/main/java/dev/jbang/source/SourceSet.java index 0a1dd70f4..2bac17613 100644 --- a/src/main/java/dev/jbang/source/SourceSet.java +++ b/src/main/java/dev/jbang/source/SourceSet.java @@ -4,7 +4,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -21,6 +23,7 @@ public class SourceSet { private final List sources = new ArrayList<>(); private final List resources = new ArrayList<>(); + private final Set sourceDirs = new HashSet<>(); private final List dependencies = new ArrayList<>(); private final List classPaths = new ArrayList<>(); private final List compileOptions = new ArrayList<>(); @@ -67,6 +70,23 @@ public SourceSet addResources(Collection resources) { return this; } + @Nonnull + public Set getSourceDirs() { + return Collections.unmodifiableSet(sourceDirs); + } + + @Nonnull + public SourceSet addSourceDir(ResourceRef sourceDir) { + sourceDirs.add(sourceDir); + return this; + } + + @Nonnull + public SourceSet addSourceDirs(Collection sourceDirs) { + this.sourceDirs.addAll(sourceDirs); + return this; + } + @Nonnull public List getDependencies() { return Collections.unmodifiableList(dependencies); diff --git a/src/main/java/dev/jbang/source/buildsteps/CompileBuildStep.java b/src/main/java/dev/jbang/source/buildsteps/CompileBuildStep.java index e2fcca54d..ccd84438d 100644 --- a/src/main/java/dev/jbang/source/buildsteps/CompileBuildStep.java +++ b/src/main/java/dev/jbang/source/buildsteps/CompileBuildStep.java @@ -10,6 +10,7 @@ import dev.jbang.cli.ExitException; import dev.jbang.dependencies.MavenCoordinate; +import dev.jbang.dependencies.ModularClassPath; import dev.jbang.source.Builder; import dev.jbang.source.Project; import dev.jbang.util.CommandBuffer; @@ -41,10 +42,22 @@ protected Project compile() throws IOException { optionList.addAll(project.getMainSourceSet().getCompileOptions()); String path = project.resolveClassPath().getClassPath(); if (!Util.isBlankString(path)) { - optionList.addAll(Arrays.asList("-classpath", path)); + optionList.add("-classpath"); + optionList.add(path); } optionList.addAll(Arrays.asList("-d", compileDir.toAbsolutePath().toString())); + // add -sourcepath for all source folders + List srcDirs = project .getMainSourceSet() + .getSourceDirs() + .stream() + .map(d -> d.getFile().toString()) + .collect(Collectors.toList()); + if (!srcDirs.isEmpty()) { + optionList.add("-sourcepath"); + optionList.add(ModularClassPath.toClassPath(srcDirs)); + } + // add source files to compile optionList.addAll(project .getMainSourceSet() .getSources() diff --git a/src/main/java/dev/jbang/source/generators/JshCmdGenerator.java b/src/main/java/dev/jbang/source/generators/JshCmdGenerator.java index 3fdb592ba..290f0c6dc 100644 --- a/src/main/java/dev/jbang/source/generators/JshCmdGenerator.java +++ b/src/main/java/dev/jbang/source/generators/JshCmdGenerator.java @@ -12,6 +12,7 @@ import org.apache.commons.text.StringEscapeUtils; +import dev.jbang.dependencies.ModularClassPath; import dev.jbang.source.*; import dev.jbang.util.JavaUtil; import dev.jbang.util.Util; @@ -43,8 +44,10 @@ protected List generateCommandLineList() throws IOException { List optionalArgs = new ArrayList<>(); String requestedJavaVersion = getProject().getJavaVersion(); - String javacmd; - javacmd = JavaUtil.resolveInJavaHome("jshell", requestedJavaVersion); + if (requestedJavaVersion == null) { + requestedJavaVersion = "9+"; + } + String jshcmd = JavaUtil.resolveInJavaHome("jshell", requestedJavaVersion); // NB: See https://github.com/jbangdev/jbang/issues/992 for the reasons why we // use the -J flags below @@ -90,7 +93,7 @@ protected List generateCommandLineList() throws IOException { Util.warnMsg("Java Flight Recording not possible when running via jshell."); } - fullArgs.add(javacmd); + fullArgs.add(jshcmd); addAgentsArgs(fullArgs); fullArgs.addAll(jshellOpts(project.getRuntimeOptions())); @@ -98,6 +101,17 @@ protected List generateCommandLineList() throws IOException { fullArgs.addAll(optionalArgs); if (project.isJShell()) { + // add -sourcepath for all source folders + List srcDirs = project .getMainSourceSet() + .getSourceDirs() + .stream() + .map(d -> d.getFile().toString()) + .collect(Collectors.toList()); + if (!srcDirs.isEmpty()) { + fullArgs.add("-C-sourcepath"); + fullArgs.add(ModularClassPath.toClassPath(srcDirs)); + } + ArrayList revSources = new ArrayList<>(project.getMainSourceSet().getSources()); Collections.reverse(revSources); for (ResourceRef s : revSources) { diff --git a/src/test/java/dev/jbang/cli/TestRun.java b/src/test/java/dev/jbang/cli/TestRun.java index 00e94ab41..960685ca1 100644 --- a/src/test/java/dev/jbang/cli/TestRun.java +++ b/src/test/java/dev/jbang/cli/TestRun.java @@ -572,7 +572,7 @@ void testHelloWorldShellNoExit() throws IOException { String result = prj.cmdGenerator().generate(); - assertThat(result, startsWith("jshell")); + assertThat(result, matchesPattern("^.*jshell(.exe)?.*")); assertThat(result, not(containsString(" "))); assertThat(result, containsString("helloworld.jsh")); assertThat(result, not(containsString("--source 11"))); @@ -662,7 +662,7 @@ void testDependenciesInteractive() throws IOException { String result = prj.cmdGenerator().generate(); - assertThat(result, startsWith("jshell ")); + assertThat(result, matchesPattern("^.*jshell(.exe)?.*")); assertThat(result, (containsString("classpath_example.java"))); // assertThat(result, containsString(" --source 11 ")); assertThat(result, not(containsString(" "))); diff --git a/src/test/java/dev/jbang/source/TestBuilder.java b/src/test/java/dev/jbang/source/TestBuilder.java index a9bfd9fe5..faca9366a 100644 --- a/src/test/java/dev/jbang/source/TestBuilder.java +++ b/src/test/java/dev/jbang/source/TestBuilder.java @@ -226,6 +226,7 @@ void testAdditionalSourcesFolder() throws IOException { Util.setCwd(examplesTestFolder); String mainFile = examplesTestFolder.resolve("foo.java").toString(); String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); + String srcPath = examplesTestFolder.resolve("bar") + File.pathSeparator + examplesTestFolder; ProjectBuilder pb = ProjectBuilder.create(); pb.additionalSources(Arrays.asList("bar")); @@ -239,6 +240,7 @@ protected Builder getCompileBuildStep() { protected void runCompiler(List optionList) { assertThat(optionList, hasItem(mainFile)); assertThat(optionList, hasItem(incFile)); + assertThat(optionList, hasItems("-sourcepath", srcPath)); // Skip the compiler } }; @@ -512,4 +514,24 @@ protected void runNativeBuilder(List optionList) throws IOException { } }.setFresh(true).build(); } + + @Test + void testMultiSourceWithDeps() throws IOException { + Path foo = examplesTestFolder.resolve("extending").resolve("Foo.java"); + ProjectBuilder pb = ProjectBuilder.create(); + Project prj = pb.build(foo.toString()); + + new JavaSource.JavaAppBuilder(prj) { + @Override + protected Builder getCompileBuildStep() { + return new JavaCompileBuildStep() { + @Override + protected void runCompiler(List optionList) { + assertThat(optionList, hasItems("-sourcepath", examplesTestFolder.toString(), foo.toString())); + // Skip the compiler + } + }; + } + }.setFresh(true).build(); + } }