EmulatorEdgeCli.java
package com.cloudforge.core.local;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import java.util.stream.Collectors;
/**
* Command-line entry point for {@link EmulatorEdgeLifecycle} — backs {@code scripts/emulator-edge-*.sh}.
*
* <p>{@code EmulatorEdgeLifecycle}'s own javadoc calls it "the preferred entry for Maven goals and
* programmatic callers", but no Maven plugin ever actually registered a {@code cloudforge:} prefix
* for it — {@code mvn -f cfc-testing cloudforge:emulator-edge-reconcile} (referenced in the nginx
* edge's own banner text and every {@code scripts/emulator-edge-*.sh} wrapper) has always 404'd
* with "No plugin found for prefix 'cloudforge'". This class is the actual, working entry point:
* invoked via {@code mvn -q -pl cloudforge-core org.codehaus.mojo:exec-maven-plugin:3.5.0:java
* -Dexec.mainClass=com.cloudforge.core.local.EmulatorEdgeCli -Dexec.args=<goal>} (fully-qualified
* plugin coordinates — sidesteps the same prefix-resolution problem entirely rather than trying to
* register one).
*/
public final class EmulatorEdgeCli {
private EmulatorEdgeCli() {
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("usage: EmulatorEdgeCli <" + allowedActions() + ">");
System.exit(2);
return;
}
EmulatorEdgeLifecycleAction action;
try {
action = EmulatorEdgeLifecycleAction.valueOf(args[0].trim().toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
System.err.println("Unknown action '" + args[0] + "' — expected one of: " + allowedActions());
System.exit(2);
return;
}
try {
EmulatorEdgeLifecycle.execute(new DefaultEmulatorEdgeRuntime(resolveWorkingDirectory()), action);
} catch (Exception e) {
System.err.println("emulator-edge " + args[0] + " failed: " + e.getMessage());
System.exit(1);
}
}
private static String allowedActions() {
return Arrays.stream(EmulatorEdgeLifecycleAction.values())
.map(a -> a.name().toLowerCase(Locale.ROOT))
.collect(Collectors.joining("|"));
}
/**
* {@link LocalEmulatorPaths#emulatorEdgeDir} resolves relative to the JVM's ambient working
* directory, on the assumption every caller runs from {@code cfc-testing/} (true of every
* existing caller — InteractiveDeployer, the deploy pipelines — since that's their own natural
* cwd). {@code scripts/emulator-edge-*.sh} instead runs `mvn -pl cloudforge-core exec:java`
* from the repo root — which also happens to contain its own {@code pom.xml}, so that shared
* heuristic would silently resolve to a `.emulator-edge` directory AT the repo root instead
* of `cfc-testing/.emulator-edge` — nowhere near the path actually bind-mounted into the
* running nginx container, so reconcile would compute and print the correct answer but write
* it to a file nginx never reads, with nothing observable ever changing. Explicitly prefer a
* `cfc-testing` child directory when one exists (with the same {@code docker/emulator-edge}
* marker {@link LocalEmulatorPaths} itself checks for) rather than trusting ambient cwd.
*/
private static Path resolveWorkingDirectory() {
Path cwd = Path.of("").toAbsolutePath().normalize();
Path cfcTesting = cwd.resolve("cfc-testing");
if (Files.exists(cfcTesting.resolve("docker/emulator-edge"))) {
return cfcTesting;
}
return cwd;
}
}