Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ camel debug [options]
| `--dep,--dependency` | Add additional dependencies | | List
| `--download` | Whether to allow automatic downloading JAR dependencies (over the internet) | true | boolean
| `--empty` | Run an empty Camel without loading source files | false | boolean
| `--example` | Run a built-in example by name (e.g., timer-log, rest-api). Use --example --list to show available examples. | | String
| `--example-list` | List available built-in examples | | boolean
| `--example` | Run an example by name, or list available examples when no name is given. | | String
| `--exclude` | Exclude files by name or pattern | | List
| `--fresh` | Make sure we use fresh (i.e. non-cached) resources | false | boolean
| `--gav` | The Maven group:artifact:version (used during exporting) | | String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ camel run [options]
| `--dep,--dependency` | Add additional dependencies | | List
| `--download` | Whether to allow automatic downloading JAR dependencies (over the internet) | true | boolean
| `--empty` | Run an empty Camel without loading source files | false | boolean
| `--example` | Run a built-in example by name (e.g., timer-log, rest-api). Use --example --list to show available examples. | | String
| `--example-list` | List available built-in examples | | boolean
| `--example` | Run an example by name, or list available examples when no name is given. | | String
| `--exclude` | Exclude files by name or pattern | | List
| `--fresh` | Make sure we use fresh (i.e. non-cached) resources | false | boolean
| `--gav` | The Maven group:artifact:version (used during exporting) | | String
Expand Down
30 changes: 30 additions & 0 deletions dsl/camel-jbang/camel-jbang-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,34 @@
</plugins>
</build>

<profiles>
<profile>
<id>sync-example-catalog</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>download-example-catalog</id>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<get src="https://raw.githubusercontent.com/apache/camel-jbang-examples/main/camel-jbang-example-catalog.json"
dest="${project.basedir}/src/main/resources/examples/camel-jbang-example-catalog.json"
usetimestamp="true"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.camel.catalog.DefaultCamelCatalog;
import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
import org.apache.camel.dsl.jbang.core.common.EnvironmentHelper;
import org.apache.camel.dsl.jbang.core.common.ExampleHelper;
import org.apache.camel.dsl.jbang.core.common.JavaVersionCompletionCandidates;
import org.apache.camel.dsl.jbang.core.common.LauncherHelper;
import org.apache.camel.dsl.jbang.core.common.LoggingLevelCompletionCandidates;
Expand Down Expand Up @@ -99,7 +100,9 @@
" camel run *",
" camel run hello.java --dev",
" camel run hello.java --port=8080",
" camel run https://gist.github.com/user/123456" })
" camel run https://gist.github.com/user/123456",
" camel run --example",
" camel run --example=timer-log" })
public class Run extends CamelCommand {

// special template for running camel-jbang in docker containers
Expand Down Expand Up @@ -338,14 +341,10 @@ public class Run extends CamelCommand {
boolean skipPlugins;

@Option(names = { "--example" },
description = "Run a built-in example by name (e.g., timer-log, rest-api). Use --example --list to show available examples.",
description = "Run an example by name, or list available examples when no name is given.",
arity = "0..1", fallbackValue = "")
String example;

@Option(names = { "--example-list" },
description = "List available built-in examples")
boolean exampleList;

public Run(CamelJBangMain main) {
super(main);
}
Expand All @@ -366,8 +365,8 @@ public boolean disarrangeLogging() {
@Override
public Integer doCall() throws Exception {
// handle --example
if (exampleList || (example != null && example.isEmpty())) {
return listExamples();
if (example != null && example.isEmpty()) {
return listExamples(null);
}
if (example != null) {
return runExample();
Expand All @@ -380,58 +379,162 @@ public Integer doCall() throws Exception {
return run();
}

private int listExamples() {
printer().println("Available built-in examples:");
private int listExamples(String filter) {
List<JsonObject> catalog = ExampleHelper.loadCatalog();
if (catalog.isEmpty()) {
printer().printErr("No example catalog found.");
return 1;
}

List<JsonObject> filtered = ExampleHelper.filterExamples(catalog, filter);
if (filtered.isEmpty()) {
printer().printErr("No examples matching: " + filter);
return 1;
}

if (filter != null && !filter.isEmpty()) {
printer().println("Examples matching '" + filter + "':");
} else {
printer().println("Available examples:");
}

Map<String, List<JsonObject>> groups = new LinkedHashMap<>();
for (String level : new String[] { "beginner", "intermediate", "advanced" }) {
groups.put(level, new ArrayList<>());
}
for (JsonObject entry : filtered) {
String level = entry.getString("level");
if (level == null) {
level = "intermediate";
}
groups.computeIfAbsent(level, k -> new ArrayList<>()).add(entry);
}

for (Map.Entry<String, List<JsonObject>> group : groups.entrySet()) {
List<JsonObject> entries = group.getValue();
if (entries.isEmpty()) {
continue;
}
entries.sort(Comparator.comparing(e -> e.getString("name")));
printer().println();
printer().println(group.getKey().substring(0, 1).toUpperCase() + group.getKey().substring(1) + ":");
printer().printf(" %-30s %s%n", "NAME", "DESCRIPTION");
printer().printf(" %-30s %s%n", "----", "-----------");
for (JsonObject entry : entries) {
String eName = entry.getString("name");
String desc = entry.getString("description");
StringBuilder icons = new StringBuilder();
if (ExampleHelper.isBundled(entry)) {
icons.append("📦");
} else {
icons.append("🌐");
}
if (ExampleHelper.requiresDocker(entry)) {
icons.append("🐳");
} else {
icons.append(" ");
}
printer().printf(" %s %-30s %s%n", icons, eName, desc);
}
}
printer().println();
printer().printf(" %-20s %s%n", "timer-log", "Simple timer that logs messages every second");
printer().printf(" %-20s %s%n", "rest-api", "REST API with hello endpoints");
printer().printf(" %-20s %s%n", "cron-log", "Scheduled task that logs every 5 seconds");
printer().println(" 📦 = bundled (works offline) 🌐 = online (fetched from GitHub) 🐳 = requires Docker");
printer().println();
printer().println("Usage: camel run --example <name>");
printer().println(" camel run --example <name> --dev");
printer().println("Usage: camel run --example=<name>");
printer().println(" camel run --example=<name> --dev");
return 0;
}

private static final List<String> EXAMPLE_NAMES = List.of("timer-log", "rest-api", "cron-log");

private int runExample() throws Exception {
String resourcePath = "examples/" + example + ".yaml";
InputStream is = Run.class.getClassLoader().getResourceAsStream(resourcePath);
if (is == null) {
List<String> suggestions
= SuggestSimilarHelper.didYouMean(EXAMPLE_NAMES, example);
List<JsonObject> catalog = ExampleHelper.loadCatalog();
JsonObject entry = ExampleHelper.findExample(catalog, example);

if (entry == null) {
List<String> names = ExampleHelper.getExampleNames(catalog);
List<String> suggestions = SuggestSimilarHelper.didYouMean(names, example);
if (!suggestions.isEmpty()) {
printer().printErr("Unknown example: " + example + ". Did you mean? " + String.join(", ", suggestions));
} else {
printer().printErr("Unknown example: " + example);
}
printer().printErr("Run 'camel run --example-list' to see available examples.");
printer().printErr("Run 'camel run --example' to see available examples.");
return 1;
}

// extract example to a temp file and run it
Path tempDir = Files.createTempDirectory("camel-example-");
Path exampleFile = tempDir.resolve(example + ".yaml");
if (ExampleHelper.isBundled(entry)) {
return runBundledExample(entry);
} else {
return runGithubExample(entry);
}
}

private int runBundledExample(JsonObject entry) throws Exception {
String eName = entry.getString("name");
Path tempDir = ExampleHelper.extractBundledExample(entry);
List<String> exampleFiles = ExampleHelper.getFiles(entry);

printer().println("Running example: " + eName);
for (String f : exampleFiles) {
files.add(tempDir.resolve(f).toString());
}
if ("CamelJBang".equals(name)) {
name = eName;
}

if (!exportRun) {
printConfigurationValues("Running integration with the following configuration:");
}
return run();
}

private int runGithubExample(JsonObject entry) throws Exception {
String eName = entry.getString("name");
String url = ExampleHelper.getGithubUrl(entry);

printer().println("Fetching example from GitHub: " + eName);
if (ExampleHelper.requiresDocker(entry)) {
printer().println("Note: this example requires Docker/Podman");
}

StringJoiner routes = new StringJoiner(",");
StringJoiner kamelets = new StringJoiner(",");
StringJoiner properties = new StringJoiner(",");
try {
String content = IOHelper.loadText(is);
IOHelper.close(is);
Files.writeString(exampleFile, content);
fetchGithubUrls(url, routes, kamelets, properties);
} catch (Exception e) {
printer().printErr("Failed to fetch example from GitHub: " + e.getMessage());
printer().printErr("This example requires an internet connection.");
return 1;
}

printer().println("Running example: " + example);
files.add(exampleFile.toString());
if ("CamelJBang".equals(name)) {
name = example;
}
if (routes.length() == 0 && kamelets.length() == 0 && properties.length() == 0) {
printer().printErr("No files found for example: " + eName);
return 1;
}

if (!exportRun) {
printConfigurationValues("Running integration with the following configuration:");
if (routes.length() > 0) {
for (String r : routes.toString().split(",")) {
files.add(r);
}
return run();
} finally {
// clean up temp files on JVM exit
exampleFile.toFile().deleteOnExit();
tempDir.toFile().deleteOnExit();
}
if (kamelets.length() > 0) {
for (String k : kamelets.toString().split(",")) {
files.add(k);
}
}
if (properties.length() > 0) {
for (String p : properties.toString().split(",")) {
files.add(p);
}
}
if ("CamelJBang".equals(name)) {
name = eName;
}

if (!exportRun) {
printConfigurationValues("Running integration with the following configuration:");
}
return run();
}

public Integer runExport() throws Exception {
Expand Down
Loading