Ricardo Martinez created CAMEL-26371:
----------------------------------------
Summary: {{camel run --runtime=camel-main
--local-kamelet-dir=<dir1>,<dir2>}} fails to resolve kamelets when more than
one directory is supplied (regression since 4.23.0).
Key: CAMEL-26371
URL: https://issues.apache.org/jira/browse/CAMEL-26371
Project: Camel
Issue Type: Bug
Components: camel-jbang
Reporter: Ricardo Martinez
h2. Description
Routes using local kamelets fail to start when \{{--runtime=camel-main}} is
combined with a comma-separated \{{--local-kamelet-dir}} value containing more
than one path. The same command works fine with a single directory, and worked
with multiple directories in 4.22 and earlier.
h3. Reproduction
*Fails — kamelets not found:*
{code:bash}
camel run demo.camel.yaml \
--runtime=camel-main \
--local-kamelet-dir=/home/user/project,/home/user/project/kamelets
{code}
*Works — single directory is fine:*
{code:bash}
camel run demo.camel.yaml \
--runtime=camel-main \
--local-kamelet-dir=/home/user/project/kamelets
{code}
h3. Root Cause
Commit \{{935f581a8a59}} (CAMEL-24659, released in 4.23.0) changed
\{{--runtime=camel-main}} to export sources to a temporary Maven project, build
a fat JAR, and launch it. This routes execution through
\{{ExportBaseCommand.copySourceFiles()}}, which has two bugs that surface only
when \{{LOCAL_KAMELET_DIR}} contains more than one comma-separated path.
*Bug 1 — scheme stripped from the entire comma-joined string*
{\{getScheme()}} finds the first \{{:}} in the whole concatenated string and
strips the scheme prefix from that position. With a multi-directory value like
\{{file:/path/a,file:/path/b}}, only the \{{file:}} from the first entry is
removed; subsequent entries retain their \{{file:}} prefix and are passed as-is
to \{{Paths.get()}}.
{code:java}
// BROKEN — value: "file:/home/user/project,file:/home/user/project/kamelets"
String localKameletDir = prop.getProperty(LOCAL_KAMELET_DIR);
if (localKameletDir != null) {
String scheme = getScheme(localKameletDir); // returns "file" (finds first ":")
if (scheme != null) {
localKameletDir = localKameletDir.substring(scheme.length() + 1);
// result: "/home/user/project,file:/home/user/project/kamelets"
// ^^^^^ second entry still has "file:" prefix
}
}
{code}
*Bug 2 — \{{Paths.get()}} called with the corrupted (unsplit) string*
{code:java}
// BROKEN — localKameletDir still contains a literal comma and a leftover
"file:" prefix
source = Paths.get(localKameletDir, f + ".kamelet.yaml");
// = Paths.get("/home/user/project,file:/home/user/project/kamelets",
"my-kamelet.kamelet.yaml")
// Resolved path contains a literal comma and does not exist on disk.
{code}
h3. Affected File
{\{dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java}}
— method \{{copySourceFiles()}}.
h3. Fix
Replace the single \{{localKameletDir}} string variable with a
\{{List<String>}}, stripping the \{{file:}} scheme from *each element
individually*, and update the kamelet-file lookup to search across all
directories in order (falling back to the first entry if none is found, which
preserves the existing error behaviour for genuinely missing kamelets). No new
imports are required — \{{List}}, \{{ArrayList}}, \{{Paths}}, and \{{Files}}
are already imported.
{code:java}
// FIXED — strip scheme per element
List<String> localKameletDirs = new ArrayList<>();
String localKameletDirRaw = prop.getProperty(LOCAL_KAMELET_DIR);
if (localKameletDirRaw != null) {
for (String part : localKameletDirRaw.split(",")) {
String scheme = getScheme(part);
if (scheme != null) {
part = part.substring(scheme.length() + 1);
}
localKameletDirs.add(part);
}
}
// FIXED — search each directory in order
if ("kamelet".equals(k) && !localKameletDirs.isEmpty()) {
String kameletFileName = f + ".kamelet.yaml";
source = localKameletDirs.stream()
.map(dir -> Paths.get(dir, kameletFileName))
.filter(Files::exists)
.findFirst()
.orElse(Paths.get(localKameletDirs.get(0), kameletFileName));
}
{code}
h3. Workarounds (until the fix is released)
* Use \{{--runtime=jbang}} (the old in-process default). The \{{KameletMain}}
codepath still handles multiple directories correctly.
* Pass only one kamelet directory — the most specific one (e.g. the
\{{kamelets/}} subdirectory).
----
_Filed by Bob (AI) on behalf of lordrip._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)