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 2b1f09734d0e CAMEL-26912: camel-jbang - camel export no longer deletes 
the files of a directory that no export created (#29813)
2b1f09734d0e is described below

commit 2b1f09734d0ef02b11d51048b3630614de5bebcd
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Nov 13 16:40:40 2026 +0100

    CAMEL-26912: camel-jbang - camel export no longer deletes the files of a 
directory that no export created (#29813)
    
    An export to a directory other than the current one writes a .camel-export
    file in it, and a later export only cleans a directory that has it. Any 
other
    directory with files is not exported to without --clean-dir.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    | 16 ++++++
 .../modules/ROOT/pages/camel-jbang-projects.adoc   |  4 ++
 .../jbang/core/commands/DependencyUpdateTest.java  |  2 +
 .../test/resources/golden/expected/deps.export.txt |  1 +
 .../resources/golden/expected/excludes.export.txt  |  1 +
 .../resources/golden/expected/groovy.export.txt    |  1 +
 .../test/resources/golden/expected/java.export.txt |  1 +
 .../resources/golden/expected/kamelet.export.txt   |  1 +
 .../golden/expected/local-kamelet-dir.export.txt   |  1 +
 .../golden/expected/maven-main-chaos.maven.txt     |  1 +
 .../golden/expected/maven-main-mixed.maven.txt     |  1 +
 .../resources/golden/expected/maven-main.maven.txt |  1 +
 .../golden/expected/maven-quarkus-dev.maven.txt    |  1 +
 .../golden/expected/maven-quarkus.maven.txt        |  1 +
 .../golden/expected/maven-spring-boot.maven.txt    |  1 +
 .../resources/golden/expected/mixed.export.txt     |  1 +
 .../resources/golden/expected/openapi.export.txt   |  1 +
 .../resources/golden/expected/options.export.txt   |  1 +
 .../golden/expected/pom-project.export.txt         |  1 +
 .../golden/expected/profile-prod.export.txt        |  1 +
 .../resources/golden/expected/profile.export.txt   |  1 +
 .../golden/expected/resource-dir.export.txt        |  1 +
 .../golden/expected/run-settings.export.txt        |  1 +
 .../test/resources/golden/expected/xml.export.txt  |  1 +
 .../resources/golden/expected/yaml-deps.export.txt |  1 +
 .../test/resources/golden/expected/yaml.export.txt |  1 +
 .../camel/dsl/jbang/run/common/ExportHelper.java   | 26 ++++++++++
 .../dsl/jbang/run/export/CamelMainExporter.java    | 16 +++---
 .../camel/dsl/jbang/run/export/Exporter.java       | 53 +++++++++++++++++++
 .../dsl/jbang/run/export/QuarkusExporter.java      | 16 +++---
 .../dsl/jbang/run/export/SpringBootExporter.java   | 16 +++---
 .../dsl/jbang/run/export/ProjectExporterTest.java  | 59 ++++++++++++++++++++++
 32 files changed, 201 insertions(+), 30 deletions(-)

diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index a419236e5e35..f74c0e2bff83 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -2079,6 +2079,22 @@ events, such as `QueueParamsEvent`, `QueueMemberEvent` 
and `PeerEntryEvent`. Bef
 `ManagerResponse` saying that the list will follow, and the events were lost. 
A route that read that response from
 the body now finds it in `${body.response}`. `EXTENSION_STATE` still sets the 
`ManagerResponse` as the body.
 
+=== camel-jbang - camel export no longer deletes the files of a directory that 
no export created
+
+`camel export --dir=<dir>` to a directory other than the current one used to 
delete the files of that directory first,
+whatever they were. It now only does so for a directory that an earlier export 
created: the export writes a
+`.camel-export` file in it. Exporting to a directory with other files fails, 
and keeps them:
+
+----
+Cannot export to /home/me/project because it has files that camel export did 
not create: use --clean-dir to delete them, or export to another directory
+----
+
+This includes exporting to the directory of the exported files themselves from 
another directory (such as
+`camel export /work/route.camel.yaml --dir=/work`), which deleted the source 
files: use `--clean-dir --yes` for that.
+A directory that an earlier Camel version exported to has no `.camel-export` 
file yet: export to it once with
+`--clean-dir --yes`. An empty directory, one with only hidden files (such as 
`.git`), and the current directory are
+exported to as before.
+
 === camel-jbang - camel validate and camel overview report the same endpoints 
no route consumes
 
 `camel validate source` and `camel overview` now use the same rules for a 
`direct:`, `seda:` or `disruptor:` endpoint
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc
index 19a3bd7a267c..5b4820208a6b 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc
@@ -15,6 +15,10 @@ camel export --runtime=camel-main 
--gav=com.foo:acme:1.0-SNAPSHOT
 
 NOTE: Without `--directory`, files are exported to the current directory. Use 
`--directory=../myproject` to copy to a separate folder.
 
+The export writes a `.camel-export` file in a separate folder, and replaces 
that folder when it exports to it again, so
+no stale files of the earlier export are left. It does not delete the files of 
a folder that no export created: the
+export fails, unless `--clean-dir` is given. Without `--directory`, the files 
of the current directory are kept.
+
 TIP: Run `camel export --help` for all options.
 
 Notes:
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
index b56e6faf8945..6a3bbc0881f6 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
@@ -126,6 +126,8 @@ class DependencyUpdateTest extends 
CamelCommandBaseTestSupport {
         CommandLineTestHelper.parse(exportCommand,
                 "--gav=examples:route:1.0.0",
                 "--dir=" + workingDir,
+                // the directory has the route that camel init created, which 
the export replaces with the project
+                "--clean-dir", "--yes",
                 "--camel-version=4.13.0",
                 "--runtime=" + rt.runtime(),
                 CamelCommandBaseTestSupport.quarkusExtRegistry(),
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/deps.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/deps.export.txt
index eb85d46ca72a..95e3dd96bdfd 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/deps.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/deps.export.txt
@@ -27,6 +27,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.export.txt
index 28a8c7d6d95d..55216ddbfe3b 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/excludes.export.txt
@@ -23,6 +23,7 @@ 
dependency=mvn\:org.apache.camel\:camel-core-languages\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/groovy.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/groovy.export.txt
index f7b23d6a7f69..55d469ff5fd0 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/groovy.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/groovy.export.txt
@@ -25,6 +25,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/java.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/java.export.txt
index a3235ce03fd1..f0113945af1f 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/java.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/java.export.txt
@@ -24,6 +24,7 @@ 
dependency=mvn\:org.apache.camel\:camel-core-languages\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/kamelet.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/kamelet.export.txt
index 18b45dafd656..8b2d36f0bd35 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/kamelet.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/kamelet.export.txt
@@ -24,6 +24,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-core-languages\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/local-kamelet-dir.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/local-kamelet-dir.export.txt
index 912522d34780..5adeb10e9532 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/local-kamelet-dir.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/local-kamelet-dir.export.txt
@@ -25,6 +25,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-core-languages\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-chaos.maven.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-chaos.maven.txt
index 0856fb89e29d..115f78e1496e 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-chaos.maven.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-chaos.maven.txt
@@ -15,6 +15,7 @@ ${run-dir}/target/runner.jar
 
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-mixed.maven.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-mixed.maven.txt
index eafd54d75faf..38f49f5c2635 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-mixed.maven.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main-mixed.maven.txt
@@ -21,6 +21,7 @@ ${run-dir}/target/runner.jar
 
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main.maven.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main.maven.txt
index 5f9eda63a551..6930b833224c 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main.maven.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-main.maven.txt
@@ -14,6 +14,7 @@ ${run-dir}/target/runner.jar
 
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus-dev.maven.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus-dev.maven.txt
index 5370d58244b2..c28773f95499 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus-dev.maven.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus-dev.maven.txt
@@ -9,6 +9,7 @@ quarkus:dev
 
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus.maven.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus.maven.txt
index f5c432aa851c..bb11589a1a0a 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus.maven.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-quarkus.maven.txt
@@ -8,6 +8,7 @@ quarkus:run
 
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-spring-boot.maven.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-spring-boot.maven.txt
index 150af3e13b96..f948b093ad2c 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-spring-boot.maven.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/maven-spring-boot.maven.txt
@@ -8,6 +8,7 @@ spring-boot:run
 
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/mixed.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/mixed.export.txt
index a6762287608c..af681bb2e231 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/mixed.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/mixed.export.txt
@@ -34,6 +34,7 @@ dependency=mvn\:org.apache.camel\:camel-bean\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/openapi.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/openapi.export.txt
index 8721f93bbe14..b1cf361d4135 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/openapi.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/openapi.export.txt
@@ -28,6 +28,7 @@ dependency=mvn\:org.apache.camel\:camel-http\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-jackson3\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/options.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/options.export.txt
index bea6226d1990..b97bd8c2da98 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/options.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/options.export.txt
@@ -36,6 +36,7 @@ 
dependency=mvn\:org.apache.camel\:camel-platform-http-vertx\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-platform-http-jolokia\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/pom-project.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/pom-project.export.txt
index eb34ebff9fca..80e17313e023 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/pom-project.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/pom-project.export.txt
@@ -28,6 +28,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile-prod.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile-prod.export.txt
index 98a0862b40bb..6fa82ed8a30f 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile-prod.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile-prod.export.txt
@@ -23,6 +23,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-seda\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile.export.txt
index 7104ad660b91..a5459397ff5c 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/profile.export.txt
@@ -26,6 +26,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/resource-dir.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/resource-dir.export.txt
index 0db33c8bd607..8d05f585a583 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/resource-dir.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/resource-dir.export.txt
@@ -25,6 +25,7 @@ 
dependency=mvn\:org.apache.camel\:camel-core-languages\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/run-settings.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/run-settings.export.txt
index e3b48d1734bc..1457fd91232c 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/run-settings.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/run-settings.export.txt
@@ -24,6 +24,7 @@ 
dependency=mvn\:org.apache.camel\:camel-core-languages\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/xml.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/xml.export.txt
index 2a70cb830b1d..def1a5c76b31 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/xml.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/xml.export.txt
@@ -22,6 +22,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml-deps.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml-deps.export.txt
index ebb8c8551d36..02305a360a58 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml-deps.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml-deps.export.txt
@@ -23,6 +23,7 @@ 
dependency=mvn\:org.apache.camel\:camel-timer\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml.export.txt
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml.export.txt
index 79392d2dcfe6..3c84d8d0fba5 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml.export.txt
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/expected/yaml.export.txt
@@ -23,6 +23,7 @@ 
dependency=mvn\:org.apache.camel\:camel-core-languages\:${camel.version}
 dependency=mvn\:org.apache.camel\:camel-log\:${camel.version}
 
 # project files
+.camel-export
 .mvn/wrapper/maven-wrapper.jar
 .mvn/wrapper/maven-wrapper.properties
 AGENTS.md
diff --git 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/common/ExportHelper.java
 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/common/ExportHelper.java
index 03c8acb5d7ff..e9ad4cbe2f73 100644
--- 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/common/ExportHelper.java
+++ 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/common/ExportHelper.java
@@ -52,6 +52,12 @@ public final class ExportHelper {
      */
     public static final String RUN_SETTINGS_FILE = 
"camel-jbang-run.properties";
 
+    /**
+     * The file that camel export writes in the directory it exports to, other 
than the current directory: a later
+     * export may replace that directory (CAMEL-26912).
+     */
+    public static final String EXPORT_MARKER = ".camel-export";
+
     public static final int MAX_RESOURCE_DIR_FILES = 1000;
 
     private ExportHelper() {
@@ -108,6 +114,26 @@ public final class ExportHelper {
         }
     }
 
+    /**
+     * Whether the directory has files or directories that are not hidden. A 
directory that does not exist has none.
+     */
+    public static boolean hasVisibleFiles(Path dir) {
+        if (!Files.isDirectory(dir)) {
+            return false;
+        }
+        try (Stream<Path> paths = Files.list(dir)) {
+            return paths.anyMatch(p -> {
+                try {
+                    return !Files.isHidden(p);
+                } catch (IOException e) {
+                    return true;
+                }
+            });
+        } catch (IOException e) {
+            return true;
+        }
+    }
+
     public static void cleanExportDir(String dir) {
         cleanExportDir(dir, true);
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/CamelMainExporter.java
 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/CamelMainExporter.java
index 8a673b9514e8..924e4c2e12f3 100644
--- 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/CamelMainExporter.java
+++ 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/CamelMainExporter.java
@@ -63,6 +63,9 @@ class CamelMainExporter extends Exporter {
             printer().printErr("--gav must be in syntax: 
groupId:artifactId:version");
             return 1;
         }
+        if (!canExportTo()) {
+            return 1;
+        }
         if (request.parentPom != null) {
             try {
                 MavenGav.parseStrictGav(request.parentPom);
@@ -199,20 +202,13 @@ class CamelMainExporter extends Exporter {
         }
         String appJar = Paths.get("target", ids[1] + "-" + ids[2] + 
".jar").toString();
         copyReadme(buildDir.toString(), appJar);
-        if (request.cleanExportDir || 
!ExportHelper.isCurrentDirOrParent(request.exportDir)) {
-            // cleaning current dir can be a bit dangerous so only clean if 
explicit enabled
-            // otherwise always clean export-dir to avoid stale data
-            if (request.cleanExportDir) {
-                String absPath = 
Path.of(request.exportDir).toAbsolutePath().toString();
-                if (!request.yes && !exportContext.confirm("Are you sure you 
want to delete " + absPath + "?")) {
-                    return 1;
-                }
-            }
-            ExportHelper.cleanExportDir(request.exportDir);
+        if (cleanExportDir() != 0) {
+            return 1;
         }
         // copy to export dir and remove work dir
         PathUtils.copyDirectory(buildDir, Path.of(request.exportDir));
         createDeferredSymlinks(buildDir, Path.of(request.exportDir));
+        markExportDir();
         PathUtils.deleteDirectory(buildDir);
 
         return 0;
diff --git 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/Exporter.java
 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/Exporter.java
index 60d77a598d4b..8b6a3c9e8bae 100644
--- 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/Exporter.java
+++ 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/Exporter.java
@@ -105,6 +105,59 @@ abstract class Exporter {
         this.exportContext = context;
     }
 
+    /**
+     * Whether the project can be exported to the export directory: the 
current directory (or one that contains it),
+     * whose files are kept, a directory that is empty or does not exist, or 
one that an earlier export created (it has
+     * the {@link ExportHelper#EXPORT_MARKER} file), which the export replaces 
so no stale files of it are left. The
+     * files of any other directory are not deleted without --clean-dir 
(CAMEL-26912).
+     */
+    protected boolean canExportTo() {
+        if (request.cleanExportDir || 
ExportHelper.isCurrentDirOrParent(request.exportDir)) {
+            return true;
+        }
+        Path dir = Path.of(request.exportDir);
+        if (Files.exists(dir.resolve(ExportHelper.EXPORT_MARKER)) || 
!ExportHelper.hasVisibleFiles(dir)) {
+            return true;
+        }
+        printer().printErr("Cannot export to " + 
dir.toAbsolutePath().normalize()
+                           + " because it has files that camel export did not 
create: use --clean-dir to delete them,"
+                           + " or export to another directory");
+        return false;
+    }
+
+    /**
+     * Cleans the export directory before the project is copied to it: with 
--clean-dir, when the user confirms it, or a
+     * directory that is not the current directory (see {@link 
#canExportTo()}).
+     *
+     * @return 0, or 1 when the user does not confirm --clean-dir
+     */
+    protected int cleanExportDir() {
+        if (request.cleanExportDir) {
+            String absPath = 
Path.of(request.exportDir).toAbsolutePath().toString();
+            if (!request.yes && !exportContext.confirm("Are you sure you want 
to delete " + absPath + "?")) {
+                return 1;
+            }
+            ExportHelper.cleanExportDir(request.exportDir);
+        } else if (!ExportHelper.isCurrentDirOrParent(request.exportDir)) {
+            // no stale data of an earlier export
+            ExportHelper.cleanExportDir(request.exportDir);
+        }
+        return 0;
+    }
+
+    /**
+     * Marks the export directory as created by camel export, so the next 
export to it may replace it. The current
+     * directory is not marked: an export from another directory must not 
delete the files of this one.
+     */
+    protected void markExportDir() throws IOException {
+        if (!ExportHelper.isCurrentDirOrParent(request.exportDir)) {
+            
Files.writeString(Path.of(request.exportDir).resolve(ExportHelper.EXPORT_MARKER),
 """
+                    # Created by camel export, which replaces the files of 
this directory when it exports to it again.
+                    # Delete this file to keep them: camel export then needs 
--clean-dir to export here.
+                    """);
+        }
+    }
+
     /**
      * The directory in the work directory where the project is built, before 
it is copied to the export directory.
      */
diff --git 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/QuarkusExporter.java
 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/QuarkusExporter.java
index 08527f199bfb..b6f0a1373bd6 100644
--- 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/QuarkusExporter.java
+++ 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/QuarkusExporter.java
@@ -86,6 +86,9 @@ class QuarkusExporter extends Exporter {
             printer().printErr("--gav must be in syntax: 
groupId:artifactId:version");
             return 1;
         }
+        if (!canExportTo()) {
+            return 1;
+        }
         if (request.parentPom != null) {
             try {
                 MavenGav.parseStrictGav(request.parentPom);
@@ -193,20 +196,13 @@ class QuarkusExporter extends Exporter {
             copyCamelWrapper();
         }
 
-        if (request.cleanExportDir || 
!ExportHelper.isCurrentDirOrParent(request.exportDir)) {
-            // cleaning current dir can be a bit dangerous so only clean if 
explicit enabled
-            // otherwise always clean export-dir to avoid stale data
-            if (request.cleanExportDir) {
-                String absPath = 
Path.of(request.exportDir).toAbsolutePath().toString();
-                if (!request.yes && !exportContext.confirm("Are you sure you 
want to delete " + absPath + "?")) {
-                    return 1;
-                }
-            }
-            ExportHelper.cleanExportDir(request.exportDir);
+        if (cleanExportDir() != 0) {
+            return 1;
         }
         // copy to export dir and remove work dir
         PathUtils.copyDirectory(buildDir, Path.of(request.exportDir));
         createDeferredSymlinks(buildDir, Path.of(request.exportDir));
+        markExportDir();
         PathUtils.deleteDirectory(buildDir);
 
         return 0;
diff --git 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/SpringBootExporter.java
 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/SpringBootExporter.java
index d87ff8947fd4..f86b392bd16b 100644
--- 
a/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/SpringBootExporter.java
+++ 
b/dsl/camel-jbang/camel-jbang-run/src/main/java/org/apache/camel/dsl/jbang/run/export/SpringBootExporter.java
@@ -71,6 +71,9 @@ class SpringBootExporter extends Exporter {
             printer().printErr("--gav must be in syntax: 
groupId:artifactId:version");
             return 1;
         }
+        if (!canExportTo()) {
+            return 1;
+        }
         if (request.parentPom != null) {
             try {
                 MavenGav.parseStrictGav(request.parentPom);
@@ -199,20 +202,13 @@ class SpringBootExporter extends Exporter {
         }
         String appJar = "target" + File.separator + ids[1] + "-" + ids[2] + 
".jar";
         copyReadme(buildDir.toString(), appJar);
-        if (request.cleanExportDir || 
!ExportHelper.isCurrentDirOrParent(request.exportDir)) {
-            // cleaning current dir can be a bit dangerous so only clean if 
explicit enabled
-            // otherwise always clean export-dir to avoid stale data
-            if (request.cleanExportDir) {
-                String absPath = 
Paths.get(request.exportDir).toAbsolutePath().toString();
-                if (!request.yes && !exportContext.confirm("Are you sure you 
want to delete " + absPath + "?")) {
-                    return 1;
-                }
-            }
-            ExportHelper.cleanExportDir(request.exportDir);
+        if (cleanExportDir() != 0) {
+            return 1;
         }
         // copy to export dir and remove work dir
         PathUtils.copyDirectory(buildDir, Paths.get(request.exportDir));
         createDeferredSymlinks(buildDir, Paths.get(request.exportDir));
+        markExportDir();
         PathUtils.deleteDirectory(buildDir);
 
         return 0;
diff --git 
a/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/export/ProjectExporterTest.java
 
b/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/export/ProjectExporterTest.java
index c7089deea347..c9e59fe8b35f 100644
--- 
a/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/export/ProjectExporterTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-run/src/test/java/org/apache/camel/dsl/jbang/run/export/ProjectExporterTest.java
@@ -263,6 +263,65 @@ class ProjectExporterTest {
         return new ExportContext().withPrinter(new 
StringPrinter()).withDependencyResolver(resolver);
     }
 
+    @Test
+    void replacesTheDirectoryOfAnEarlierExport() throws Exception {
+        Path exportDir = dir.resolve("export");
+        assertThat(export(request(writeRoute("first"), exportDir))).isZero();
+        assertThat(exportDir.resolve(ExportHelper.EXPORT_MARKER)).exists();
+
+        // the export replaces the earlier one, so no stale files of it are 
left
+        assertThat(export(request(writeRoute("second"), exportDir))).isZero();
+        
assertThat(exportDir.resolve("src/main/resources/camel")).isDirectoryContaining("glob:**/second.camel.yaml")
+                .isDirectoryNotContaining("glob:**/first.camel.yaml");
+        assertThat(exportDir.resolve(ExportHelper.EXPORT_MARKER)).exists();
+    }
+
+    @Test
+    void keepsTheFilesOfADirectoryThatNoExportCreated() throws Exception {
+        Path exportDir = Files.createDirectories(dir.resolve("export"));
+        Path todo = Files.writeString(exportDir.resolve("TODO.txt"), "my 
notes");
+        Path notes = 
Files.writeString(Files.createDirectories(exportDir.resolve("docs")).resolve("notes.txt"),
 "more");
+
+        StringPrinter printer = new StringPrinter();
+        int exit = new ProjectExporter(new 
ExportContext().withPrinter(printer).withDependencyResolver(resolver))
+                .export(request(writeRoute("hello"), exportDir));
+
+        assertThat(exit).isEqualTo(1);
+        assertThat(printer.getOutput()).contains("Cannot export to " + 
exportDir.toAbsolutePath(), "--clean-dir");
+        assertThat(todo).hasContent("my notes");
+        assertThat(notes).hasContent("more");
+        assertThat(exportDir.resolve("pom.xml")).doesNotExist();
+        // nothing was resolved: the export stops before it boots the 
integration
+        assertThat(resolved).isEmpty();
+
+        // unless they are deleted on purpose
+        ExportRequest request = request(writeRoute("hello"), exportDir);
+        request.cleanExportDir = true;
+        request.yes = true;
+        assertThat(export(request)).isZero();
+        assertThat(todo).doesNotExist();
+        assertThat(exportDir.resolve("pom.xml")).exists();
+    }
+
+    @Test
+    void exportsToADirectoryWithOnlyHiddenFiles() throws Exception {
+        // such as a clone of an empty Git repository
+        Path exportDir = Files.createDirectories(dir.resolve("export"));
+        Path git = 
Files.writeString(Files.createDirectories(exportDir.resolve(".git")).resolve("HEAD"),
 "ref");
+
+        assertThat(export(request(writeRoute("hello"), exportDir))).isZero();
+        assertThat(exportDir.resolve("pom.xml")).exists();
+        assertThat(git).hasContent("ref");
+    }
+
+    private int export(ExportRequest request) throws Exception {
+        StringPrinter printer = new StringPrinter();
+        int exit = new ProjectExporter(new 
ExportContext().withPrinter(printer).withDependencyResolver(resolver))
+                .export(request);
+        assertThat(exit).as(printer.getOutput()).isNotNegative();
+        return exit;
+    }
+
     private Path writeRoute(String name) throws Exception {
         Path route = dir.resolve(name + ".camel.yaml");
         Files.writeString(route, """

Reply via email to