diff options
Diffstat (limited to 'module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java')
-rw-r--r-- | module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java new file mode 100644 index 0000000..ef5ed1d --- /dev/null +++ b/module/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; + } +} |