Skip to content

feat: Added support for script dependencies #1641

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

Merged
merged 9 commits into from
Jul 8, 2023
8 changes: 8 additions & 0 deletions itests/onedep.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS Two.java

public class onedep {
public static void main(String... args) {
Two.main();
}
}
2 changes: 1 addition & 1 deletion src/main/java/dev/jbang/cli/Build.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public Integer doCall() throws IOException {

ProjectBuilder pb = createProjectBuilderForBuild();
Project prj = pb.build(scriptMixin.scriptOrFile);
prj.codeBuilder(BuildContext.forProject(prj, buildDir)).build();
Project.codeBuilder(BuildContext.forProject(prj, buildDir)).build();

return EXIT_OK;
}
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/dev/jbang/cli/Edit.java
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,7 @@ public Integer doCall() throws IOException {
throw new ExitException(EXIT_INVALID_INPUT, "You can only edit source files");
}

Path project = createProjectForLinkedEdit(prj, Collections
.emptyList(),
false);
Path project = createProjectForLinkedEdit(prj, Collections.emptyList(), false);
String projectPathString = pathToString(project.toAbsolutePath());
// err.println(project.getAbsolutePath());

Expand Down Expand Up @@ -394,7 +392,7 @@ Path createProjectForLinkedEdit(Project prj, List<String> arguments, boolean rel
Path originalFile = prj.getResourceRef().getFile();

List<String> dependencies = prj.getMainSourceSet().getDependencies();
String cp = prj.resolveClassPath().getClassPath();
String cp = BuildContext.forProject(prj).resolveClassPath().getClassPath();
List<String> resolvedDependencies = Arrays.asList(cp.split(CP_SEPARATOR));

Path baseDir = Settings.getCacheDir(Cache.CacheClass.projects);
Expand Down
33 changes: 19 additions & 14 deletions src/main/java/dev/jbang/cli/Export.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ public Integer doCall() throws IOException {
ProjectBuilder pb = createProjectBuilder(exportMixin);
Project prj = pb.build(exportMixin.scriptMixin.scriptOrFile);
BuildContext ctx = BuildContext.forProject(prj);
prj.codeBuilder(ctx).build();
Project.codeBuilder(ctx).build();
if (prj.getResourceRef() instanceof AliasResourceResolver.AliasedResourceRef) {
Alias alias = ((AliasResourceResolver.AliasedResourceRef) prj.getResourceRef()).getAlias();
if (prj.getMainClass() == null) {
prj.setMainClass(alias.mainClass);
}
}
return apply(prj, ctx);
return apply(ctx);
}

abstract int apply(Project prj, BuildContext ctx) throws IOException;
abstract int apply(BuildContext ctx) throws IOException;

protected ProjectBuilder createProjectBuilder(ExportMixin exportMixin) {
return Project
Expand Down Expand Up @@ -108,7 +108,7 @@ Path getJarOutputPath() {
class ExportLocal extends BaseExportCommand {

@Override
int apply(Project prj, BuildContext ctx) throws IOException {
int apply(BuildContext ctx) throws IOException {
// Copy the JAR
Path source = ctx.getJarFile();
Path outputPath = getJarOutputPath();
Expand All @@ -126,7 +126,8 @@ int apply(Project prj, BuildContext ctx) throws IOException {

// Update the JAR's MANIFEST.MF Class-Path to point to
// its dependencies
String newPath = prj.resolveClassPath().getManifestPath();
Project prj = ctx.getProject();
String newPath = ctx.resolveClassPath().getManifestPath();
if (!newPath.isEmpty()) {
Util.infoMsg("Updating jar...");
String javaVersion = exportMixin.buildMixin.javaVersion != null
Expand All @@ -146,7 +147,7 @@ class ExportPortable extends BaseExportCommand {
public static final String LIB = "lib";

@Override
int apply(Project prj, BuildContext ctx) throws IOException {
int apply(BuildContext ctx) throws IOException {
// Copy the JAR
Path source = ctx.getJarFile();
Path outputPath = getJarOutputPath();
Expand All @@ -162,7 +163,8 @@ int apply(Project prj, BuildContext ctx) throws IOException {
}

Files.copy(source, outputPath);
List<ArtifactInfo> deps = prj.resolveClassPath().getArtifacts();
Project prj = ctx.getProject();
List<ArtifactInfo> deps = ctx.resolveClassPath().getArtifacts();
if (!deps.isEmpty()) {
// Copy dependencies to "./lib" dir
Path libDir = outputPath.getParent().resolve(LIB);
Expand Down Expand Up @@ -197,7 +199,7 @@ class ExportMavenPublish extends BaseExportCommand {
String version;

@Override
int apply(Project prj, BuildContext ctx) throws IOException {
int apply(BuildContext ctx) throws IOException {
Path outputPath = exportMixin.outputFile;

if (outputPath == null) {
Expand All @@ -219,6 +221,7 @@ int apply(Project prj, BuildContext ctx) throws IOException {
}
}

Project prj = ctx.getProject();
if (prj.getGav().isPresent()) {
MavenCoordinate coord = MavenCoordinate.fromString(prj.getGav().get()).withVersion();
if (group == null) {
Expand Down Expand Up @@ -283,7 +286,7 @@ int apply(Project prj, BuildContext ctx) throws IOException {
.data("artifact", artifact)
.data("version", version)
.data("description", prj.getDescription().orElse(""))
.data("dependencies", prj.resolveClassPath().getArtifacts())
.data("dependencies", ctx.resolveClassPath().getArtifacts())
.render();
Util.infoMsg("Writing " + pomPath);
Util.writeString(pomPath, pomfile);
Expand All @@ -299,7 +302,7 @@ int apply(Project prj, BuildContext ctx) throws IOException {
class ExportNative extends BaseExportCommand {

@Override
int apply(Project prj, BuildContext ctx) throws IOException {
int apply(BuildContext ctx) throws IOException {
// Copy the native binary
Path source = ctx.getNativeImageFile();
Path outputPath = getNativeOutputPath();
Expand Down Expand Up @@ -340,7 +343,7 @@ Path getNativeOutputPath() {
class ExportFatjar extends BaseExportCommand {

@Override
int apply(Project prj, BuildContext ctx) throws IOException {
int apply(BuildContext ctx) throws IOException {
// Copy the native binary
Path source = ctx.getJarFile();
Path outputPath = getFatjarOutputPath();
Expand All @@ -355,7 +358,8 @@ int apply(Project prj, BuildContext ctx) throws IOException {
Util.mkdirs(outputPath.getParent());
}

List<ArtifactInfo> deps = prj.resolveClassPath().getArtifacts();
Project prj = ctx.getProject();
List<ArtifactInfo> deps = ctx.resolveClassPath().getArtifacts();
if (!deps.isEmpty()) {
// Extract main jar and all dependencies to a temp dir
Path tmpDir = Files.createTempDirectory("fatjar");
Expand Down Expand Up @@ -417,8 +421,9 @@ protected ProjectBuilder createProjectBuilder(ExportMixin exportMixin) {
}

@Override
int apply(Project prj, BuildContext ctx) throws IOException {
List<ArtifactInfo> artifacts = prj.resolveClassPath().getArtifacts();
int apply(BuildContext ctx) throws IOException {
Project prj = ctx.getProject();
List<ArtifactInfo> artifacts = ctx.resolveClassPath().getArtifacts();
List<ArtifactInfo> nonMods = artifacts
.stream()
.filter(a -> !ModuleUtil.isModule(a.getFile()))
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/dev/jbang/cli/Info.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,14 @@ static class ScriptInfo {
String gav;
String module;

public ScriptInfo(Project prj, BuildContext ctx, boolean assureJdkInstalled) {
public ScriptInfo(BuildContext ctx, boolean assureJdkInstalled) {
Project prj = ctx.getProject();
originalResource = prj.getResourceRef().getOriginalResource();

if (scripts.add(originalResource)) {
backingResource = prj.getResourceRef().getFile().toString();

init(prj);
init(ctx);

applicationJar = ctx.getJarFile() == null ? null
: ctx.getJarFile().toAbsolutePath().toString();
Expand All @@ -125,7 +126,7 @@ public ScriptInfo(Project prj, BuildContext ctx, boolean assureJdkInstalled) {
// Ignore
}

List<ArtifactInfo> artifacts = prj.resolveClassPath().getArtifacts();
List<ArtifactInfo> artifacts = ctx.resolveClassPath().getArtifacts();
if (artifacts.isEmpty()) {
resolvedDependencies = Collections.emptyList();
} else {
Expand Down Expand Up @@ -153,8 +154,9 @@ public ScriptInfo(Project prj, BuildContext ctx, boolean assureJdkInstalled) {
}
}

private void init(Project prj) {
List<String> deps = prj.resolveClassPath().getClassPaths();
private void init(BuildContext ctx) {
Project prj = ctx.getProject();
List<String> deps = ctx.resolveClassPath().getClassPaths();
if (!deps.isEmpty()) {
dependencies = deps;
}
Expand Down Expand Up @@ -213,7 +215,7 @@ ScriptInfo getInfo(boolean assureJdkInstalled) {

scripts = new HashSet<>();

return new ScriptInfo(prj, BuildContext.forProject(prj, buildDir), assureJdkInstalled);
return new ScriptInfo(BuildContext.forProject(prj, buildDir), assureJdkInstalled);
}

ProjectBuilder createProjectBuilder() {
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/dev/jbang/cli/Run.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ public Integer doCall() throws IOException {
}

BuildContext ctx = BuildContext.forProject(prj, buildDir);
CmdGeneratorBuilder genb = prj.codeBuilder(ctx).build();
CmdGeneratorBuilder genb = Project.codeBuilder(ctx).build();

buildAgents(prj, ctx);
buildAgents(ctx);

String cmdline = updateGeneratorForRun(genb).build().generate();

Expand All @@ -104,7 +104,8 @@ public Integer doCall() throws IOException {
return EXIT_EXECUTE;
}

void buildAgents(Project prj, BuildContext ctx) throws IOException {
void buildAgents(BuildContext ctx) throws IOException {
Project prj = ctx.getProject();
Map<String, String> agents = runMixin.javaAgentSlots;
if (agents == null && prj.getResourceRef() instanceof AliasResourceResolver.AliasedResourceRef) {
AliasResourceResolver.AliasedResourceRef aref = (AliasResourceResolver.AliasedResourceRef) prj.getResourceRef();
Expand All @@ -125,7 +126,7 @@ void buildAgents(Project prj, BuildContext ctx) throws IOException {
ProjectBuilder apb = createBaseProjectBuilder();
Project aprj = apb.build(javaAgent);
BuildContext actx = BuildContext.forProject(aprj);
aprj.codeBuilder(actx).build();
Project.codeBuilder(actx).build();
runMixin.javaRuntimeOptions.addAll(javaAgentOptions(actx, javaAgentOptions));
}
}
Expand Down
12 changes: 0 additions & 12 deletions src/main/java/dev/jbang/dependencies/DependencyCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
Expand Down Expand Up @@ -111,16 +109,6 @@ public static List<ArtifactInfo> findDependenciesByHash(String depsHash) {
return null;
}

public static ArtifactInfo findArtifactByPath(Path artifactPath) {
Map<String, List<ArtifactInfo>> cache = getCache();
Optional<ArtifactInfo> result = cache .values()
.stream()
.flatMap(Collection::stream)
.filter(art -> art.getFile().equals(artifactPath))
.findFirst();
return result.orElseGet(() -> new ArtifactInfo(null, artifactPath));
}

public static void clear() {
depCache = null;
}
Expand Down
30 changes: 10 additions & 20 deletions src/main/java/dev/jbang/dependencies/DependencyResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
public class DependencyResolver {
private final Set<MavenRepo> repositories;
private final Set<String> dependencies;
private final Set<ArtifactInfo> artifacts;
private final Set<String> classPaths;

public DependencyResolver() {
repositories = new LinkedHashSet<>();
dependencies = new LinkedHashSet<>();
artifacts = new LinkedHashSet<>();
classPaths = new LinkedHashSet<>();
}

public DependencyResolver addRepository(MavenRepo repository) {
Expand Down Expand Up @@ -50,19 +50,9 @@ public DependencyResolver addDependencies(List<String> dependencies) {
return this;
}

public DependencyResolver addArtifact(ArtifactInfo artifact) {
artifacts.add(artifact);
return this;
}

public DependencyResolver addArtifacts(List<ArtifactInfo> artifacts) {
this.artifacts.addAll(artifacts);
return this;
}

public DependencyResolver addClassPath(String classPath) {
// WARN need File here because it's more lenient about paths than Path!
return addArtifact(DependencyCache.findArtifactByPath(new File(classPath).toPath()));
classPaths.add(classPath);
return this;
}

public DependencyResolver addClassPaths(List<String> classPaths) {
Expand All @@ -72,18 +62,18 @@ public DependencyResolver addClassPaths(List<String> classPaths) {
return this;
}

public DependencyResolver addClassPaths(String classPaths) {
return addClassPaths(Arrays.asList(classPaths.split(" ")));
}

public ModularClassPath resolve() {
ModularClassPath mcp = DependencyUtil.resolveDependencies(
new ArrayList<>(dependencies), new ArrayList<>(repositories),
Util.isOffline(), Util.isFresh(), !Util.isQuiet(), Util.downloadSources());
if (artifacts.isEmpty()) {
if (classPaths.isEmpty()) {
return mcp;
} else {
List<ArtifactInfo> arts = Stream.concat(mcp.getArtifacts().stream(), artifacts.stream())
// WARN need File here because it's more lenient about paths than Path!
Stream<ArtifactInfo> cpas = classPaths
.stream()
.map(p -> new ArtifactInfo(null, new File(p).toPath()));
List<ArtifactInfo> arts = Stream.concat(mcp.getArtifacts().stream(), cpas)
.collect(Collectors.toList());
return new ModularClassPath(arts);
}
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/dev/jbang/dependencies/DependencyUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ public class DependencyUtil {
}

public static final Pattern fullGavPattern = Pattern.compile(
"^(?<groupid>[^:]*):(?<artifactid>[^:]*):(?<version>[^:@]*)(:(?<classifier>[^@]*))?(@(?<type>.*))?$");
"^(?<groupid>[a-z0-9_.-]*):(?<artifactid>[a-z0-9_.-]*):(?<version>[^:@]*)(:(?<classifier>[^@]*))?(@(?<type>.*))?$");

public static final Pattern lenientGavPattern = Pattern.compile(
"^(?<groupid>[a-z0-9_.-]*):(?<artifactid>[a-z0-9_.-]*)(:(?<version>[^:@]*)(:(?<classifier>[^@]*))?)?(@(?<type>.*))?$");

private DependencyUtil() {
}
Expand Down Expand Up @@ -145,6 +148,12 @@ public static boolean looksLikeAGav(String candidate) {
return (gav.matches());
}

public static boolean looksLikeAPossibleGav(String candidate) {
Matcher gav = lenientGavPattern.matcher(candidate);
gav.find();
return (gav.matches());
}

public static String formatVersion(String version) {
// replace + with open version range for maven
if (version != null && version.endsWith("+")) {
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/dev/jbang/dependencies/JitPackUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@

public class JitPackUtil {
private static final Pattern GITHUB_TREE_PATTERN = Pattern.compile(
"^https?://github.com/(.+?)/(.+?)(/tree/(.+?)(/(.+?))?)?/?$");
"^https?://github.com/([^/]+?)/([^/]+?)(/tree/([^/]+?)(/(.+?))?)?/?$");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these patterns changing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because they are too lenient, they match URLs that are not valid JitPack URLs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example it will match https://github.com/jbangdev/jbang/blob/main/itests/SankeyPlotTest.java , even though that's obviously neither a "tree" nor a "commit".

private static final Pattern GITUB_COMMIT_PATTERN = Pattern.compile(
"^https?://github.com/(.+?)/(.+?)/commit/(.+)$");
"^https?://github.com/([^/]+?)/([^/]+?)/commit/(.+)$");
private static final Pattern GITLAB_TREE_PATTERN = Pattern.compile(
"^https?://gitlab.com/(.+?)/(.+?)(/-/tree/(.+?)(/(.+?))?)?/?$");
"^https?://gitlab.com/([^/]+?)/([^/]+?)(/-/tree/([^/]+?)(/(.+?))?)?/?$");
private static final Pattern GITLAB_COMMIT_PATTERN = Pattern.compile(
"^https?://gitlab.com/(.+?)/(.+?)/-/commit/(.+)$");
"^https?://gitlab.com/([^/]+?)/([^/]+?)/-/commit/(.+)$");
private static final Pattern BITBUCKET_TREE_PATTERN = Pattern.compile(
"^https?://bitbucket.org/(.+?)/(.+?)(/src/(.+?)(/(.+?))?)?/?$");
"^https?://bitbucket.org/([^/]+?)/([^/]+?)(/src/([^/]+?)(/(.+?))?)?/?$");
private static final Pattern BITBUCKET_COMMIT_PATTERN = Pattern.compile(
"^https?://bitbucket.org/(.+?)/(.+?)/commits/(.+)$");
"^https?://bitbucket.org/([^/]+?)/([^/]+?)/commits/(.+)$");

private static final Pattern POSSIBLE_SHA1_PATTERN = Pattern.compile("^[0-9a-f]{40}$");

Expand Down
Loading