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

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


The following commit(s) were added to refs/heads/main by this push:
     new d8f63a89f60 feat(dsl): camel jbang export property
d8f63a89f60 is described below

commit d8f63a89f602fa269abab2280a30f985df4bad3f
Author: Pasquale Congiusti <pasquale.congiu...@gmail.com>
AuthorDate: Thu Jan 23 11:53:15 2025 +0100

    feat(dsl): camel jbang export property
    
    You can now use `camel export --property xyz=abc`
    
    Closes CAMEL-21645
---
 .../camel/dsl/jbang/core/commands/Export.java      |   1 +
 .../dsl/jbang/core/commands/ExportBaseCommand.java |  35 ++++++-
 .../dsl/jbang/core/commands/ExportQuarkus.java     |   1 +
 .../apache/camel/dsl/jbang/core/commands/Run.java  |   2 +
 .../commands/ExportMainApplicationProperties.java  | 103 +++++++++++++++++++++
 .../camel/dsl/jbang/core/commands/ExportTest.java  |  21 +++++
 .../test/resources/sample-application.properties   |  18 ++++
 7 files changed, 180 insertions(+), 1 deletion(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
index ac095731f85..4884a23a4d1 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
@@ -160,6 +160,7 @@ public class Export extends ExportBaseCommand {
         cmd.excludes = this.excludes;
         cmd.ignoreLoadingError = this.ignoreLoadingError;
         cmd.lazyBean = this.lazyBean;
+        cmd.applicationProperties = this.applicationProperties;
         // run export
         return cmd.export();
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
index a298e022560..9312f91cc1f 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
@@ -218,6 +218,10 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
                         description = "Maven/Gradle build properties, ex. 
--build-property=prop1=foo")
     protected List<String> buildProperties = new ArrayList<>();
 
+    @CommandLine.Option(names = { "--property" },
+                        description = "Camel application properties, ex. 
--property=prop1=foo")
+    String[] applicationProperties;
+
     @CommandLine.Option(names = { "--logging" }, defaultValue = "false",
                         description = "Can be used to turn on logging (logs to 
file in <user home>/.camel directory)")
     protected boolean logging;
@@ -328,6 +332,8 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
         run.localKameletDir = localKameletDir;
         run.ignoreLoadingError = ignoreLoadingError;
         run.lazyBean = lazyBean;
+        run.property = applicationProperties;
+
         return run.runExport(ignoreLoadingError);
     }
 
@@ -699,6 +705,10 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
             customize.apply(prop2);
         }
 
+        // User properties
+        Properties prop3 = new CamelCaseOrderedProperties();
+        prepareUserProperties(prop3);
+
         FileOutputStream fos = new FileOutputStream(new File(targetDir, 
"application.properties"), false);
         try {
             for (Map.Entry<Object, Object> entry : prop2.entrySet()) {
@@ -727,6 +737,15 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
                         fos.write("\n".getBytes(StandardCharsets.UTF_8));
                     }
                 }
+                for (Map.Entry<Object, Object> entryUserProp : 
prop3.entrySet()) {
+                    String uK = entryUserProp.getKey().toString();
+                    String uV = entryUserProp.getValue().toString();
+                    String line = applicationPropertyLine(uK, uV);
+                    if (line != null && !line.isBlank()) {
+                        fos.write(line.getBytes(StandardCharsets.UTF_8));
+                        fos.write("\n".getBytes(StandardCharsets.UTF_8));
+                    }
+                }
             }
         } finally {
             IOHelper.close(fos);
@@ -734,7 +753,21 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
     }
 
     protected void prepareApplicationProperties(Properties properties) {
-        // noop
+        // NOOP
+    }
+
+    protected void prepareUserProperties(Properties properties) {
+        if (this.applicationProperties != null) {
+            for (String s : this.applicationProperties) {
+                String[] kv = s.split("=");
+                if (kv.length != 2) {
+                    // likely a user mistake, we warn the user
+                    printer().println("WARN: property '" + s + "'' has a bad 
format (should be 'key=value'), skipping.");
+                } else {
+                    properties.put(kv[0], kv[1]);
+                }
+            }
+        }
     }
 
     // Returns true if it has either an openapi spec or it uses contract-first 
DSL
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
index f12c9941562..f1865ee7bbc 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
@@ -148,6 +148,7 @@ class ExportQuarkus extends Export {
 
     @Override
     protected void prepareApplicationProperties(Properties properties) {
+        super.prepareApplicationProperties(properties);
         // quarkus native compilation only works if we specify each resource 
explicit
 
         StringJoiner sj = new StringJoiner(",");
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 12250485ab8..057810c7d92 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
@@ -951,6 +951,7 @@ public class Run extends CamelCommand {
         eq.loggingLevel = "off";
         eq.ignoreLoadingError = this.ignoreLoadingError;
         eq.lazyBean = this.lazyBean;
+        eq.applicationProperties = this.property;
 
         printer().println("Running using Quarkus v" + eq.quarkusVersion + " 
(preparing and downloading files)");
 
@@ -1026,6 +1027,7 @@ public class Run extends CamelCommand {
         eq.loggingLevel = "off";
         eq.ignoreLoadingError = this.ignoreLoadingError;
         eq.lazyBean = this.lazyBean;
+        eq.applicationProperties = this.property;
 
         printer().println("Running using Spring Boot v" + eq.springBootVersion 
+ " (preparing and downloading files)");
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainApplicationProperties.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainApplicationProperties.java
new file mode 100644
index 00000000000..4a44484d77b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportMainApplicationProperties.java
@@ -0,0 +1,103 @@
+/*
+ * 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 java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import org.apache.camel.dsl.jbang.core.common.RuntimeType;
+import org.apache.camel.util.FileUtil;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import picocli.CommandLine;
+
+class ExportMainApplicationProperties {
+
+    private File workingDir;
+    private File profile = new File(".", "application.properties");
+
+    @BeforeEach
+    public void setup() throws IOException {
+        Path base = Paths.get("target");
+        workingDir = Files.createTempDirectory(base, "camel-export").toFile();
+    }
+
+    @AfterEach
+    public void end() throws IOException {
+        // force removing, since deleteOnExit is not removing.
+        FileUtil.removeDir(workingDir);
+        FileUtil.deleteFile(profile);
+    }
+
+    private static Stream<Arguments> runtimeProvider() {
+        return Stream.of(
+                Arguments.of(RuntimeType.quarkus),
+                Arguments.of(RuntimeType.springBoot),
+                Arguments.of(RuntimeType.main));
+    }
+
+    @ParameterizedTest
+    @MethodSource("runtimeProvider")
+    public void shouldExportUserPropertyOverride(RuntimeType rt) throws 
Exception {
+        // prepare as we need application.properties that contains 
configuration to be overridden
+        Files.copy(
+                new 
File("src/test/resources/sample-application.properties").toPath(),
+                profile.toPath(),
+                StandardCopyOption.REPLACE_EXISTING);
+
+        // We need a real file as we want to test the generated content
+        Export command = createCommand(rt,
+                new String[] { "src/test/resources/route.yaml", 
"src/test/resources/sample-application.properties" },
+                "--gav=examples:route:1.0.0", "--dir=" + workingDir, "--quiet",
+                "--property", "hello=test");
+        int exit = command.doCall();
+
+        Assertions.assertEquals(0, exit);
+        // Application properties
+        File appProperties = new File(workingDir + "/src/main/resources", 
"application.properties");
+        Assertions.assertTrue(appProperties.exists(), "Missing application 
properties");
+        Properties appProps = new Properties();
+        appProps.load(new FileInputStream(appProperties));
+        Assertions.assertEquals("test", appProps.getProperty("hello"));
+        Assertions.assertEquals("true", 
appProps.getProperty("another.property"));
+    }
+
+    private Export createCommand(RuntimeType rt, String[] files, String... 
args) {
+        Export command = new Export(new CamelJBangMain());
+        CommandLine.populateCommand(command, "--gav=examples:route:1.0.0", 
"--dir=" + workingDir, "--quiet",
+                "--runtime=%s".formatted(rt.runtime()));
+        if (args != null) {
+            CommandLine.populateCommand(command, args);
+        }
+        command.files = Arrays.asList(files);
+        return command;
+    }
+
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
index bd50898cd9f..1c5a760d3b5 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
@@ -25,6 +25,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Properties;
 import java.util.stream.Stream;
 
 import org.apache.camel.dsl.jbang.core.common.RuntimeType;
@@ -483,4 +484,24 @@ class ExportTest {
         }
     }
 
+    @ParameterizedTest
+    @MethodSource("runtimeProvider")
+    public void shouldExportUserProperty(RuntimeType rt) throws Exception {
+        // We need a real file as we want to test the generated content
+        Export command = createCommand(rt, new String[] { 
"src/test/resources/route.yaml" },
+                "--gav=examples:route:1.0.0", "--dir=" + workingDir, "--quiet",
+                "--property", "hello=world");
+        int exit = command.doCall();
+
+        Assertions.assertEquals(0, exit);
+        // In this test we can validate any generic resource that must be 
created along the export.
+        // Exporting once to reduce the time to execute the test and the 
resource required to test.
+
+        // Application properties
+        File appProperties = new File(workingDir + "/src/main/resources", 
"application.properties");
+        Assertions.assertTrue(appProperties.exists(), "Missing application 
properties");
+        Properties appProps = new Properties();
+        appProps.load(new FileInputStream(appProperties));
+        Assertions.assertEquals("world", appProps.getProperty("hello"));
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/sample-application.properties
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/sample-application.properties
new file mode 100644
index 00000000000..3ce094edbd6
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/sample-application.properties
@@ -0,0 +1,18 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+hello=world
+another.property=true
\ No newline at end of file

Reply via email to