You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/01/25 09:23:36 UTC

[camel] 01/02: CAMEL-17280: camel-jbang - Run from github using wildcards

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit b89f2238f936116e18d1c7a2514117a67830879b
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Jan 25 10:12:34 2022 +0100

    CAMEL-17280: camel-jbang - Run from github using wildcards
---
 .../apache/camel/dsl/jbang/core/commands/Run.java  | 135 ++++++++++++++++++++-
 1 file changed, 131 insertions(+), 4 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index 2283fe1..e0bf1f6 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -18,17 +18,26 @@ package org.apache.camel.dsl.jbang.core.commands;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
 import java.nio.file.FileSystems;
+import java.time.Duration;
 import java.util.StringJoiner;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.camel.CamelContext;
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
 import org.apache.camel.main.KameletMain;
 import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.util.AntPathMatcher;
+import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.ObjectHelper;
 import picocli.CommandLine.Command;
 import picocli.CommandLine.Option;
@@ -44,7 +53,7 @@ class Run implements Callable<Integer> {
     private String[] files;
 
     //CHECKSTYLE:OFF
-    @Option(names = { "-h", "--help" }, usageHelp = true, description = "Display the help and sub-commands")
+    @Option(names = {"-h", "--help"}, usageHelp = true, description = "Display the help and sub-commands")
     private boolean helpRequested;
     //CHECKSTYLE:ON
 
@@ -220,7 +229,33 @@ class Run implements Callable<Integer> {
 
             // automatic map github https urls to github resolver
             if (file.startsWith("https://github.com/")) {
-                file = mapGithubUrl(file);
+                String ext = FileUtil.onlyExt(file);
+                boolean wildcard = FileUtil.onlyName(file, false).contains("*");
+                if (ext != null && !wildcard) {
+                    // it is a single file so map to
+                    file = asGithubSingleUrl(file);
+                } else {
+                    StringJoiner files = new StringJoiner(",");
+                    StringJoiner kamelets = new StringJoiner(",");
+                    StringJoiner properties = new StringJoiner(",");
+                    fetchGithubUrls(file, files, kamelets, properties);
+
+                    if (files.length() > 0) {
+                        file = files.toString();
+                    }
+                    if (properties.length() > 0) {
+                        main.addInitialProperty("camel.component.properties.location", properties.toString());
+                    }
+                    if (kamelets.length() > 0) {
+                        String loc = main.getInitialProperties().getProperty("camel.component.kamelet.location");
+                        if (loc != null) {
+                            loc = loc + "," + kamelets;
+                        } else {
+                            loc = kamelets.toString();
+                        }
+                        main.addInitialProperty("camel.component.kamelet.location", loc);
+                    }
+                }
             }
 
             js.add(file);
@@ -253,7 +288,14 @@ class Run implements Callable<Integer> {
                 }
                 locations.append(file).append(",");
             }
-            main.addInitialProperty("camel.component.properties.location", locations.toString());
+            // there may be existing properties
+            String loc = main.getInitialProperties().getProperty("camel.component.properties.location");
+            if (loc != null) {
+                loc = loc + "," + locations;
+            } else {
+                loc = locations.toString();
+            }
+            main.addInitialProperty("camel.component.properties.location", loc);
         }
 
         System.out.println("Starting CamelJBang");
@@ -277,7 +319,7 @@ class Run implements Callable<Integer> {
         return lockFile;
     }
 
-    private static String mapGithubUrl(String url) {
+    private static String asGithubSingleUrl(String url) throws Exception {
         // strip https://github.com/
         url = url.substring(19);
         // https://github.com/apache/camel-k/blob/main/examples/languages/routes.kts
@@ -288,4 +330,89 @@ class Run implements Callable<Integer> {
         url = url.replaceFirst("/", ":");
         return "github:" + url;
     }
+
+    private static void fetchGithubUrls(String url, StringJoiner files, StringJoiner kamelets, StringJoiner properties)
+            throws Exception {
+        // this is a directory, so we need to query github which files are there and filter them
+
+        // URL: https://api.github.com/repos/apache/camel-k/contents/examples/kamelets/kameletbindings
+        // URL: https://api.github.com/repos/apache/camel-k/contents/examples/kamelets/kameletbindings?ref=v1.7.0
+        // https://github.com/apache/camel-k/tree/main/examples/kamelets/kameletbindings
+        // https://github.com/apache/camel-k/tree/v1.7.0/examples/kamelets/kameletbindings
+
+        // strip https://github.com/
+        url = url.substring(19);
+
+        String[] parts = url.split("/");
+        if (parts.length < 5) {
+            return;
+        }
+
+        String org = parts[0];
+        String repo = parts[1];
+        String action = parts[2];
+        String branch = parts[3];
+        String path;
+        String wildcard = null;
+        StringJoiner sj = new StringJoiner("/");
+        for (int i = 4; i < parts.length; i++) {
+            if (i == parts.length - 1) {
+                // last element uses wildcard to filter which files to include
+                if (parts[i].contains("*")) {
+                    wildcard = parts[i];
+                    break;
+                }
+            }
+            sj.add(parts[i]);
+        }
+        path = sj.toString();
+
+        if ("tree".equals(action)) {
+            // https://api.github.com/repos/apache/camel-k/contents/examples/kamelets/kameletbindings?ref=v1.7.0
+            url = "https://api.github.com/repos/" + org + "/" + repo + "/contents/" + path;
+            if (!"main".equals(branch) && !"master".equals(branch)) {
+                url = url + "?ref=" + branch;
+            }
+        }
+
+        downloadGithubFiles(url, wildcard, files, kamelets, properties);
+    }
+
+    private static void downloadGithubFiles(
+            String url, String wildcard, StringJoiner files, StringJoiner kamelets, StringJoiner properties)
+            throws Exception {
+
+        // use JDK http client to call github api
+        HttpClient hc = HttpClient.newHttpClient();
+        HttpResponse<String> res = hc.send(HttpRequest.newBuilder(new URI(url)).timeout(Duration.ofSeconds(20)).build(),
+                HttpResponse.BodyHandlers.ofString());
+
+        if (res.statusCode() == 200) {
+            ObjectMapper mapper = new ObjectMapper();
+            JsonNode root = mapper.readTree(res.body());
+            for (JsonNode c : root) {
+                String name = c.get("name").asText();
+                String ext = FileUtil.onlyExt(name, false);
+                boolean match = wildcard == null || AntPathMatcher.INSTANCE.match(wildcard, name, false);
+                if (match) {
+                    if ("kamelet.yaml".equalsIgnoreCase(ext)) {
+                        String htmlUrl = c.get("html_url").asText();
+                        String u = asGithubSingleUrl(htmlUrl);
+                        kamelets.add(u);
+                    } else if ("properties".equalsIgnoreCase(ext)) {
+                        String htmlUrl = c.get("html_url").asText();
+                        String u = asGithubSingleUrl(htmlUrl);
+                        properties.add(u);
+                    } else if ("java".equalsIgnoreCase(ext) || "xml".equalsIgnoreCase(ext) || "yaml".equalsIgnoreCase(ext)
+                            || "groovy".equalsIgnoreCase(ext) || "js".equalsIgnoreCase(ext) || "jsh".equalsIgnoreCase(ext)
+                            || "kts".equalsIgnoreCase(ext)) {
+                        String htmlUrl = c.get("html_url").asText();
+                        String u = asGithubSingleUrl(htmlUrl);
+                        files.add(u);
+                    }
+                }
+            }
+        }
+    }
+
 }