diff --git a/bootstrap.sh b/bootstrap.sh index 40bcefb9f..ed35ae3b9 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -2,7 +2,7 @@ ## in gradle we have plugin to generate BuildConfig with version info in it. ## For now just generate a placeholder. Ultimately could be some other script to generate the file. -mkdir generated +mkdir -p generated cat << EOF > generated/BuildConfig.java package dev.jbang; @@ -15,4 +15,4 @@ public final class BuildConfig { } EOF -jbang export local --verbose --fresh --force --sources src/main/java/**.java,generated/**.java --files .=src/main/resources/** --repos mavencentral,jitpack --deps org.jboss:jandex:2.2.3.Final,org.slf4j:slf4j-nop:1.7.30,com.offbytwo:docopt:0.6.0.20150202,org.apache.commons:commons-text:1.9,org.apache.commons:commons-compress:1.20,info.picocli:picocli:4.6.1,io.quarkus.qute:qute-core:1.12.2.Final,kr.motd.maven:os-maven-plugin:1.7.0,org.codehaus.plexus:plexus-java:1.0.6,com.google.code.gson:gson:2.9.0,org.jsoup:jsoup:1.13.1,org.codejive:java-properties:0.0.4,com.github.jbangdev.jbang-resolver:shrinkwrap-resolver-api:3.1.5-allowpom,com.github.jbangdev.jbang-resolver:shrinkwrap-resolver-impl-maven:3.1.5-allowpom src/main/java/dev/jbang/Main.java \ No newline at end of file +jbang export local --verbose --force -O jbang.jar --sources 'src/main/java,generated/' --files 'src/main/resources' --repos mavencentral,jitpack --deps org.jboss:jandex:2.2.3.Final,org.slf4j:slf4j-nop:1.7.30,com.offbytwo:docopt:0.6.0.20150202,org.apache.commons:commons-text:1.9,org.apache.commons:commons-compress:1.20,info.picocli:picocli:4.6.1,io.quarkus.qute:qute-core:1.12.2.Final,kr.motd.maven:os-maven-plugin:1.7.0,org.codehaus.plexus:plexus-java:1.0.6,com.google.code.gson:gson:2.9.0,org.jsoup:jsoup:1.13.1,org.codejive:java-properties:0.0.4,com.github.jbangdev.jbang-resolver:shrinkwrap-resolver-api:3.1.5-allowpom,com.github.jbangdev.jbang-resolver:shrinkwrap-resolver-impl-maven:3.1.5-allowpom src/main/java/dev/jbang/Main.java diff --git a/src/main/java/dev/jbang/util/Util.java b/src/main/java/dev/jbang/util/Util.java index 6f3d72c17..188081d32 100644 --- a/src/main/java/dev/jbang/util/Util.java +++ b/src/main/java/dev/jbang/util/Util.java @@ -54,6 +54,7 @@ import dev.jbang.BuildConfig; import dev.jbang.Cache; import dev.jbang.Settings; +import dev.jbang.catalog.Catalog; import dev.jbang.cli.BaseCommand; import dev.jbang.cli.ExitException; import dev.jbang.dependencies.DependencyUtil; @@ -181,76 +182,81 @@ static public boolean isPattern(String pattern) { /** * Explodes filePattern found in baseDir returning list of relative Path names. - * - * TODO: this really should return some kind of abstraction of paths that allow - * it be portable for urls as wells as files...or have a filesystem for each... - * - * @param source - * @param baseDir - * @param filePattern - * @return + * If the filePattern refers to an existing folder the filePattern will be + * treated as if it ended in "/**". */ public static List explode(String source, Path baseDir, String filePattern) { - List results = new ArrayList<>(); - if (source != null && Util.isURL(source)) { // if url then just return it back for others to resolve. // TODO: technically this is really where it should get resolved! if (isPattern(filePattern)) { Util.warnMsg("Pattern " + filePattern + " used while using URL to run; this could result in errors."); - return results; + return Collections.emptyList(); } else { - results.add(filePattern); + return Collections.singletonList(filePattern); } } else if (Util.isURL(filePattern)) { - results.add(filePattern); - } else if (!isPattern(filePattern)) { - // not a pattern thus just as well return path directly - results.add(filePattern); - } else { - // it is a non-url let's try to locate it - final Path bd; - final boolean useAbsPath; - Path base = basePathWithoutPattern(filePattern); - String fp; - if (base.isAbsolute()) { - bd = base; - fp = filePattern.substring(bd.toString().length() + 1); - useAbsPath = true; + return Collections.singletonList(filePattern); + } + + if (!isPattern(filePattern)) { + if (!Catalog.isValidCatalogReference(filePattern) + && Util.isValidPath(filePattern) && Files.isDirectory(baseDir.resolve(filePattern))) { + // The filePattern refers to a folder, so let's add "/**" + if (!filePattern.endsWith("/") && !filePattern.endsWith(File.separator)) { + filePattern = filePattern + "/"; + } + filePattern = filePattern + "**"; } else { - bd = baseDir.resolve(base); - fp = base.toString().isEmpty() ? filePattern : filePattern.substring(base.toString().length() + 1); - useAbsPath = false; + // not a pattern and not a folder thus just as well return path directly + return Collections.singletonList(filePattern); } - PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + fp); - - FileVisitor matcherVisitor = new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attribs) { - Path relpath = bd.relativize(file); - if (matcher.matches(relpath)) { - // to avoid windows fail. - if (file.toFile().exists()) { - Path p = useAbsPath ? file : base.resolve(relpath); - if (isWindows()) { - results.add(p.toString().replace("\\", "/")); - } else { - results.add(p.toString()); - } + } + + // it is a non-url let's try to locate it + final Path bd; + final boolean useAbsPath; + Path base = basePathWithoutPattern(filePattern); + String fp; + if (base.isAbsolute()) { + bd = base; + fp = filePattern.substring(bd.toString().length() + 1); + useAbsPath = true; + } else { + bd = baseDir.resolve(base); + fp = base.toString().isEmpty() ? filePattern : filePattern.substring(base.toString().length() + 1); + useAbsPath = false; + } + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + fp); + + List results = new ArrayList<>(); + FileVisitor matcherVisitor = new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attribs) { + Path relpath = bd.relativize(file); + if (matcher.matches(relpath)) { + // to avoid windows fail. + if (file.toFile().exists()) { + Path p = useAbsPath ? file : base.resolve(relpath); + if (isWindows()) { + results.add(p.toString().replace("\\", "/")); } else { - Util.verboseMsg("Warning: " + relpath + " matches but does not exist!"); + results.add(p.toString()); } + } else { + Util.verboseMsg("Warning: " + relpath + " matches but does not exist!"); } - return FileVisitResult.CONTINUE; } - }; - - try { - Files.walkFileTree(bd, matcherVisitor); - } catch (IOException e) { - throw new ExitException(BaseCommand.EXIT_INTERNAL_ERROR, "Problem looking for " + fp + " in " + bd, e); + return FileVisitResult.CONTINUE; } + }; + + try { + Files.walkFileTree(bd, matcherVisitor); + } catch (IOException e) { + throw new ExitException(BaseCommand.EXIT_INTERNAL_ERROR, "Problem looking for " + fp + " in " + bd, e); } + return results; } diff --git a/src/test/java/dev/jbang/cli/TestRun.java b/src/test/java/dev/jbang/cli/TestRun.java index e151e9e63..9d8144d6d 100644 --- a/src/test/java/dev/jbang/cli/TestRun.java +++ b/src/test/java/dev/jbang/cli/TestRun.java @@ -3,7 +3,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static dev.jbang.util.Util.readString; import static dev.jbang.util.Util.writeString; import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.CoreMatchers.nullValue; @@ -53,7 +52,6 @@ import dev.jbang.Cache; import dev.jbang.Settings; import dev.jbang.catalog.Catalog; -import dev.jbang.catalog.CatalogUtil; import dev.jbang.net.TrustedSources; import dev.jbang.source.Code; import dev.jbang.source.Jar; @@ -1568,104 +1566,6 @@ protected void runCompiler(List optionList) }.setFresh(true).build(); } - @Test - void testAdditionalSourcesUsingAlias() throws IOException { - String mainFile = examplesTestFolder.resolve("foo.java").toString(); - String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); - - CatalogUtil.addNearestAlias("bar", incFile, null, null, null, null, null, null, null, null, null, null, null); - - CommandLine.ParseResult pr = JBang.getCommandLine().parseArgs("build", "-s", "bar", mainFile); - Build build = (Build) pr.subcommand().commandSpec().userObject(); - - RunContext ctx = build.getRunContext(); - SourceSet ss = (SourceSet) ctx.forResource(mainFile); - - new JavaBuilder(ss, ctx) { - @Override - protected void runCompiler(List optionList) - throws IOException { - assertThat(optionList, hasItem(mainFile)); - assertThat(optionList, hasItem(incFile)); - // Skip the compiler - } - }.setFresh(true).build(); - } - - @Test - void testIncludedSourcesUsingAlias(@TempDir Path dir) throws IOException { - Path mainFile = dir.resolve("foo.java"); - String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); - - Path fooFile = examplesTestFolder.resolve("foo.java"); - String fooScript = readString(fooFile); - writeString(mainFile, "//SOURCES bar@" + jbangTempDir + "\n" + fooScript); - - CatalogUtil.addNearestAlias("bar", incFile, null, null, null, null, null, null, null, null, null, null, null); - - CommandLine.ParseResult pr = JBang.getCommandLine().parseArgs("build", mainFile.toString()); - Build build = (Build) pr.subcommand().commandSpec().userObject(); - - RunContext ctx = build.getRunContext(); - SourceSet ss = (SourceSet) ctx.forResource(mainFile.toString()); - - new JavaBuilder(ss, ctx) { - @Override - protected void runCompiler(List optionList) - throws IOException { - assertThat(optionList, hasItem(mainFile.toString())); - assertThat(optionList, hasItem(incFile)); - // Skip the compiler - } - }.setFresh(true).build(); - } - - @Test - void testAdditionalSourcesGlobbing() throws IOException { - Util.setCwd(examplesTestFolder); - String mainFile = examplesTestFolder.resolve("foo.java").toString(); - String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); - - CommandLine.ParseResult pr = JBang.getCommandLine().parseArgs("build", "-s", "bar/*.java", "foo.java"); - Build build = (Build) pr.subcommand().commandSpec().userObject(); - - RunContext ctx = build.getRunContext(); - SourceSet ss = (SourceSet) ctx.forResource(mainFile); - - new JavaBuilder(ss, ctx) { - @Override - protected void runCompiler(List optionList) - throws IOException { - assertThat(optionList, hasItem(mainFile)); - assertThat(optionList, hasItem(incFile)); - // Skip the compiler - } - }.setFresh(true).build(); - } - - @Test - void testAdditionalSourcesAbsGlobbing() throws IOException { - String mainFile = examplesTestFolder.resolve("foo.java").toString(); - String incGlob = examplesTestFolder.resolve("bar").toString() + File.separatorChar + "*.java"; - String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); - - CommandLine.ParseResult pr = JBang.getCommandLine().parseArgs("build", "-s", incGlob, mainFile); - Build build = (Build) pr.subcommand().commandSpec().userObject(); - - RunContext ctx = build.getRunContext(); - SourceSet ss = (SourceSet) ctx.forResource(mainFile); - - new JavaBuilder(ss, ctx) { - @Override - protected void runCompiler(List optionList) - throws IOException { - assertThat(optionList, hasItem(mainFile)); - assertThat(optionList, hasItem(incFile)); - // Skip the compiler - } - }.setFresh(true).build(); - } - @Test void testAdditionalResources() throws IOException { Util.setCwd(examplesTestFolder); @@ -1698,39 +1598,6 @@ public void createJar() throws IOException { }.setFresh(true).build(); } - @Test - void testAdditionalResourcesGlobbing() throws IOException { - Util.setCwd(examplesTestFolder); - String mainFile = "foo.java"; - - CommandLine.ParseResult pr = JBang .getCommandLine() - .parseArgs("build", "--files", "res/**.properties", mainFile); - Build build = (Build) pr.subcommand().commandSpec().userObject(); - - RunContext ctx = build.getRunContext(); - SourceSet ss = (SourceSet) ctx.forResource(mainFile); - - new JavaBuilder(ss, ctx) { - @Override - protected void runCompiler(List optionList) { - assertThat(optionList, hasItem(endsWith(File.separator + "foo.java"))); - // Skip the compiler - } - - @Override - public void createJar() throws IOException { - assertThat(ss.getResources().size(), is(3)); - List ps = ss.getResources() - .stream() - .map(r -> r.getSource().getFile().toPath().toString()) - .collect(Collectors.toList()); - assertThat(ps, hasItem(endsWith("resource.properties"))); - assertThat(ps, hasItem(endsWith("test.properties"))); - assertThat(ps, hasItem(endsWith("sub" + File.separator + "sub.properties"))); - } - }.setFresh(true).build(); - } - WireMockServer wms; @BeforeEach diff --git a/src/test/java/dev/jbang/source/TestBuilder.java b/src/test/java/dev/jbang/source/TestBuilder.java index bc4252bac..27776fcac 100644 --- a/src/test/java/dev/jbang/source/TestBuilder.java +++ b/src/test/java/dev/jbang/source/TestBuilder.java @@ -1,5 +1,8 @@ package dev.jbang.source; +import static dev.jbang.util.Util.readString; +import static dev.jbang.util.Util.writeString; +import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @@ -9,10 +12,13 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import dev.jbang.BaseTest; +import dev.jbang.catalog.CatalogUtil; import dev.jbang.source.builders.JavaBuilder; import dev.jbang.util.Util; @@ -37,6 +43,116 @@ protected void runCompiler(List optionList) }.setFresh(true).build(); } + @Test + void testAdditionalSourcesUsingAlias() throws IOException { + String mainFile = examplesTestFolder.resolve("foo.java").toString(); + String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); + + CatalogUtil.addNearestAlias("bar", incFile, null, null, null, null, null, null, null, null, null, null, null); + + RunContext ctx = RunContext.empty(); + ctx.setAdditionalSources(Arrays.asList("bar")); + SourceSet ss = (SourceSet) ctx.forResource(mainFile); + + new JavaBuilder(ss, ctx) { + @Override + protected void runCompiler(List optionList) + throws IOException { + assertThat(optionList, hasItem(mainFile)); + assertThat(optionList, hasItem(incFile)); + // Skip the compiler + } + }.setFresh(true).build(); + } + + @Test + void testIncludedSourcesUsingAlias(@TempDir Path dir) throws IOException { + Path mainFile = dir.resolve("foo.java"); + String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); + + Path fooFile = examplesTestFolder.resolve("foo.java"); + String fooScript = readString(fooFile); + writeString(mainFile, "//SOURCES bar@" + jbangTempDir + "\n" + fooScript); + + CatalogUtil.addNearestAlias("bar", incFile, null, null, null, null, null, null, null, null, null, null, null); + + RunContext ctx = RunContext.empty(); + SourceSet ss = (SourceSet) ctx.forResource(mainFile.toString()); + + new JavaBuilder(ss, ctx) { + @Override + protected void runCompiler(List optionList) + throws IOException { + assertThat(optionList, hasItem(mainFile.toString())); + assertThat(optionList, hasItem(incFile)); + // Skip the compiler + } + }.setFresh(true).build(); + } + + @Test + void testAdditionalSourcesGlobbing() throws IOException { + Util.setCwd(examplesTestFolder); + String mainFile = examplesTestFolder.resolve("foo.java").toString(); + String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); + + RunContext ctx = RunContext.empty(); + ctx.setAdditionalSources(Arrays.asList("bar/*.java")); + SourceSet ss = (SourceSet) ctx.forResource(mainFile); + + new JavaBuilder(ss, ctx) { + @Override + protected void runCompiler(List optionList) + throws IOException { + assertThat(optionList, hasItem(mainFile)); + assertThat(optionList, hasItem(incFile)); + // Skip the compiler + } + }.setFresh(true).build(); + } + + @Test + void testAdditionalSourcesAbsGlobbing() throws IOException { + String mainFile = examplesTestFolder.resolve("foo.java").toString(); + String incGlob = examplesTestFolder.resolve("bar").toString() + File.separatorChar + "*.java"; + String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); + + RunContext ctx = RunContext.empty(); + ctx.setAdditionalSources(Arrays.asList(incGlob)); + SourceSet ss = (SourceSet) ctx.forResource(mainFile); + + new JavaBuilder(ss, ctx) { + @Override + protected void runCompiler(List optionList) + throws IOException { + assertThat(optionList, hasItem(mainFile)); + assertThat(optionList, hasItem(incFile)); + // Skip the compiler + } + }.setFresh(true).build(); + } + + @Test + void testAdditionalSourcesFolder() throws IOException { + Util.setCwd(examplesTestFolder); + String mainFile = examplesTestFolder.resolve("foo.java").toString(); + String incFile = examplesTestFolder.resolve("bar/Bar.java").toString(); + + RunContext ctx = RunContext.empty(); + ctx.setAdditionalSources(Arrays.asList("bar")); + SourceSet ss = (SourceSet) ctx.forResource(mainFile); + + new JavaBuilder(ss, ctx) { + @Override + protected void runCompiler(List optionList) + throws IOException { + assertThat(optionList, hasItem(mainFile)); + assertThat(optionList, hasItem(incFile)); + // Skip the compiler + } + }.setFresh(true).build(); + } + @Test void testBuildAdditionalResources() throws IOException { Util.setCwd(examplesTestFolder); @@ -94,4 +210,67 @@ public void createJar() { } }.setFresh(true).build(); } + + @Test + void testAdditionalResourcesGlobbing() throws IOException { + Util.setCwd(examplesTestFolder); + Path foo = Paths.get("foo.java"); + Path res1 = Paths.get("resource.properties"); + Path res2 = Paths.get("sub/sub.properties"); + RunContext ctx = RunContext.empty(); + ctx.setAdditionalResources(Arrays.asList("res/**.properties")); + SourceSet ss = (SourceSet) ctx.forResource(foo.toString()); + + new JavaBuilder(ss, ctx) { + @Override + protected void runCompiler(List optionList) { + assertThat(optionList, hasItem(endsWith(File.separator + "foo.java"))); + // Skip the compiler + } + + @Override + public void createJar() throws IOException { + assertThat(ss.getResources().size(), is(3)); + List ps = ss.getResources() + .stream() + .map(r -> r.getSource().getFile().toPath().toString()) + .collect(Collectors.toList()); + assertThat(ps, hasItem(endsWith("resource.properties"))); + assertThat(ps, hasItem(endsWith("test.properties"))); + assertThat(ps, hasItem(endsWith("sub" + File.separator + "sub.properties"))); + } + }.setFresh(true).build(); + } + + @Test + void testAdditionalResourcesFolder() throws IOException { + Util.setCwd(examplesTestFolder); + Path foo = Paths.get("foo.java"); + Path res1 = Paths.get("resource.properties"); + Path res2 = Paths.get("sub/sub.properties"); + RunContext ctx = RunContext.empty(); + ctx.setAdditionalResources(Arrays.asList("res")); + SourceSet ss = (SourceSet) ctx.forResource(foo.toString()); + + new JavaBuilder(ss, ctx) { + @Override + protected void runCompiler(List optionList) { + assertThat(optionList, hasItem(endsWith(File.separator + "foo.java"))); + // Skip the compiler + } + + @Override + public void createJar() throws IOException { + assertThat(ss.getResources().size(), is(4)); + List ps = ss.getResources() + .stream() + .map(r -> r.getSource().getFile().toPath().toString()) + .collect(Collectors.toList()); + assertThat(ps, hasItem(endsWith("resource.java"))); + assertThat(ps, hasItem(endsWith("resource.properties"))); + assertThat(ps, hasItem(endsWith("test.properties"))); + assertThat(ps, hasItem(endsWith("sub" + File.separator + "sub.properties"))); + } + }.setFresh(true).build(); + } }