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