summaryrefslogtreecommitdiff
path: root/src/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java')
-rw-r--r--src/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java b/src/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java
new file mode 100644
index 0000000..ef5ed1d
--- /dev/null
+++ b/src/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java
@@ -0,0 +1,156 @@
+package io.trygvis.rules.engine.cli;
+
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
+
+import static picocli.CommandLine.Command;
+
+@Command(name = "ninja")
+public class NinjaCommand implements Callable<Integer> {
+
+ public File basedir = null;
+
+ public Path basepath;
+
+ @Override
+ public Integer call() throws Exception {
+ basepath = Objects.requireNonNullElseGet(basedir, () -> new File("").getAbsoluteFile()).toPath();
+
+ var factory = new YAMLFactory();
+ factory.enable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID);
+ factory.enable(YAMLGenerator.Feature.USE_NATIVE_OBJECT_ID);
+ var mapper = new ObjectMapper(factory);
+ mapper.enable(MapperFeature.AUTO_DETECT_FIELDS);
+
+ var f = mapper.readValue(new File(basedir, "engine.yaml"), EngineFile.class);
+
+ Path dbDir;
+ if (StringUtils.trimToNull(f.dbDir) == null) {
+ System.err.println("Missing required field: dbDir");
+ return 1;
+ } else {
+ dbDir = Path.of(f.dbDir);
+ }
+
+ var buf = new StringWriter();
+ var out = new PrintWriter(buf);
+
+ out.println("# Generated");
+ out.println("#");
+ out.println("### engine.ninja");
+ out.println("");
+ out.println("rule engine-yaml-to-ninja");
+ out.println(" command = engine ninja");
+ out.println("");
+ out.println("build engine.ninja: engine-yaml-to-ninja engine.yaml");
+ out.println("");
+ out.println("### engine.png");
+ out.println("");
+ out.println("rule ninja-to-dot");
+ out.println(" command = ninja -t graph > $out");
+ out.println("");
+ out.println("rule dot-to-png");
+ out.println(" command = dot -Tpng < $in > $out");
+ out.println("");
+ out.println("build engine.dot: ninja-to-dot build.ninja engine.ninja");
+ out.println("");
+ out.println("build engine.png: dot-to-png engine.dot");
+ out.println("");
+ out.println("# Jobs");
+
+ for (var job : f.jobs) {
+ out.println("");
+
+ out.println("rule %s".formatted(job.name));
+ out.println(" command=engine run $name $inputs $output_state $output_includes $generated_output $agenda_groups $modules");
+ out.println();
+ var dependencies = job.inputs.stream()
+ .map(s -> dbDir.resolve(s + ".yaml").toString())
+ .collect(Collectors.joining(" "));
+
+ var outputState = dbDir.resolve(job.name + ".yaml");
+
+ var generated = List.of(outputState).stream()
+ .map(Path::toString)
+ .collect(Collectors.joining(" "));
+
+ out.println("build %s: %s %s".formatted(generated, job.name, dependencies));
+ out.println(" name=--name %s".formatted(job.name));
+
+ if (!job.inputs.isEmpty()) {
+ var is = job.inputs.stream()
+ .map(s -> "--input=" + dbDir.resolve(s + ".yaml"))
+ .collect(Collectors.joining(" $\n ", "\n ", ""));
+
+ out.println(" inputs=$%s".formatted(is));
+ }
+
+ out.println(" output_state=--output-state %s".formatted(outputState));
+ if (!job.outputIncludes.isEmpty()) {
+ var str = job.outputIncludes.stream()
+ .map(s -> "--output-include=" + s)
+ .collect(Collectors.joining(" $\n ", "\n ", ""));
+
+ out.println(" output_includes=$%s".formatted(str));
+ }
+
+ if (job.generatedOutput != null) {
+ out.println(" generated_output=--generated-output %s".formatted(fixPath(job.generatedOutput)));
+ }
+
+ if (!job.agendaGroups.isEmpty()) {
+ var ag = job.agendaGroups.stream()
+ .map(s -> "--agenda-group=" + s)
+ .collect(Collectors.joining(" $\n ", "\n ", ""));
+ out.println(" agenda_groups=%s".formatted(ag));
+ }
+
+ if (!job.modules.isEmpty()) {
+ var ms = job.modules.stream()
+ .map(this::fixPath)
+ .map(s -> "--module=" + s)
+ .collect(Collectors.joining(" $\n ", "\n ", ""));
+
+ out.println(" modules=$%s".formatted(ms));
+ }
+ }
+
+ var ninjaFile = new File(basedir, "engine.ninja");
+ try (var writer = new FileWriter(ninjaFile)) {
+ writer.write(buf.toString());
+ }
+
+ return 0;
+ }
+
+ private String fixPath(String s) {
+ if (s.startsWith("$MODULE_HOME/")) {
+ s = "$" + s;
+ }
+
+ var p = Path.of(s);
+
+ if (p.isAbsolute()) {
+ s = basepath.relativize(Path.of(s)).toString();
+ }
+
+ if (s.contains("*")) {
+ s = "$$(echo " + s + ")";
+ }
+
+ return s;
+ }
+}