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
The following commit(s) were added to refs/heads/main by this push:
new f2c282236eb6 CAMEL-26930: camel-jbang - --exclude matches a path, and
applies to the files of a source directory (#29951)
f2c282236eb6 is described below
commit f2c282236eb62eb5e2525420d9ba48ed73f9aaba
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Nov 14 21:57:22 2026 +0100
CAMEL-26930: camel-jbang - --exclude matches a path, and applies to the
files of a source directory (#29951)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../resources/golden/expected/excludes.run.txt | 2 +
.../camel/dsl/jbang/run/CamelMainRunner.java | 2 +-
.../org/apache/camel/dsl/jbang/run/RunFiles.java | 7 ++-
.../apache/camel/dsl/jbang/run/RunPipeline.java | 58 +++++++++++++++++++++-
.../apache/camel/dsl/jbang/run/RunFilesTest.java | 11 ++++
.../dsl/jbang/run/RunPipelineExcludeTest.java | 53 ++++++++++++++++++++
6 files changed, 130 insertions(+), 3 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.run.txt
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.run.txt
index 580480158ee4..84556027b723 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.run.txt
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.run.txt
@@ -19,6 +19,7 @@ camel.jbang.javaVersion=21
camel.jbang.kameletsVersion=${kamelets.version}
camel.main.name=excludes
camel.main.routesIncludePattern=file\:src/test/resources/golden/excludes/**?optional\=true
+camel.main.routesExcludePattern=file\:src/test/resources/golden/excludes/**/*.xml
# initial properties
camel.component.kamelet.location=classpath:kamelets
@@ -38,6 +39,7 @@ camel.jbang.springBootVersion=${spring-boot.version}
camel.jbang.verbose=false
camel.main.modeline=true
camel.main.name=excludes
+camel.main.routesExcludePattern=file:src/test/resources/golden/excludes/**/*.xml
camel.main.routesIncludePattern=file:src/test/resources/golden/excludes/**?optional=true
# override properties
diff --git
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/CamelMainRunner.java
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/CamelMainRunner.java
index 03616347461d..618c621fee74 100644
---
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/CamelMainRunner.java
+++
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/CamelMainRunner.java
@@ -267,7 +267,7 @@ final class CamelMainRunner {
boolean recursive;
if (request.sourceDir != null) {
reloadDir = request.sourceDir;
- pattern = RunPipeline.sourceDirReloadPattern(request.dataDir);
+ pattern = RunPipeline.sourceDirReloadPattern(request.dataDir) +
RunPipeline.reloadExcludes(request.excludes);
recursive = true;
} else {
// the folder that has all the files, not the one of the first
file in another folder (CAMEL-26930)
diff --git
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunFiles.java
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunFiles.java
index 86f4b3a30c57..bdee1f27ee68 100644
---
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunFiles.java
+++
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunFiles.java
@@ -148,6 +148,11 @@ public final class RunFiles {
return false;
}
+ // the path as given, for an exclude with a folder such as routes/**
(CAMEL-26930)
+ String given = name.replace('\\', '/');
+ while (given.startsWith("./")) {
+ given = given.substring(2);
+ }
// flatten file
name = FileUtil.stripPath(name);
@@ -184,7 +189,7 @@ public final class RunFiles {
}
// is the file excluded?
- if (isExcluded(name, excludes)) {
+ if (isExcluded(name, excludes) || isExcluded(given, excludes)) {
return true;
}
diff --git
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunPipeline.java
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunPipeline.java
index 08d35933ecbd..d6f175afe159 100644
---
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunPipeline.java
+++
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/RunPipeline.java
@@ -760,6 +760,16 @@ public class RunPipeline {
String sdir = "file:" + request.sourceDir + "/**?optional=true";
main.addInitialProperty("camel.main.routesIncludePattern", sdir);
writeSettings("camel.main.routesIncludePattern", sdir);
+ String excluded = sourceDirExcludePattern(request.sourceDir,
request.excludes);
+ if (excluded != null) {
+ // --exclude applies to the files of the directory too
(CAMEL-26930)
+ String existing =
main.getInitialProperties().getProperty("camel.main.routesExcludePattern");
+ if (existing != null && !existing.isBlank()) {
+ excluded = existing + "," + excluded;
+ }
+ main.addInitialProperty("camel.main.routesExcludePattern",
excluded);
+ writeSettings("camel.main.routesExcludePattern", excluded);
+ }
} else if (js.length() > 0) {
main.addInitialProperty("camel.main.routesIncludePattern",
js.toString());
writeSettings("camel.main.routesIncludePattern", js.toString());
@@ -1164,7 +1174,8 @@ public class RunPipeline {
if (request.sourceDir != null) {
main.addInitialProperty(SOURCE_DIR, request.sourceDir);
main.addInitialProperty("camel.main.routesReloadDirectory",
request.sourceDir);
- main.addInitialProperty("camel.main.routesReloadPattern",
sourceDirReloadPattern(request.dataDir));
+ main.addInitialProperty("camel.main.routesReloadPattern",
+ sourceDirReloadPattern(request.dataDir) +
reloadExcludes(request.excludes));
main.addInitialProperty("camel.main.routesReloadDirectoryRecursive", "true");
} else {
dataDirWithoutSourceDir.run();
@@ -1238,6 +1249,51 @@ public class RunPipeline {
return answer != null ? answer : a.getRoot();
}
+ /**
+ * The routes exclude pattern (camel.main.routesExcludePattern) of the
--exclude patterns for the files of a source
+ * directory, or null when there are none. The files of the directory have
the location file:dir/name; a pattern
+ * without a folder, such as *.xml, matches a file name in any folder, as
it does for the files given by name.
+ */
+ public static String sourceDirExcludePattern(String sourceDir,
List<String> excludes) {
+ if (excludes == null || excludes.isEmpty()) {
+ return null;
+ }
+ String dir = sourceDir.replace('\\', '/');
+ while (dir.length() > 1 && dir.endsWith("/")) {
+ dir = dir.substring(0, dir.length() - 1);
+ }
+ StringJoiner sj = new StringJoiner(",");
+ for (String pattern : excludes) {
+ pattern = pattern.trim().replace('\\', '/');
+ while (pattern.startsWith("./")) {
+ pattern = pattern.substring(2);
+ }
+ if (!pattern.isEmpty()) {
+ sj.add("file:" + dir + "/" + (pattern.contains("/") ? pattern
: "**/" + pattern));
+ }
+ }
+ return sj.length() > 0 ? sj.toString() : null;
+ }
+
+ /**
+ * The --exclude patterns as excludes of the reload pattern, so a change
of an excluded file does not load it.
+ */
+ public static String reloadExcludes(List<String> excludes) {
+ StringBuilder sb = new StringBuilder();
+ if (excludes != null) {
+ for (String pattern : excludes) {
+ pattern = pattern.trim().replace('\\', '/');
+ while (pattern.startsWith("./")) {
+ pattern = pattern.substring(2);
+ }
+ if (!pattern.isEmpty()) {
+ sb.append(",!").append(pattern);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
/**
* The reload pattern of dev mode with a source directory: every file
under it, except the test folder, which holds
* the Citrus tests of the project (run with camel test run) and their
data, none of them routes (CAMEL-26494), and
diff --git
a/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/RunFilesTest.java
b/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/RunFilesTest.java
index df10c0390fba..7594ec28343a 100644
---
a/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/RunFilesTest.java
+++
b/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/RunFilesTest.java
@@ -53,6 +53,17 @@ class RunFilesTest {
assertThat(RunFiles.skipFile("orders.camel.yaml", List.of(),
"")).isFalse();
}
+ @Test
+ void anExcludeWithAFolderMatchesThePath() {
+ // the file name was matched only, so routes/** or sub/skip.camel.yaml
never matched (CAMEL-26930)
+ assertThat(RunFiles.skipFile("sub/skip.camel.yaml",
List.of("sub/skip.camel.yaml"), "")).isTrue();
+ assertThat(RunFiles.skipFile("./sub/skip.camel.yaml",
List.of("sub/**"), "")).isTrue();
+ assertThat(RunFiles.skipFile("sub/b.camel.yaml",
List.of("sub/skip.camel.yaml"), "")).isFalse();
+ // a pattern without a folder matches the file name, in any folder, as
before
+ assertThat(RunFiles.skipFile("sub/skip.camel.yaml",
List.of("skip.camel.yaml"), "")).isTrue();
+ assertThat(RunFiles.skipFile("a.camel.yaml", List.of("*.xml"),
"")).isFalse();
+ }
+
@ParameterizedTest
@ValueSource(strings = {
"orders.camel.yaml", "orders.yaml", "citrus.yaml",
"orders.camel.xml", "Orders.java", "orders.groovy",
diff --git
a/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/RunPipelineExcludeTest.java
b/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/RunPipelineExcludeTest.java
new file mode 100644
index 000000000000..ac07c438b5df
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/RunPipelineExcludeTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.run;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * --exclude for the files of a source directory: camel run ., --source-dir
and camel dev (CAMEL-26930).
+ */
+class RunPipelineExcludeTest {
+
+ @Test
+ void theExcludesAreUnderTheSourceDirectory() {
+ // the files of the directory have the location file:./sub/b.camel.yaml
+ assertThat(RunPipeline.sourceDirExcludePattern(".", List.of("sub/**",
"./skip.camel.yaml", "*.xml")))
+
.isEqualTo("file:./sub/**,file:./**/skip.camel.yaml,file:./**/*.xml");
+ assertThat(RunPipeline.sourceDirExcludePattern("routes/",
List.of("old/**")))
+ .isEqualTo("file:routes/old/**");
+ }
+
+ @Test
+ void noExcludesNoPattern() {
+ assertThat(RunPipeline.sourceDirExcludePattern(".",
List.of())).isNull();
+ assertThat(RunPipeline.sourceDirExcludePattern(".", null)).isNull();
+ assertThat(RunPipeline.sourceDirExcludePattern(".", List.of("
"))).isNull();
+ }
+
+ @Test
+ void theExcludesAreLeftOutOfTheReload() {
+ assertThat(
+ RunPipeline.sourceDirReloadPattern(null) +
RunPipeline.reloadExcludes(List.of("sub/**", "./skip.camel.yaml")))
+ .endsWith(",!sub/**,!skip.camel.yaml");
+ assertThat(RunPipeline.reloadExcludes(null)).isEmpty();
+ }
+}