Skip to content

feat: handle documentation references both in source references and in alias catalog #2013

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

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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
10 changes: 10 additions & 0 deletions itests/docstest1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//DOCS readme.md

import static java.lang.System.*;

public class docstest1 {
public static void main(String... args) {
out.println("Docs test 1"));
}
}
10 changes: 10 additions & 0 deletions itests/docstest2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//DOCS https://www.jbang.dev/documentation/guide/latest/faq.html

import static java.lang.System.*;

public class docstest1 {
public static void main(String... args) {
out.println("Docs test 2"));
}
}
12 changes: 8 additions & 4 deletions src/main/java/dev/jbang/catalog/Alias.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class Alias extends CatalogItem {
public final Map<String, String> manifestOptions;
@SerializedName(value = "java-agents")
public final List<JavaAgent> javaAgents;
public final String docs;

public static class JavaAgent {
@SerializedName(value = "agent-ref")
Expand Down Expand Up @@ -89,7 +90,7 @@ public int hashCode() {

public Alias() {
this(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null);
null, null, null, null, null, null, null, null, null, null);
}

public Alias(String scriptRef,
Expand Down Expand Up @@ -118,6 +119,7 @@ public Alias(String scriptRef,
Boolean enableSystemAssertions,
Map<String, String> manifestOptions,
List<JavaAgent> javaAgents,
String docs,
Catalog catalog) {
super(catalog);
this.scriptRef = scriptRef;
Expand Down Expand Up @@ -146,6 +148,7 @@ public Alias(String scriptRef,
this.enableSystemAssertions = enableSystemAssertions;
this.manifestOptions = manifestOptions;
this.javaAgents = javaAgents;
this.docs = docs;
}

/**
Expand Down Expand Up @@ -246,10 +249,11 @@ private static Alias merge(Alias a1, String name, Function<String, Alias> findUn
Map<String, String> mopts = a1.manifestOptions != null && !a1.manifestOptions.isEmpty() ? a1.manifestOptions
: a2.manifestOptions;
List<JavaAgent> jags = a1.javaAgents != null && !a1.javaAgents.isEmpty() ? a1.javaAgents : a2.javaAgents;
String docs = a1.docs != null ? a1.docs : a2.docs;
Catalog catalog = a2.catalog != null ? a2.catalog : a1.catalog;
return new Alias(a2.scriptRef, desc, args, jopts, srcs, ress, deps, repos, cpaths, props, javaVersion,
mainClass, moduleName, copts, nimg, nopts, ints, jfr, debug, cds, inter, ep, ea, esa, mopts, jags,
catalog);
docs, catalog);
} else {
return a1;
}
Expand Down Expand Up @@ -294,13 +298,13 @@ public Alias withCatalog(Catalog catalog) {
return new Alias(scriptRef, description, arguments, runtimeOptions, sources, resources, dependencies,
repositories, classpaths, properties, javaVersion, mainClass, moduleName, compileOptions, nativeImage,
nativeOptions, integrations, jfr, debug, cds, interactive, enablePreview, enableAssertions,
enableSystemAssertions, manifestOptions, javaAgents, catalog);
enableSystemAssertions, manifestOptions, javaAgents, docs, catalog);
}

public Alias withScriptRef(String scriptRef) {
return new Alias(scriptRef, description, arguments, runtimeOptions, sources, resources, dependencies,
repositories, classpaths, properties, javaVersion, mainClass, moduleName, compileOptions, nativeImage,
nativeOptions, integrations, jfr, debug, cds, interactive, enablePreview, enableAssertions,
enableSystemAssertions, manifestOptions, javaAgents, catalog);
enableSystemAssertions, manifestOptions, javaAgents, docs, catalog);
}
}
10 changes: 9 additions & 1 deletion src/main/java/dev/jbang/cli/Alias.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class AliasAdd extends BaseAliasCommand {
@CommandLine.Parameters(paramLabel = "params", index = "1..*", arity = "0..*", description = "Parameters to pass on to the script")
List<String> userParams;

@CommandLine.Option(names = { "--docs" }, description = "Documentation reference for the alias")
String docs;

@Override
public Integer doCall() {
scriptMixin.validate();
Expand All @@ -118,7 +121,7 @@ public Integer doCall() {
buildMixin.compileOptions, nativeMixin.nativeImage, nativeMixin.nativeOptions, buildMixin.integrations,
runMixin.flightRecorderString, runMixin.debugString, runMixin.cds, runMixin.interactive,
enablePreviewRequested, runMixin.enableAssertions, runMixin.enableSystemAssertions,
buildMixin.manifestOptions, createJavaAgents(), null);
buildMixin.manifestOptions, createJavaAgents(), docs, null);
Path catFile = getCatalog(false);
if (catFile == null) {
catFile = Catalog.getCatalogFile(null);
Expand Down Expand Up @@ -262,6 +265,7 @@ static class AliasOut {
public Map<String, String> properties;
public transient ResourceRef _catalogRef;
public Boolean enablePreview;
public String docsRef;
}

private static AliasOut getAliasOut(String catalogName, Catalog catalog, String name) {
Expand All @@ -287,6 +291,7 @@ private static AliasOut getAliasOut(String catalogName, Catalog catalog, String
out.properties = alias.properties;
out._catalogRef = alias.catalog.catalogRef;
out.enablePreview = alias.enablePreview;
out.docsRef = alias.docs;
return out;
}

Expand All @@ -298,6 +303,9 @@ private static void printAlias(PrintStream out, AliasOut alias, int indent) {
if (alias.description != null) {
out.println(prefix2 + alias.description);
}
if (alias.docsRef != null) {
out.println(prefix2 + alias.docsRef);
}
out.println(prefix2 + ConsoleOutput.faint(alias.scriptRef));
if (alias.arguments != null) {
out.println(prefix3 + ConsoleOutput.cyan(" Arguments: ") + String.join(" ", alias.arguments));
Expand Down
34 changes: 33 additions & 1 deletion src/main/java/dev/jbang/cli/Info.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import static dev.jbang.Settings.CP_SEPARATOR;

import java.awt.Desktop;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
Expand All @@ -28,7 +30,7 @@
import picocli.CommandLine;

@CommandLine.Command(name = "info", description = "Provides info about the script for tools (and humans who are tools).", subcommands = {
Tools.class, ClassPath.class, Jar.class })
Tools.class, ClassPath.class, Jar.class, Docs.class })
public class Info {
}

Expand Down Expand Up @@ -94,6 +96,7 @@ static class ScriptInfo {
String description;
String gav;
String module;
ResourceRef docs;

public ScriptInfo(BuildContext ctx, boolean assureJdkInstalled) {
Project prj = ctx.getProject();
Expand Down Expand Up @@ -179,6 +182,8 @@ private void init(BuildContext ctx) {
}
gav = prj.getGav().orElse(null);
description = prj.getDescription().orElse(null);
docs = prj.getDocs().orElse(null);

module = prj.getModuleName().orElse(null);
}

Expand Down Expand Up @@ -308,3 +313,30 @@ public Integer doCall() throws IOException {
return EXIT_OK;
}
}

@CommandLine.Command(name = "docs", description = "Open the documentation file in the default browser.")
class Docs extends BaseInfoCommand {

@Override
public Integer doCall() throws IOException {
URI uri = getDocsUri();
info("Showing documentation: " + uri);
Desktop.getDesktop().browse(uri);
return EXIT_OK;
}

URI getDocsUri() {
ScriptInfo info = getInfo(false);
return validateDocsReferenceAndTransformToUri(info);
}

private static URI validateDocsReferenceAndTransformToUri(ScriptInfo info) {
if (info.docs.isURL()) {
return URI.create(info.docs.getOriginalResource());
}
if (!info.docs.exists()) {
throw new ExitException(EXIT_INVALID_INPUT, "Invalid documentation file path: " + info.docs.getFile());
}
return info.docs.getFile().toUri();
}
}
12 changes: 12 additions & 0 deletions src/main/java/dev/jbang/source/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class Project {
private final Map<String, String> manifestAttributes = new LinkedHashMap<>();
private String javaVersion;
private String description;
private ResourceRef docs;
private String gav;
private String mainClass;
private String moduleName;
Expand Down Expand Up @@ -180,6 +181,17 @@ public Project setDescription(String description) {
return this;
}

@Nonnull
public Optional<ResourceRef> getDocs() {
return Optional.ofNullable(docs);
}

@Nonnull
public Project setDocs(ResourceRef docs) {
this.docs = docs;
return this;
}

@Nonnull
public Optional<String> getGav() {
return Optional.ofNullable(gav);
Expand Down
18 changes: 16 additions & 2 deletions src/main/java/dev/jbang/source/ProjectBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import dev.jbang.source.resolvers.CombinedResourceResolver;
import dev.jbang.source.resolvers.FileResourceResolver;
import dev.jbang.source.resolvers.GavResourceResolver;
import dev.jbang.source.resolvers.LazyResourceResolver;
import dev.jbang.source.resolvers.LiteralScriptResourceResolver;
import dev.jbang.source.resolvers.RemoteResourceResolver;
import dev.jbang.source.resolvers.RenamingScriptResourceResolver;
Expand Down Expand Up @@ -76,6 +77,7 @@ public class ProjectBuilder {
private Boolean integrations;
private String javaVersion;
private Boolean enablePreview;
private String docs;
private JdkManager jdkManager;

// Cached values
Expand Down Expand Up @@ -320,13 +322,14 @@ private Project createJbangProject(ResourceRef resourceRef) {
TagReader tagReader = new TagReader.JbangProject(contents,
it -> PropertiesValueResolver.replaceProperties(it, getContextProperties()));
prj.setDescription(tagReader.getDescription().orElse(null));
ResourceResolver resolver1 = new SiblingResourceResolver(resourceRef, ResourceResolver.forResources());
prj.setDocs(tagReader.getDocs(LazyResourceResolver.lazy(resolver1)).orElse(null));
prj.setGav(tagReader.getGav().orElse(null));
prj.setMainClass(tagReader.getMain().orElse(null));
prj.setModuleName(tagReader.getModule().orElse(null));

SourceSet ss = prj.getMainSourceSet();
ss.addResources(tagReader.collectFiles(resourceRef,
new SiblingResourceResolver(resourceRef, ResourceResolver.forResources())));
ss.addResources(tagReader.collectFiles(resourceRef, resolver1));
ss.addDependencies(tagReader.collectBinaryDependencies());
ss.addCompileOptions(tagReader.collectOptions("JAVAC_OPTIONS", "COMPILE_OPTIONS"));
ss.addNativeOptions(tagReader.collectOptions("NATIVE_OPTIONS"));
Expand Down Expand Up @@ -485,6 +488,12 @@ private Project updateProject(Project prj) {
if (enablePreview != null) {
prj.setEnablePreviewRequested(enablePreview);
}
if (docs != null) {
ResourceResolver resolver = LazyResourceResolver
.lazy(new SiblingResourceResolver(prj.getResourceRef(), ResourceResolver.forResources()));
ResourceRef docsRef = resolver.resolve(docs);
prj.setDocs(docsRef);
}
if (jdkManager != null) {
prj.setJdkManager(jdkManager);
} else {
Expand Down Expand Up @@ -560,6 +569,8 @@ private Project updateProject(Source src, Project prj, ResourceResolver resolver
ss.addNativeOptions(src.getNativeOptions());
prj.addRepositories(src.tagReader.collectRepositories());
prj.addRuntimeOptions(src.getRuntimeOptions());
prj.setDocs(src.tagReader.getDocs(LazyResourceResolver.lazy(sibRes1)).orElse(null));

src.tagReader.collectManifestOptions().forEach(kv -> {
if (!kv.getKey().isEmpty()) {
prj.getManifestAttributes().put(kv.getKey(), kv.getValue() != null ? kv.getValue() : "true");
Expand Down Expand Up @@ -660,6 +671,9 @@ private void updateFromAlias(Alias alias) {
if (enablePreview == null) {
enablePreview(alias.enablePreview);
}
if (docs != null) {
docs = alias.docs;
}
}

public static boolean isAlias(ResourceRef resourceRef) {
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/dev/jbang/source/TagReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public abstract class TagReader {
private static final String MODULE_COMMENT_PREFIX = "MODULE";
private static final String DESCRIPTION_COMMENT_PREFIX = "DESCRIPTION ";
private static final String GAV_COMMENT_PREFIX = "GAV ";
private static final String DOCS_COMMENT_PREFIX = "DOCS ";

private static final Pattern EOL = Pattern.compile("\\r?\\n");

Expand Down Expand Up @@ -153,6 +154,18 @@ protected boolean isDescriptionDeclare(String line) {
return line.startsWith(DESCRIPTION_COMMENT_PREFIX);
}

public Optional<ResourceRef> getDocs(ResourceResolver siblingResolver) {
return getTags()
.filter(this::isDocsDeclare)
.map(s -> s.substring(DOCS_COMMENT_PREFIX.length()))
.map(siblingResolver::resolve)
.findFirst();
}

protected boolean isDocsDeclare(String line) {
return line.startsWith(DOCS_COMMENT_PREFIX);
}

public Optional<String> getMain() {
List<String> mains = getTags()
.filter(this::isMainDeclare)
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/dev/jbang/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,9 @@ private static HttpURLConnection handleRedirects(HttpURLConnection httpConn, Con
throw new IOException("No 'Location' header in redirect");
}
URL url = new URL(httpConn.getURL(), location);
// TODO we should make this swizzler optional/configurable!
// Right now it assumes we're always trying to get Java
// source files which just isn't the case (eg //FILES)
url = new URL(swizzleURL(url.toString()));
verboseMsg("Redirected to: " + url); // Should be debug info
httpConn = (HttpURLConnection) url.openConnection();
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/dev/jbang/cli/TestInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

import java.net.URI;
import java.nio.file.Paths;
import java.util.Collection;

Expand Down Expand Up @@ -162,4 +163,22 @@ void testInfoStarSources() {
// assertThat(info.mainClass, equalTo("helloworld"));
assertThat(info.resolvedDependencies, empty());
}

@Test
void testInfoDocsFile() {
String src = examplesTestFolder.resolve("docstest1.java").toString();
CommandLine.ParseResult pr = JBang.getCommandLine().parseArgs("info", "docs", src);
Docs docs = (Docs) pr.subcommand().subcommand().commandSpec().userObject();
URI uri = docs.getDocsUri();
assertThat(uri.toString(), endsWith("/itests/readme.md"));
}

@Test
void testInfoDocsUrl() {
String src = examplesTestFolder.resolve("docstest2.java").toString();
CommandLine.ParseResult pr = JBang.getCommandLine().parseArgs("info", "docs", src);
Docs docs = (Docs) pr.subcommand().subcommand().commandSpec().userObject();
URI uri = docs.getDocsUri();
assertThat(uri.toString(), equalTo("https://www.jbang.dev/documentation/guide/latest/faq.html"));
}
}
2 changes: 1 addition & 1 deletion src/test/java/dev/jbang/cli/TestRun.java
Original file line number Diff line number Diff line change
Expand Up @@ -2563,7 +2563,7 @@ void testAliasArguments() throws IOException {
File f = examplesTestFolder.resolve("echo.java").toFile();
List<String> args = Arrays.asList("foo", "bar");
Alias alias = new Alias(f.toString(), null, args, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null);
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
CatalogUtil.addNearestAlias("echo", alias);

CommandLine.ParseResult pr = JBang.getCommandLine()
Expand Down
Loading