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)

Reply via email to