From bafe762ac01d16904c18404283027e426e19bc73 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 3 Feb 2021 16:35:48 +0100 Subject: Code reorganization. Moving main code to src, keeping modules in modules/ --- .../main/java/io/trygvis/rules/engine/DbIo.java | 365 --------------------- .../java/io/trygvis/rules/engine/DbObject.java | 16 - .../main/java/io/trygvis/rules/engine/Engine.java | 172 ---------- .../rules/engine/JinjavaTemplateEngine.java | 51 --- .../main/java/io/trygvis/rules/engine/Main.java | 21 -- .../io/trygvis/rules/engine/TemplateLoader.java | 7 - .../trygvis/rules/engine/cli/DatabaseCommand.java | 20 -- .../io/trygvis/rules/engine/cli/EngineFile.java | 18 - .../io/trygvis/rules/engine/cli/NinjaCommand.java | 156 --------- .../io/trygvis/rules/engine/cli/RunCommand.java | 82 ----- 10 files changed, 908 deletions(-) delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateLoader.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/DatabaseCommand.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/EngineFile.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java (limited to 'module/ri-engine/src/main/java/io/trygvis/rules/engine') diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java deleted file mode 100644 index 7dc24ad..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java +++ /dev/null @@ -1,365 +0,0 @@ -package io.trygvis.rules.engine; - -import ch.qos.logback.core.util.FileUtil; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyName; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.introspect.Annotated; -import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; -import com.fasterxml.jackson.databind.introspect.ObjectIdInfo; -import com.fasterxml.jackson.databind.type.TypeFactory; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; -import org.drools.core.common.DefaultFactHandle; -import org.drools.core.factmodel.GeneratedFact; -import org.kie.api.KieBase; -import org.kie.api.runtime.KieContainer; -import org.kie.api.runtime.rule.FactHandle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.function.Function; - -@SuppressWarnings("unchecked") -public class DbIo { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final ObjectMapper mapper; - - private static final List prioritizedKeys = List.of("key", "name", "fqdn"); - - public DbIo(KieContainer container, KieBase kieBase) { - var factory = new YAMLFactory(); - factory.enable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID); - factory.enable(YAMLGenerator.Feature.USE_NATIVE_OBJECT_ID); - mapper = new ObjectMapper(factory); - mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); - var typeFactory = TypeFactory.defaultInstance() - .withClassLoader(new DbClassLoader(container, kieBase)); - mapper.setTypeFactory(typeFactory); - mapper.findAndRegisterModules(); - - mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() { - @Override - public ObjectIdInfo findObjectIdInfo(Annotated a) { - final Class klass = a.getRawType(); - if (GeneratedFact.class.isAssignableFrom(klass)) { - System.out.println("klass = " + klass); - - for (String name : prioritizedKeys) { - try { - final String getter = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); - klass.getMethod(getter); - return new ObjectIdInfo(PropertyName.construct(name), null, ObjectIdGenerators.PropertyGenerator.class, null); - } catch (NoSuchMethodException ignore) { - } - } - System.out.println("a.getRawType() = " + klass); - return new ObjectIdInfo(null, null, ObjectIdGenerators.IntSequenceGenerator.class, null); - } - - return super.findObjectIdInfo(a); - } - }); - } - - public List load(File file) throws IOException { - var parser = mapper.getFactory().createParser(file); - - var objects = parser.>readValueAs(new TypeReference>() {}); - - var items = new ArrayList<>(); - for (DbObject object : objects) { - try { - var type = mapper.getTypeFactory().findClass(object.type); - var x = mapper.treeToValue(object.data, type); - if (x == null) { - x = type.getDeclaredConstructor().newInstance(); - } - items.add(x); - } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { - System.out.println("e.getClass() = " + e.getClass().getName()); - System.out.println("e.getMessage() = " + e.getMessage()); - // ignore - } - } - - return items; - } - - public void dump(File file, Collection factHandles) throws IOException { - dump(file, factHandles, (o) -> true); - } - - // This should just sort by all getters instead. - static class FactCollection { - public final Class type; - public final List values; - - public FactCollection(Class type) { - this.type = type; - this.values = new ArrayList<>(); - } - - public void sort() { - var comparator = comparable(type); - - this.values.sort(comparator); - } - } - - private static final Map, Comparator> comparators = new HashMap<>(); - - private static > Comparator comparable(Class klass) { - var comparator = comparators.get(klass); - if (comparator != null) { - return comparator; - } - - // TODO: check if klass is a Comparable directly. - - var discoveredFieldsP1 = new LinkedHashMap>(); - var discoveredFieldsP2 = new LinkedHashMap>(); - - var prioritizedTypes = List.of(String.class, int.class, Number.class); - - for (var f : klass.getDeclaredFields()) { - if (f.getDeclaringClass() == Object.class) { - continue; - } - - if (!f.trySetAccessible()) { - continue; - } - - var collection = discoveredFieldsP2; - - if (prioritizedTypes.contains(f.getType())) { - collection = discoveredFieldsP1; - } - - collection.put(f.getName(), (Object o) -> { - try { - return f.get(o); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - -// for (var m : klass.getFields()) { -// if (m.getParameterCount() != 0) { -// continue; -// } -// -// var name = m.getName(); -// -// if (name.startsWith("get") && name.length() > 3 && Character.isUpperCase(name.charAt(4))) { -// name = name.substring(3, 3).toLowerCase() + name.substring(4); -// } else { -// continue; -// } -// -// if (!m.isAccessible()) { -// if (!m.trySetAccessible()) -// return null; -// } -// -// discoveredFields.put(name, m); -// } - -// System.out.printf("Sorting %s by:%n", klass.getName()); - - var discoveredFields = new LinkedHashMap<>(discoveredFieldsP1); - discoveredFields.putAll(discoveredFieldsP2); - - List> accessors = new ArrayList<>(); - for (String prioritizedKey : prioritizedKeys) { - var m = discoveredFields.remove(prioritizedKey); - if (m == null) { - continue; - } - - accessors.add(m); -// System.out.println(" + " + prioritizedKey); - } - accessors.addAll(discoveredFields.values()); -// discoveredFields.keySet().forEach((s)-> System.out.println(" - " + s)); - - comparator = (a, b) -> { -// if (klass.getName().contains("AcmeServer")) { -// System.out.println("AcmeIo.comparable"); -// } - - for (var method : accessors) { - var x = method.apply(a); - var y = method.apply(b); - - if (x == null && y == null) { - continue; - } - - if (x == null) { - return -1; - } else if (y == null) { - return 1; - } else { - var res = x.toString().compareTo(y.toString()); - if (res != 0) { - return res; - } - } - } - - return 0; - }; - - comparators.put(klass, comparator); - - return comparator; - } - - static record DbObject2(String type, Object data) { - } - - public void dump(File file, Collection factHandles, Function filter) throws IOException { - FileUtil.createMissingParentDirectories(file); - - var facts = new TreeMap, FactCollection>(Comparator.comparing(Class::getName)); - for (var handle : factHandles) { - if (handle instanceof DefaultFactHandle h) { - var obj = h.getObject(); - if (!filter.apply(obj)) { - continue; - } - - Class type = obj.getClass(); - var collection = facts.get(type); - - if (collection == null) { - collection = new FactCollection(type); - facts.put(type, collection); - } - - collection.values.add(obj); - } - } - - var objects = new ArrayList(facts.size()); - for (var e : facts.entrySet()) { - var name = e.getKey().getName(); - - var collection = e.getValue(); - collection.sort(); - for (var fact : collection.values) { - objects.add(new DbObject2(name, fact)); - } - } - - objects.sort(new DbObjectComparator()); - - var factory = mapper.getFactory(); - try (var writer = new FileWriter(file); - var g = factory.createGenerator(writer)) { - g.writeObject(objects); - } - } - - private class DbClassLoader extends ClassLoader { - private final KieContainer container; - private final KieBase kieBase; - - public DbClassLoader(KieContainer container, KieBase kieBase) { - this.container = container; - this.kieBase = kieBase; - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - logger.info("Loading class {}", name); - try { - var klass = super.loadClass(name); - logger.info("Found class in super classloader"); - return klass; - } catch (ClassNotFoundException e) { - var i = name.lastIndexOf('.'); - String pkg, simpleName; - if (i == -1) { - pkg = null; - simpleName = name; - } else { - pkg = name.substring(0, i); - simpleName = name.substring(i + 1); - } - - try { - var klass = container.getClassLoader().loadClass(name); - logger.info("Found class in container's classloader"); - return klass; - } catch (ClassNotFoundException ignore) { - } - - try { - logger.info("pkg = {}", pkg); - logger.info("simpleName = {}", simpleName); - var clazz = kieBase.getFactType(pkg, simpleName); - if (clazz != null) { - logger.info("Found class as a FactType"); - return clazz.getFactClass(); - } - } catch (UnsupportedOperationException ignore) { - } - - logger.warn("Class not found: {}", name); - - throw e; - } - } - } - - private static class DbObjectComparator implements Comparator { - private final List prioritizedPackages = List.of( - "io.trygvis.rules.machine", - "io.trygvis.rules.network", - "io.trygvis.rules.dns", - "io.trygvis.rules.dba", - "io.trygvis.rules", - "io.trygvis.rules.core"); - - @Override - public int compare(DbObject2 a, DbObject2 b) { - var indexA = a.type.lastIndexOf("."); - String packageA = indexA == -1 ? null : a.type.substring(0, indexA); - String classA = indexA == -1 ? a.type : a.type.substring(indexA + 1); - - var indexB = b.type.lastIndexOf("."); - String packageB = indexB == -1 ? null : b.type.substring(0, indexB); - String classB = indexB == -1 ? b.type : b.type.substring(indexB + 1); - - var priIdxA = prioritizedPackages.indexOf(packageA); - var priIdxB = prioritizedPackages.indexOf(packageB); - - if (priIdxA == -1 && priIdxB == -1) { - return classB.compareTo(classA); - } else if (priIdxA == -1) { - return 1; - } else if (priIdxB == -1) { - return -1; - } - return priIdxA - priIdxB; -// var diff = priIdxB - priIdxA; -// if (diff != 0) { -// return diff; -// } -// -// return classB.compareTo(classA); - } - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java deleted file mode 100644 index 6b9817e..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.trygvis.rules.engine; - -import com.fasterxml.jackson.databind.node.ObjectNode; - -public final class DbObject { - public String type; - public ObjectNode data; - - public DbObject() { - } - - public DbObject(String type, ObjectNode data) { - this.type = type; - this.data = data; - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java deleted file mode 100644 index f2247d3..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java +++ /dev/null @@ -1,172 +0,0 @@ -package io.trygvis.rules.engine; - -import org.drools.core.audit.WorkingMemoryConsoleLogger; -import org.drools.core.base.MapGlobalResolver; -import org.drools.reflective.classloader.ProjectClassLoader; -import org.kie.api.KieServices; -import org.kie.api.event.rule.AgendaEventListener; -import org.kie.api.event.rule.RuleRuntimeEventListener; -import org.kie.api.io.Resource; -import org.kie.api.runtime.KieContainer; -import org.kie.api.runtime.KieSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import java.io.Closeable; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -public class Engine implements Closeable { - @SuppressWarnings("FieldCanBeLocal") - private final Logger logger = LoggerFactory.getLogger(getClass()); - - public final String name; - @Nullable - public final File output; - public final DbIo io; - public final KieSession session; - - public Engine(String name, File[] databases, @Nullable File output, String[] agendaGroups, File[] modules) - throws IOException { - this.name = name; - this.output = output; - - logger.info("Getting KieServices"); - - var services = KieServices.Factory.get(); - - var kieRepository = services.getRepository(); - - KieContainer container; - TemplateLoader templateLoader; - if (modules != null && modules.length > 0) { - List resources = new ArrayList<>(); - List files = new ArrayList<>(); - for (File path : modules) { - if (!path.exists()) { - logger.warn("Module path does not exist: {}", path.getAbsolutePath()); - continue; - } - - logger.info("New KieBuilder: {}, file={}, directory={}", path, path.isFile(), path.isDirectory()); - - if (path.isFile()) { - files.add(path.toURI().toURL()); - } - - var resource = services.getResources().newFileSystemResource(path); - logger.info("resource.getResourceType() = {}", resource.getResourceType()); - resources.add(resource); - } - - var module = kieRepository.addKieModule(resources.get(0), resources.subList(1, resources.size()).toArray(new Resource[0])); - logger.info("module.getReleaseId() = {}", module.getReleaseId()); - var rId = module.getReleaseId(); - - logger.info("Creating classpath container, releaseId=" + rId); - container = services.newKieContainer(rId); - - templateLoader = new ClasspathTemplateLoader(new URLClassLoader(files.toArray(new URL[0]))); - } else { - var classLoader = ProjectClassLoader.findParentClassLoader(); - container = services.getKieClasspathContainer(classLoader); - templateLoader = new ClasspathTemplateLoader(classLoader); - } - - logger.info("Creating KieBase \"{}\"", name); - logger.info("Available kie base names: {}", container.getKieBaseNames()); - var kieBase = container.getKieBase(name); - - session = container.newKieSession(name); - - var l = new WorkingMemoryConsoleLogger(session); - session.addEventListener((AgendaEventListener) l); - session.addEventListener((RuleRuntimeEventListener) l); - - session.getGlobals().setDelegate(new EngineGlobalResolver(templateLoader)); - - logger.info("Loading data"); - io = new DbIo(container, kieBase); - - List allObjects = new ArrayList<>(); - for (File database : databases) { - var objects = io.load(database); - - if (objects.isEmpty()) { - logger.warn("Did not load any objects, something is wrong"); - return; - } - - logger.info("Loaded {} objects from {}", objects.size(), database); - allObjects.addAll(objects); - } - logger.info("Loaded {} objects", allObjects.size()); - - for (var object : allObjects) { - logger.info("object = " + object); - session.insert(object); - } - - for (var agendaGroup : agendaGroups) { - logger.info("Setting agenda: " + agendaGroup); - session.getAgenda().getAgendaGroup(agendaGroup).setFocus(); - session.fireAllRules(); - } - } - - @Override - public void close() { - session.dispose(); - } - - private static class ClasspathTemplateLoader implements TemplateLoader { - private final ClassLoader classLoader; - - private ClasspathTemplateLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - @Override - public String load(String name) throws IOException { - var resource = "templates/" + name + ".j2"; - - try (var inputStream = classLoader.getResourceAsStream(resource)) { - if (inputStream == null) { - throw new FileNotFoundException("Classpath resource: " + resource); - } - - return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - } - } - } - - private class EngineGlobalResolver extends MapGlobalResolver { - private final TemplateLoader templateLoader; - - public EngineGlobalResolver() { - templateLoader = null; - } - - public EngineGlobalResolver(TemplateLoader templateLoader) { - this.templateLoader = templateLoader; - } - - @Override - public Object resolveGlobal(String identifier) { - if ("te".equals(identifier)) { - if (output == null) { - throw new IllegalArgumentException("An instance of the TemplateEngine is required, but this job is not configured with a output directory."); - } - return new JinjavaTemplateEngine(templateLoader, output); - } - return super.resolveGlobal(identifier); - } - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java deleted file mode 100644 index ba23089..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.trygvis.rules.engine; - -import ch.qos.logback.core.util.FileUtil; -import com.hubspot.jinjava.Jinjava; -import org.apache.commons.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Map; -import java.util.Objects; - -/** - * TODO: cache templates. - */ -public class JinjavaTemplateEngine implements TemplateEngine { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final Jinjava jinjava = new Jinjava(); - - private final TemplateLoader loader; - private final File basedir; - - public JinjavaTemplateEngine(TemplateLoader templateLoader, File basedir) { - Objects.requireNonNull(templateLoader); - Objects.requireNonNull(basedir); - this.loader = templateLoader; - this.basedir = basedir; - } - - @Override - public void clean() { - try { - logger.info("Removing output directory: {}", basedir); - FileUtils.deleteDirectory(basedir); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public void template(String name, String output, Map params) throws IOException { - var template = loader.load(name); - String renderedTemplate = jinjava.render(template, params); - var f = new File(basedir, output); - FileUtil.createMissingParentDirectories(f); - Files.writeString(f.toPath(), renderedTemplate); - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java deleted file mode 100644 index dc9ed02..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.trygvis.rules.engine; - -import io.trygvis.rules.engine.cli.DatabaseCommand; -import io.trygvis.rules.engine.cli.NinjaCommand; -import io.trygvis.rules.engine.cli.RunCommand; -import picocli.CommandLine; -import picocli.CommandLine.Command; - -@Command( - name = "engine", - subcommands = {RunCommand.class, DatabaseCommand.class, NinjaCommand.class}, - mixinStandardHelpOptions = true, - version = "UNSPECIFIED") -class Main { - - public static void main(String... args) { - //noinspection InstantiationOfUtilityClass - int exitCode = new CommandLine(new Main()).execute(args); - System.exit(exitCode); - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateLoader.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateLoader.java deleted file mode 100644 index 9441264..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateLoader.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.trygvis.rules.engine; - -import java.io.IOException; - -interface TemplateLoader { - String load(String name) throws IOException; -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/DatabaseCommand.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/DatabaseCommand.java deleted file mode 100644 index 03650b5..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/DatabaseCommand.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.trygvis.rules.engine.cli; - -import picocli.CommandLine.Command; - -import java.util.concurrent.Callable; - -import static picocli.CommandLine.Option; - -@Command(name = "database") -public class DatabaseCommand implements Callable { - - @Option(names = {"-v", "--verbose"}) - private boolean verbose; - - @Override - public Integer call() { - System.out.println("DatabaseCommand.call"); - return 0; - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/EngineFile.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/EngineFile.java deleted file mode 100644 index 8da0e39..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/EngineFile.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.trygvis.rules.engine.cli; - -import java.util.ArrayList; -import java.util.List; - -public class EngineFile { - public String dbDir; - public List jobs; - - public static class Job { - public String name; - public List inputs = new ArrayList<>(); - public List outputIncludes = new ArrayList<>(); - public String generatedOutput; - public List agendaGroups = new ArrayList<>(); - public List modules = new ArrayList<>(); - } -} 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 deleted file mode 100644 index ef5ed1d..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/NinjaCommand.java +++ /dev/null @@ -1,156 +0,0 @@ -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 { - - 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; - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java deleted file mode 100644 index 35f30cd..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.trygvis.rules.engine.cli; - -import io.trygvis.rules.engine.Engine; - -import java.io.File; -import java.util.concurrent.Callable; - -import static picocli.CommandLine.Command; -import static picocli.CommandLine.Option; - -@Command(name = "run") -public class RunCommand implements Callable { - - @Option(names = {"-n", "--name"}) - public String name; - - @Option(names = {"-i", "--input"}) - public File[] input; - - @Option(names = {"--output-state"}) - public File outputState; - - @Option(names = {"--output-include"}, split = ",", arity = "1..*") - public String[] outputIncludes; - - @Option(names = {"--generated-output"}) - public File generatedOutput; - - @Option(names = {"--agenda-group"}) - public String[] agendaGroups; - - @Option(names = {"--module"}, split = ",", arity = "1..*") - public File[] module; - - @Override - public Integer call() throws Exception { - - if (agendaGroups == null || agendaGroups.length == 0) { - agendaGroups = new String[]{"init", "generate"}; - } - - try (var engine = new Engine(name, input, generatedOutput, agendaGroups, module)) { - engine.io.dump(outputState, engine.session.getFactHandles(), (Object o) -> - { - if (outputIncludes == null || outputIncludes.length == 0) { - return true; - } - - var name = o.getClass().getName(); - var simpleName = o.getClass().getSimpleName(); - - for (var i : outputIncludes) { - var ok = false; - if (i.startsWith("*")) { - i = i.substring(1); - - if (i.endsWith("*")) { - i = i.substring(1, i.length() - 2); - ok = name.contains(i); - } else { - ok = name.startsWith(i) || simpleName.startsWith(i); - } - } else if (i.endsWith("*")) { - i = i.substring(0, i.length() - 2); - ok = name.startsWith(i) || simpleName.startsWith(i); - } else { - ok = name.equals(i) || simpleName.equals(i); - } - - if (ok) { - return true; - } - } - - return false; - } - ); - } - - return 0; - } -} -- cgit v1.2.3