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/05/17 11:02:43 UTC

[camel] branch main updated (521c536116b -> dc9ebe6dd1d)

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

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


    from 521c536116b Sync deps
     new bcf60eab840 CAMEL-18118: camel-jbang - Linux terminal scripting using pipes
     new dc9ebe6dd1d CAMEL-18118: camel-jbang - Linux terminal scripting using pipes

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../modules/ROOT/pages/camel-jbang.adoc            | 59 ++++++++++++++++++----
 .../dsl/support/RouteBuilderLoaderSupport.java     | 55 ++++++++++++++++++++
 .../dsl/java/joor/ClassRoutesBuilderLoader.java    |  2 +-
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     |  2 +-
 .../dsl/jbang/core/commands/CamelJBangMain.java    | 17 +++++++
 .../core/commands/{Profile.java => Pipe.java}      | 20 ++++----
 .../apache/camel/dsl/jbang/core/commands/Run.java  | 14 ++++-
 .../dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java   |  8 +--
 .../camel/dsl/yaml/YamlRoutesBuilderLoader.java    |  2 +-
 .../dsl/yaml/YamlRoutesBuilderLoaderSupport.java   |  2 +-
 10 files changed, 151 insertions(+), 30 deletions(-)
 copy dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/{Profile.java => Pipe.java} (72%)


[camel] 02/02: CAMEL-18118: camel-jbang - Linux terminal scripting using pipes

Posted by da...@apache.org.
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 dc9ebe6dd1d1e73619dfd1ede2d7bc4e11afa16a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue May 17 13:00:42 2022 +0200

    CAMEL-18118: camel-jbang - Linux terminal scripting using pipes
---
 .../modules/ROOT/pages/camel-jbang.adoc            | 59 ++++++++++++++++++----
 .../dsl/support/RouteBuilderLoaderSupport.java     | 55 ++++++++++++++++++++
 .../dsl/java/joor/ClassRoutesBuilderLoader.java    |  2 +-
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     |  2 +-
 .../dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java   |  8 +--
 .../camel/dsl/yaml/YamlRoutesBuilderLoader.java    |  2 +-
 .../dsl/yaml/YamlRoutesBuilderLoaderSupport.java   |  2 +-
 7 files changed, 113 insertions(+), 17 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index 932f7be9a02..6881d7fecf9 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -206,15 +206,6 @@ This is a groovy route, which you can run with (or use `*`):
 camel run simple.groovy
 ----
 
-=== Running local Kamelets
-
-You can also use Camel JBang to try local Kamelets, without the need to publish them on GitHub or package them in a jar.
-
-[source,bash]
-----
-camel run --local-kamelet-dir=/path/to/local/kamelets earthquake.yaml
-----
-
 ==== Downloading routes form GitHub gists
 
 You can also download files from gists easily as shown:
@@ -297,6 +288,56 @@ For example. you can copy this to your clipboard and then run it afterwards:
 camel run clipboard.xml
 ----
 
+=== Scripting from terminal using pipes
+
+You can also execute a Camel JBang file as a script that can be used for terminal scripting with pipes and filters.
+
+This requires to add the following line in top of the file, for example as in the `upper.yaml` file below:
+
+[source,text]
+----
+///usr/bin/env jbang --quiet camel@apache/camel pipe "$0" "$@" ; exit $?
+
+# Will upper-case the input
+- from:
+    uri: "stream:in"
+    steps:
+      - setBody:
+          simple: "${body.toUpperCase()}"
+      - to: "stream:out"
+----
+
+To be able to execute this as a script, you need to set execute file permission:
+
+[source,bash]
+----
+chmod +x upper.yaml
+----
+
+Then you can then execute this as a script:
+
+[source,bash]
+----
+echo "Hello\nWorld" | ./upper.yaml
+----
+
+Which should output:
+
+[source,text]
+----
+HELLO
+WORLD
+----
+
+=== Running local Kamelets
+
+You can also use Camel JBang to try local Kamelets, without the need to publish them on GitHub or package them in a jar.
+
+[source,bash]
+----
+camel run --local-kamelet-dir=/path/to/local/kamelets earthquake.yaml
+----
+
 === Using platform-http component
 
 When a route is started from `platform-http` then Camel JBang will automatically include a VertX HTTP server
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index fe67a37cfa7..05aaae5d806 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -16,6 +16,12 @@
  */
 package org.apache.camel.dsl.support;
 
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -32,6 +38,9 @@ import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.RoutesBuilderLoader;
 import org.apache.camel.spi.StartupStepRecorder;
 import org.apache.camel.support.RoutesBuilderLoaderSupport;
+import org.apache.camel.util.IOHelper;
+
+import static org.apache.camel.util.IOHelper.buffered;
 
 /**
  * Base class for {@link RoutesBuilderLoader} implementations.
@@ -115,5 +124,51 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
         return builder;
     }
 
+    /**
+     * Gets the input stream to the resource
+     *
+     * @param resource  the resource
+     * @return  the input stream
+     */
+    protected InputStream resourceInputStream(Resource resource) throws IOException {
+        // load into memory as we need to skip a specific first-line if present
+        String data = loadResource(resource.getInputStream());
+        return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
+    }
+
+
+    /**
+     * Loads {@link RoutesBuilder} from {@link Resource} from the DSL implementation.
+     *
+     * @param  resource the resource to be loaded.
+     * @return          a {@link RoutesBuilder}
+     */
     protected abstract RouteBuilder doLoadRouteBuilder(Resource resource) throws Exception;
+
+    private static String loadResource(InputStream in) throws IOException {
+        StringBuilder builder = new StringBuilder();
+        InputStreamReader isr = new InputStreamReader(in);
+        boolean first = true;
+        try {
+            BufferedReader reader = IOHelper.buffered(isr);
+            while (true) {
+                String line = reader.readLine();
+                if (line != null) {
+                    // we need to skip first line if it starts with a special script marker for camel-jbang in pipe mode
+                    if (first && line.startsWith("///usr/bin/env jbang --quiet camel@apache/camel pipe")) {
+                        line = ""; // use an empty line so line numbers still matches
+                    }
+                    builder.append(line);
+                    builder.append("\n");
+                    first = false;
+                } else {
+                    break;
+                }
+            }
+            return builder.toString();
+        } finally {
+            IOHelper.close(isr, in);
+        }
+    }
+
 }
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
index b216f220d3d..c7eb34402f1 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
@@ -57,7 +57,7 @@ public class ClassRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport
         Map<String, byte[]> byteCodes = new LinkedHashMap<>();
         for (Resource res : resources) {
             String className = asClassName(res);
-            InputStream is = res.getInputStream();
+            InputStream is = resourceInputStream(res);
             if (is != null) {
                 byte[] code = is.readAllBytes();
                 byteCodes.put(className, code);
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index c157262cd00..238721e66eb 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -82,7 +82,7 @@ public class JavaRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport {
 
         Map<String, Resource> nameToResource = new HashMap<>();
         for (Resource resource : resources) {
-            try (InputStream is = resource.getInputStream()) {
+            try (InputStream is = resourceInputStream(resource)) {
                 if (is == null) {
                     throw new FileNotFoundException(resource.getLocation());
                 }
diff --git a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
index f20a0ac144f..48e3453d84d 100644
--- a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
+++ b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
@@ -50,28 +50,28 @@ public class JaxbXmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
             @Override
             public void configure() throws Exception {
                 // we use configure to load the routes
-                try (InputStream is = resource.getInputStream()) {
+                try (InputStream is = resourceInputStream(resource)) {
                     RouteTemplatesDefinition templates = loadRouteTemplatesDefinition(getCamelContext(), is);
                     if (templates != null) {
                         setRouteTemplateCollection(templates);
                     }
                 }
 
-                try (InputStream is = resource.getInputStream()) {
+                try (InputStream is = resourceInputStream(resource)) {
                     TemplatedRoutesDefinition templates = loadTemplatedRoutesDefinition(getCamelContext(), is);
                     if (templates != null) {
                         setTemplatedRouteCollection(templates);
                     }
                 }
 
-                try (InputStream is = resource.getInputStream()) {
+                try (InputStream is = resourceInputStream(resource)) {
                     RestsDefinition rests = loadRestsDefinition(getCamelContext(), is);
                     if (rests != null) {
                         setRestCollection(rests);
                     }
                 }
 
-                try (InputStream is = resource.getInputStream()) {
+                try (InputStream is = resourceInputStream(resource)) {
                     RoutesDefinition routes = loadRoutesDefinition(getCamelContext(), is);
                     if (routes != null) {
                         CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
index f63b5eb4d71..a6f8cea52ef 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
@@ -712,7 +712,7 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
             throw new FileNotFoundException("Resource not found: " + resource.getLocation());
         }
 
-        try (InputStream is = resource.getInputStream()) {
+        try (InputStream is = resourceInputStream(resource)) {
             LoadSettings local = LoadSettings.builder().setLabel(resource.getLocation()).build();
             final YamlDeserializationContext ctx = newYamlDeserializationContext(local, resource);
             final StreamReader reader = new StreamReader(local, new YamlUnicodeReader(is));
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java
index de84468b15f..f841970fa22 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java
@@ -76,7 +76,7 @@ public abstract class YamlRoutesBuilderLoaderSupport extends RouteBuilderLoaderS
             throw new FileNotFoundException("Resource not found: " + resource.getLocation());
         }
 
-        try (InputStream is = resource.getInputStream()) {
+        try (InputStream is = resourceInputStream(resource)) {
             // need a local settings because we want the label to be the resource we parse so the parser
             // can show parsing errors referring to actual resource file being parsed.
             LoadSettings local = LoadSettings.builder().setLabel(resource.getLocation()).build();


[camel] 01/02: CAMEL-18118: camel-jbang - Linux terminal scripting using pipes

Posted by da...@apache.org.
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 bcf60eab8409ab70169e12fccfb9e97892469341
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue May 17 10:56:31 2022 +0200

    CAMEL-18118: camel-jbang - Linux terminal scripting using pipes
---
 .../dsl/jbang/core/commands/CamelJBangMain.java    | 17 +++++++++++
 .../apache/camel/dsl/jbang/core/commands/Pipe.java | 35 ++++++++++++++++++++++
 .../apache/camel/dsl/jbang/core/commands/Run.java  | 14 +++++++--
 3 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 3d6896eb5fb..4df7651cfe6 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -54,6 +54,23 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("project", new Project()));
         */
 
+        // special for pipe mode
+        if (args.length == 2 && "pipe".equals(args[0])) {
+            Pipe pipe = new Pipe();
+            pipe.file = args[1];
+            if (pipe.file.startsWith("./")) {
+                pipe.file = pipe.file.substring(2);
+            }
+            int exitCode;
+            try {
+                exitCode = pipe.call();
+            } catch (Exception e) {
+                e.printStackTrace();
+                exitCode = 1;
+            }
+            System.exit(exitCode);
+        }
+
         commandLine.getCommandSpec().versionProvider(() -> {
             CamelCatalog catalog = new DefaultCamelCatalog();
             String v = catalog.getCatalogVersion();
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Pipe.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Pipe.java
new file mode 100644
index 00000000000..3051ca18158
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Pipe.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands;
+
+import picocli.CommandLine;
+
+import java.util.concurrent.Callable;
+
+@CommandLine.Command(name = "pipe", description = "Run Camel in pipe and filters mode for terminal scripting")
+class Pipe implements Callable<Integer> {
+
+    // the name of the file itself
+    String file;
+
+    @Override
+    public Integer call() throws Exception {
+        Run run = new Run();
+        return run.runPipe(file);
+    }
+
+}
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 4355f68f809..b6a1affaf49 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
@@ -83,6 +83,7 @@ class Run implements Callable<Integer> {
     private File lockFile;
     private ScheduledExecutorService executor;
     private boolean silentRun;
+    private boolean pipeRun;
 
     @Parameters(description = "The Camel file(s) to run. If no files specified then application.properties is used as source for which files to run.",
                 arity = "0..9")
@@ -186,6 +187,12 @@ class Run implements Callable<Integer> {
         return run();
     }
 
+    protected Integer runPipe(String file) throws Exception {
+        this.files = new String[]{file};
+        pipeRun = true;
+        return run();
+    }
+
     private void writeSetting(KameletMain main, Properties existing, String key, String value) {
         String val = existing != null ? existing.getProperty(key, value) : value;
         if (val != null) {
@@ -278,7 +285,7 @@ class Run implements Callable<Integer> {
             } else if (!silentRun && !source.exists()) {
                 System.out.println("Cannot run because application.properties file does not exist");
                 return 1;
-            } else {
+            } else if (silentRun) {
                 // silent-run then auto-detect all files
                 files = new File(".").list();
             }
@@ -332,6 +339,9 @@ class Run implements Callable<Integer> {
             // do not run for very long in silent run
             main.addInitialProperty("camel.main.autoStartup", "false");
             main.addInitialProperty("camel.main.durationMaxSeconds", "1");
+        } else if (pipeRun) {
+            // auto terminate if being idle
+            main.addInitialProperty("camel.main.durationMaxIdleSeconds", "1");
         }
         writeSetting(main, applicationProperties, "camel.main.durationMaxMessages",
                 () -> maxMessages > 0 ? String.valueOf(maxMessages) : null);
@@ -599,7 +609,7 @@ class Run implements Callable<Integer> {
     }
 
     private void configureLogging() throws Exception {
-        if (silentRun) {
+        if (silentRun || pipeRun) {
             RuntimeUtil.configureLog("off", false, false);
         } else if (logging) {
             RuntimeUtil.configureLog(loggingLevel, loggingColor, loggingJson);