diff --git a/docs/emc/EMC_config.md b/docs/emc/EMC_config.md
index de41212..9f9625e 100644
--- a/docs/emc/EMC_config.md
+++ b/docs/emc/EMC_config.md
@@ -422,9 +422,9 @@ The following properties and methods are available for this class:
-#### `String` **`directoryName`**
+#### `String` **`directoryPath`**
-Returns the directory name if available. Otherwise returns `null`
+Returns the directory path if available. Otherwise returns `null`
diff --git a/pom.xml b/pom.xml
index 233e1ea..2591844 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,16 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ -parameters
+
+
+
diff --git a/src/main/java/org/entityc/compiler/ASTVisitor.java b/src/main/java/org/entityc/compiler/ASTVisitor.java
index aded481..09c61f1 100644
--- a/src/main/java/org/entityc/compiler/ASTVisitor.java
+++ b/src/main/java/org/entityc/compiler/ASTVisitor.java
@@ -2264,6 +2264,7 @@ public Object visitTemplates(EntityLanguageParser.TemplatesContext ctx) {
MTRepositoryImport thisImport = new MTRepositoryImport(ctx.templatesBody().templatesImport(), false);
thisImport.setRepositoryName(repositoryImport.getRepositoryName());
thisImport.setFilename(template.getFilename());
+ thisImport.setDirectoryPath(template.getDirectoryPath());
template.setRepositoryImport(thisImport);
}
}
@@ -2283,7 +2284,7 @@ public MTTemplate visitTemplate(EntityLanguageParser.TemplateContext ctx) {
MTTemplate template = new MTTemplate(ctx, currentConfiguration, ctx.id().getText());
if (ctx.STRING() != null) {
- template.setDirectoryName(ECStringUtil.ProcessParserString(ctx.STRING().getText()));
+ template.setDirectoryPath(ECStringUtil.ProcessParserString(ctx.STRING().getText()));
}
EntityLanguageParser.TemplateBodyContext body = ctx.templateBody();
if (body == null) {
diff --git a/src/main/java/org/entityc/compiler/CommandLineParser.java b/src/main/java/org/entityc/compiler/CommandLineParser.java
deleted file mode 100644
index b983173..0000000
--- a/src/main/java/org/entityc/compiler/CommandLineParser.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
- * Use of this file is governed by the BSD 3-clause license that
- * can be found in the LICENSE.md file in the project root.
- */
-
-package org.entityc.compiler;
-
-import org.apache.commons.io.filefilter.WildcardFileFilter;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static java.lang.System.exit;
-
-class CommandLineParser {
-
- private final Map defineValues = new HashMap<>();
- public boolean help = false;
- public boolean version = false;
- public boolean verbose = false;
- public List sourceFileNames = new ArrayList<>();
- public boolean advanceSchemaVersion = false;
- public boolean deleteSchema = false;
- public String configurationName;
- public List templateSearchPaths = new ArrayList<>();
- public String templateToRun;
- public String templateToFormat;
- public String templateToFormatInPath;
- public String templateToFormatOutPath;
- public String setupUri;
-
- public String getDefineValue(String name) {
- return defineValues.get(name);
- }
-
- public boolean parse(String[] args) {
- int index = 0;
- while (index < args.length) {
- String arg = args[index++];
-
- if (!arg.startsWith("-")) {
- if (arg.contains("*")) {
- processWildcardArg(arg);
- } else {
- sourceFileNames.add(arg);
- }
- continue;
- }
-
- if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")) {
- help = true;
- return false;
- }
-
- if (arg.equals("-v") || arg.equals("-version") || arg.equals("--version")) {
- version = true;
- return false;
- }
-
- if (arg.equals("-verbose") || arg.equals("--verbose")) {
- verbose = true;
- }
-
- if ((arg.equals("-c") || arg.equals("-config") || arg.equals("--config")) && index < args.length) {
- configurationName = args[index++];
- }
-
- if (arg.equals("-tp") && index < args.length) {
- String pathsString = args[index++];
- for (String path : pathsString.split(":")) {
- templateSearchPaths.add(path);
- }
- }
-
- if (arg.equals("-rt") && index < args.length) {
- templateToRun = args[index++];
- }
-
- if (arg.equals("-tf") && index < args.length) {
- templateToFormat = args[index++];
- }
-
- if (arg.equals("-tfin") && index < args.length) {
- templateToFormatInPath = args[index++];
- }
- if (arg.equals("-tfout") && index < args.length) {
- templateToFormatOutPath = args[index++];
- }
-
- if (arg.equals("-s") || arg.equals("-setup") || arg.equals("--setup")) {
- setupUri = args[index++];
- }
-
- if (arg.equals("-asv")) {
- advanceSchemaVersion = true;
- } else if (arg.equals("-sdelete")) {
- deleteSchema = true;
- }
-
- String nameValue = null;
- if (arg.equals("-D") && (index < args.length)) {
- nameValue = args[index++];
- } else if (arg.startsWith("-D")) {
- nameValue = arg.substring(2);
- }
- if (nameValue != null) {
- String[] nameAndValue = nameValue.split("=");
- if (nameAndValue.length == 2) {
- defineValues.put(nameAndValue[0], nameAndValue[1]);
- }
- }
- }
- return false;
- }
-
- private void processWildcardArg(String arg) {
- String[] args = arg.split("\\/");
- if (args.length == 1) {
- processSingleDirWildcardArg(arg, ".");
- } else {
- int lastSegmentIndex = args.length - 1;
- if (!args[lastSegmentIndex].contains("*")) {
- System.err.println("ERROR: wildcards only supported in last path segment.");
- exit(1);
- }
- String dirPath = args[0];
- for (int i = 1; i < args.length - 1; i++) {
- dirPath += File.separator + args[i];
- }
- processSingleDirWildcardArg(args[lastSegmentIndex], dirPath);
- }
- }
-
- private void processSingleDirWildcardArg(String arg, String dirpath) {
- File dir = new File(dirpath);
- FileFilter fileFilter = new WildcardFileFilter(arg);
- File[] files = dir.listFiles(fileFilter);
- for (File file : files) {
- sourceFileNames.add(dirpath + File.separator + file.getName());
- }
- }
-
- public void printUsage() {
- System.out.println("ec [options] sourceFile [...]");
- System.out.println();
- System.out.println("Options:");
- System.out.println("-h Print this help.");
- System.out.println("-v Print compiler version.");
- System.out.println("-verbose Outputs informational messages.");
- System.out.println("-c configName The name of the configuration to use.");
- System.out.println(
- "-asv Advances the current schema version the next time a new schema version is generated.");
- System.out.println("-sdelete Deletes all the schema files.");
- System.out.println("-tp path:... Specifies colon delimited search path for templates.");
- System.out.println("-rt name Runs only the specified template.");
- System.out.println("-tf name Formats template file.");
- System.out.println("-tfin path Formats template file specifying its file path.");
- System.out.println(
- "-tfout path Sends the formatted file to the specified file path (default is same as -tfin path).");
- System.out.println("-D name=value Defines a variable to a value - they can be accessed via templates.");
- System.out.println("-setup uri Creates a new project using the specified setup URI, where the URI is:");
- System.out.println(" site:organization/reponame:tag/setupName");
- System.out.println(" site - only github is currently supported.");
- System.out.println(" organization - The github organization for the setup repo.");
- System.out.println(" reponame - The name of the repo.");
- System.out.println(" tag - The tag from which to pull the setup files.");
- System.out.println(
- " setupName - Path and name of setup file to run (e.g. setups/BasicWebAppSetup).");
- System.out.println(
- " This option requires that you use the -D option to define the following variable names:");
- System.out.println(
- " appIdentifier - A unique name for your app (e.g., basic-app). This will be the name");
- System.out.println(
- " of the created project directory. This would likely be its github");
- System.out.println(
- " repository name as well if it where to be uploaded there.");
- System.out.println(" appName - A name for your app (e.g., BasicApp).");
- System.out.println(
- " apiPrefixNamespace - Represents a URL path prefix for all endpoints of the app. This");
- System.out.println(
- " variable should use a \".\" as a delimiter (e.g., api.basicapp");
- System.out.println(
- " which would result in api/basicapp/ as a url path prefix.");
- System.out.println(
- " appBasePackage - This is the base Java package to use for all generated code for the app.");
- }
-}
diff --git a/src/main/java/org/entityc/compiler/EntityCompiler.java b/src/main/java/org/entityc/compiler/EntityCompiler.java
index ca58269..95394d4 100644
--- a/src/main/java/org/entityc/compiler/EntityCompiler.java
+++ b/src/main/java/org/entityc/compiler/EntityCompiler.java
@@ -10,39 +10,28 @@
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.apache.commons.io.IOUtils;
-import org.entityc.compiler.model.MTCodeFormat;
-import org.entityc.compiler.model.MTModule;
+import org.entityc.compiler.cmdline.CommandLine;
import org.entityc.compiler.model.MTRoot;
import org.entityc.compiler.model.config.MTConfiguration;
-import org.entityc.compiler.model.config.MTDirectory;
-import org.entityc.compiler.model.config.MTFile;
import org.entityc.compiler.model.config.MTProtoc;
-import org.entityc.compiler.model.config.MTRepository;
import org.entityc.compiler.model.config.MTRepositoryImport;
import org.entityc.compiler.model.config.MTSpace;
import org.entityc.compiler.model.config.MTSpaceInclude;
import org.entityc.compiler.model.config.MTTemplate;
import org.entityc.compiler.model.config.MTTransform;
-import org.entityc.compiler.model.domain.MTDEntity;
-import org.entityc.compiler.model.domain.MTDModule;
-import org.entityc.compiler.model.domain.MTDomain;
-import org.entityc.compiler.model.entity.MTEntity;
import org.entityc.compiler.protobuf.PBLoaderExtractor;
import org.entityc.compiler.repository.RepositoryCache;
import org.entityc.compiler.repository.RepositoryFile;
import org.entityc.compiler.repository.RepositoryImportManager;
-import org.entityc.compiler.structure.sql.SSSchemaVersioning;
import org.entityc.compiler.transform.MTBaseTransform;
import org.entityc.compiler.transform.TransformManager;
import org.entityc.compiler.transform.template.FileTemplateTransform;
import org.entityc.compiler.transform.template.TemplatePublishing;
import org.entityc.compiler.transform.template.TemplateTransform;
-import org.entityc.compiler.transform.template.tree.FTTemplate;
-import org.entityc.compiler.transform.template.tree.FTTransformSession;
import org.entityc.compiler.util.ECANTLRErrorListener;
import org.entityc.compiler.util.ECLog;
-import org.entityc.compiler.util.ECSessionManager;
import org.entityc.compiler.util.ECStringUtil;
+import org.entityc.compiler.util.LogHandler;
import java.io.File;
import java.io.FileInputStream;
@@ -50,271 +39,63 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import java.util.logging.Handler;
-import java.util.logging.Level;
+import java.util.Map;
+import java.util.Set;
import java.util.logging.LogManager;
-import java.util.logging.LogRecord;
import java.util.logging.Logger;
-import java.util.stream.Stream;
import static java.lang.System.exit;
-class LogHandler extends Handler {
-
- @Override
- public void publish(LogRecord record) {
- String fullClassPath = record.getSourceClassName();
- String[] parts = fullClassPath.split("\\.");
- String justClassName = parts[parts.length - 1];
-
- StringBuilder sb = new StringBuilder();
- sb.append(record.getLevel().getName());
- sb.append(": ");
- sb.append(justClassName);
- sb.append(".");
- sb.append(record.getSourceMethodName());
- sb.append("()| ");
- sb.append(record.getMessage());
- if (record.getLevel() == Level.SEVERE) {
- System.err.println(sb);
- } else {
- System.out.println(sb);
- }
- }
-
- @Override
- public void flush() {
-
- }
-
- @Override
- public void close() throws SecurityException {
-
- }
-}
-
public class EntityCompiler {
- public static final String COMPILER_VERSION = "0.12.6";
- public static final String LANGUAGE_VERSION = "0.12.3";
- private static CommandLineParser cmdLineParser;
+ public static final String COMPILER_VERSION = "0.13.0";
+ public static final String LANGUAGE_VERSION = "0.12.3";
+ private static final Map defineValues = new HashMap<>();
+ private static final Set templateSearchPath = new HashSet<>();
+ private static CommandLine commandLine;
- public static final List GetTemplateSearchPaths() {
- return cmdLineParser.templateSearchPaths;
- }
+ public static void main(String[] args) {
- public static final String GetDefineValue(String name, String defaultValue) {
- String value = cmdLineParser.getDefineValue(name);
- if (value == null) {
- value = defaultValue;
- }
- return value;
- }
+ setupLogger();
- public static final boolean ShouldAdvanceSchemaVersion() {
- return cmdLineParser.advanceSchemaVersion;
+ commandLine = new CommandLine();
+ commandLine.run(args);
}
- public static final boolean isVerbose() {
- return cmdLineParser != null && cmdLineParser.verbose;
+ private static void setupLogger() {
+ LogManager.getLogManager().reset();
+ Logger rootLogger = LogManager.getLogManager().getLogger("");
+ rootLogger.addHandler(new LogHandler());
}
- private static String readLineByLineJava8(String filePath) {
- StringBuilder contentBuilder = new StringBuilder();
-
- try (Stream stream = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) {
- stream.forEach(s -> contentBuilder.append(s).append("\n"));
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return contentBuilder.toString();
+ public static void RunConfiguration(MTConfiguration configuration) {
+ MTRoot root = configuration.getRoot();
+ EntityCompiler.LoadTransforms(root, configuration);
+ EntityCompiler.RunTransforms(root, configuration);
+ EntityCompiler.RunProtoc(root, configuration);
}
- public static void main(String[] args) {
-
- setupLogger();
-
- cmdLineParser = new CommandLineParser();
-
- cmdLineParser.parse(args);
-
- if (cmdLineParser.help) {
- cmdLineParser.printUsage();
- exit(0);
- }
-
- if (cmdLineParser.version) {
- System.out.println("ec compiler version " + COMPILER_VERSION + ", language version " + LANGUAGE_VERSION);
- exit(0);
- }
-
- boolean setupMode = cmdLineParser.setupUri != null;
-
- boolean codeFormattingOnly = !setupMode && (cmdLineParser.templateToFormat != null
- || cmdLineParser.templateToFormatInPath != null);
- if (cmdLineParser.sourceFileNames.size() < 1) {
- if (cmdLineParser.deleteSchema) {
- SSSchemaVersioning.DeleteEntireSchema();
- exit(0);
- }
- if (!codeFormattingOnly && !setupMode) {
- System.err.println("ERROR: Must specify at least one source file.");
- exit(1);
- }
- }
-
- // root node for all things read in during this execution session
- MTRoot root = new MTRoot(null);
-
- List sourceFilenames = new ArrayList<>();
- String configurationName = cmdLineParser.configurationName;
-
- if (setupMode) {
- // site : organization / repo-name / path-to-setup-edl
- MTRepository repository = new MTRepository(cmdLineParser.setupUri);
- repository.setName("SetupRepo");
- if (cmdLineParser.getDefineValue("appIdentifier") == null) {
- ECLog.logFatal("Must define variable \"appIdentifier\" on the command line.");
- }
- EntityCompiler.ensureDirectory(cmdLineParser.getDefineValue("appIdentifier"));
- MTRepositoryImport repositoryImport = new MTRepositoryImport(null, false);
- MTSpace space = new MTSpace(null, "Setup");
- root.setSpace(space);
- space.addRepository(repository);
- repositoryImport.setRepositoryName(repository.getName());
- repositoryImport.setFilename(repository.getSetupFilename());
- RepositoryImportManager importManager = new RepositoryImportManager(
- RepositoryCache.CacheStructure.TempDirectory);
- ECLog.logInfo("Fetching setup: " + repository.getSetupFilename());
- RepositoryFile repositoryFile = importManager.importFromRepository(space,
- repositoryImport, "edl", false);
- sourceFilenames.add(repositoryFile.getFilepath());
- configurationName = "Setup";
- } else {
- sourceFilenames.addAll(cmdLineParser.sourceFileNames);
- }
-
- ECSessionManager.getInstance().start();
-
- // get all filenames passed on command line and parse those files
- ArrayList repositoryFiles = new ArrayList<>();
- for (String sourceFilename : sourceFilenames) {
- repositoryFiles.add(new RepositoryFile(sourceFilename, false));
- }
- parseSourceFiles(root, null, repositoryFiles, codeFormattingOnly);
-
- // CODE FORMATTING
- if (cmdLineParser.templateToFormat != null) {
- MTSpace space = new MTSpace(null, "formatterSpace");
- root.setSpace(space);
- MTConfiguration config = new MTConfiguration(null, root, "formatter");
- root.addConfiguration(config);
-
- MTFile file = null;
- for (String basePath : cmdLineParser.templateSearchPaths) {
- File f = new File(basePath + File.separator + cmdLineParser.templateToFormat + ".eml");
- if (f.exists()) {
- file = new MTFile(null, f);
- }
- }
- MTTemplate mtTemplate = new MTTemplate(null, config, file);
- TransformManager.AddTransform(new FileTemplateTransform(config, mtTemplate, file.getPath()));
- FTTemplate ftTemplate = mtTemplate.parse((FTTransformSession) null, true);
- File outFile = null;
- if (cmdLineParser.templateToFormatOutPath != null) {
- outFile = new File(cmdLineParser.templateToFormatOutPath);
- } else {
- outFile = new File(file.getPath());
- }
- MTCodeFormat codeFormat = root.getCodeFormat("Default");
- ftTemplate.formatCodeToFile(outFile, codeFormat);
- exit(0);
- }
- // CODE FORMATTING
- if (cmdLineParser.templateToFormatInPath != null) {
- MTSpace space = new MTSpace(null, "formatterSpace");
- root.setSpace(space);
- MTConfiguration config = new MTConfiguration(null, root, "formatter");
- root.addConfiguration(config);
- MTFile file = null;
- File f = new File(cmdLineParser.templateToFormatInPath);
- if (f.exists()) {
- file = new MTFile(null, f);
- } else {
- ECLog.logFatal("The specified template file to format does not exist: "
- + cmdLineParser.templateToFormatInPath);
- }
-
- MTTemplate mtTemplate = new MTTemplate(null, config, file);
- TransformManager.AddTransform(new FileTemplateTransform(config, mtTemplate, file.getPath()));
- FTTemplate ftTemplate = mtTemplate.parse((FTTransformSession) null, true);
- File outFile = null;
- if (cmdLineParser.templateToFormatOutPath != null) {
- outFile = new File(cmdLineParser.templateToFormatOutPath);
- } else {
- outFile = new File(file.getPath());
- }
- MTCodeFormat codeFormat = root.getCodeFormat("Default");
- ftTemplate.formatCodeToFile(outFile, codeFormat);
- exit(0);
- }
-
- // Get configuration name from command line - this is used to only execute a configuration
- // by that name from the files read in.
- if (configurationName == null) {
- if (root.getConfigurationNames().size() == 1) {
- configurationName = root.getConfigurationNames().get(0);
- }
- }
-
- MTConfiguration configuration = configurationName != null ?
- root.getConfiguration(configurationName) :
- null;
-
- if (configuration == null) {
- ECLog.logFatal("Need to specify a configuration.");
- }
- if (setupMode) {
- // add the project directory we created above to the start of the output path
- MTDirectory outputDirectory = configuration.getOutputByName("SetupTargetDir");
- if (outputDirectory == null) {
- ECLog.logFatal("Setup needs an output defined by the name of \"SetupTargetDir\".");
- }
- outputDirectory.setPath(cmdLineParser.getDefineValue("appIdentifier") + "/" + outputDirectory.getPath());
-
- outputDirectory = configuration.getOutputByName("ProjectTopDir");
- if (outputDirectory != null) {
- outputDirectory.setPath(
- cmdLineParser.getDefineValue("appIdentifier") + "/" + outputDirectory.getPath());
- }
- }
-
-
+ public static void LoadTransforms(MTRoot root, MTConfiguration configuration) {
+ String configurationName = configuration.getName();
// Load any built in transforms (such as the postgres one)
TransformManager.LoadBuiltins(root, configurationName);
- if (cmdLineParser.deleteSchema) {
- SSSchemaVersioning.DeleteEntireSchema();
- }
-
// templates
boolean failedToLoadTransform = false;
for (MTTransform transformSpec : configuration.getTransforms()) {
if (transformSpec.isTemplate()) {
- MTTemplate template = (MTTemplate) transformSpec;
- if (cmdLineParser.templateToRun != null && !template.getName().equals(cmdLineParser.templateToRun)) {
+ MTTemplate template = (MTTemplate) transformSpec;
+ if (commandLine.templateToRun != null && !template.getName().equals(commandLine.templateToRun)) {
continue;
}
RepositoryFile repositoryFile;
String templateFilename;
if (template.getRepositoryImport() != null) {
- if (cmdLineParser.verbose) {
+ if (commandLine.verbose) {
ECLog.logInfo("Getting template " + template.getName() + " from repository: "
+ template.getRepositoryImport().getRepositoryName());
}
@@ -345,10 +126,9 @@ public static void main(String[] args) {
if (failedToLoadTransform) {
exit(1);
}
+ }
- if (cmdLineParser.verbose) {
- ECLog.logInfo("RESOLVING REFERENCES...");
- }
+ public static void RunTransforms(MTRoot root, MTConfiguration configuration) {
root.resolveReferences(false);
//model.processAssetAttributes();
root.getSpace().checkValidReferences();
@@ -360,7 +140,7 @@ public static void main(String[] args) {
if (transform instanceof FileTemplateTransform) {
continue; // skip templates for now
}
- if (cmdLineParser.verbose) {
+ if (commandLine.verbose) {
System.out.println("Running " + "transform" + " " + transform.getName());
}
transform.start();
@@ -370,7 +150,6 @@ public static void main(String[] args) {
root.getSpace().checkValidReferences();
ArrayList fileTemplatesToRun = new ArrayList<>();
- // Non-Contextual Templates
for (MTTransform transformSpec : configuration.getTransforms()) {
if (transformSpec instanceof MTTemplate) {
if (((MTTemplate) transformSpec).isContextual()) {
@@ -380,12 +159,12 @@ public static void main(String[] args) {
if (transform instanceof FileTemplateTransform) {
TemplateTransform templateTransform = (TemplateTransform) transform;
templateTransform.setConfig(transformSpec.getConfig());
- if (cmdLineParser.verbose) {
+ if (commandLine.verbose) {
System.out.println("Loading template " + templateTransform.getName());
}
templateTransform.load();
fileTemplatesToRun.add((FileTemplateTransform) templateTransform);
- if (cmdLineParser.verbose) {
+ if (commandLine.verbose) {
System.out.println("Finished Loading template " + templateTransform.getName());
}
}
@@ -405,60 +184,9 @@ public static void main(String[] args) {
for (FileTemplateTransform transform : fileTemplatesToRun) {
transform.run();
}
+ }
- // Contextual Templates
- for (MTTransform transformSpec : configuration.getTransforms()) {
- if (transformSpec instanceof MTTemplate) {
- if (!((MTTemplate) transformSpec).isContextual()) {
- continue;
- }
-
- MTBaseTransform transform = TransformManager.GetTransformByName(transformSpec.getName());
- if (!(transform instanceof TemplateTransform)) {
- continue;
- }
-
- String templateName = transformSpec.getName();
-
- for (MTDomain domain : root.getSpace().getDomains()) {
- for (MTEntity entity : root.getSpace().getEntities()) {
- MTDEntity domainEntity = domain.getDomainEntity(entity, true);
- if (domainEntity.getApplyTemplate() != null
- && domainEntity.getApplyTemplate().getTemplateName().equals(templateName)) {
- if (EntityCompiler.isVerbose()) {
- ECLog.logInfo(
- "Running entity contextual template " + transform.getName() + " for domain "
- + domain.getName() + " on entity " + entity.getName());
- }
- ((TemplateTransform) transform).start(domainEntity.getApplyTemplate(), entity);
- } else {
- MTModule module = entity.getModule();
- MTDModule domainModule = module != null ?
- domain.getDomainModule(module, true) :
- null;
- if (domainModule != null && domainModule.getApplyTemplate() != null
- && domainModule.getApplyTemplate().getTemplateName().equals(templateName)) {
- if (EntityCompiler.isVerbose()) {
- ECLog.logInfo(
- "Running module contextual template " + transform.getName() + " for domain "
- + domain.getName() + " in module " + module.getName() + " on entity "
- + entity.getName());
- }
- ((TemplateTransform) transform).start(domainModule.getApplyTemplate(), entity);
- } else if (domain.getApplyTemplate() != null
- && domain.getApplyTemplate().getTemplateName().equals(templateName)) {
- if (EntityCompiler.isVerbose()) {
- ECLog.logInfo(
- "Running domain contextual template " + transform.getName() + " for domain "
- + domain.getName() + " on entity " + entity.getName());
- }
- ((TemplateTransform) transform).start(domain.getApplyTemplate(), entity);
- }
- }
- }
- }
- }
- }
+ public static void RunProtoc(MTRoot root, MTConfiguration configuration) {
// PROTOBUF COMPILER
for (MTProtoc protoc : configuration.getProtocs()) {
@@ -684,10 +412,46 @@ public static void main(String[] args) {
}
}
}
- ECSessionManager.getInstance().close();
}
- private static void parseSourceFiles(MTRoot root, MTSpace space, List repositoryFiles, boolean ignoreSpaceRequirement) {
+ public static final boolean isVerbose() {
+ return commandLine != null && commandLine.verbose;
+ }
+
+ public static boolean ensureDirectory(File dir) {
+ if (!dir.exists()) {
+ boolean created = dir.mkdirs();
+ return created && dir.exists();
+ }
+ return true;
+ }
+
+ public static boolean ensureDirectory(String directoryPath) {
+ File dir = new File(directoryPath);
+ return ensureDirectory(dir);
+ }
+
+ public static final String GetDefineValue(String name, String defaultValue) {
+ String value = GetDefineValue(name);
+ if (value == null) {
+ value = defaultValue;
+ }
+ return value;
+ }
+
+ public static String GetDefineValue(String name) {
+ return defineValues.get(name);
+ }
+
+ public static void SetDefineValue(String name, String value) {
+ defineValues.put(name, value);
+ }
+
+ public static final boolean ShouldAdvanceSchemaVersion() {
+ return commandLine.advanceSchemaVersion;
+ }
+
+ public static void parseSourceFiles(MTRoot root, MTSpace space, List repositoryFiles, boolean ignoreSpaceRequirement) {
// parse each source file and
for (RepositoryFile repositoryFile : repositoryFiles) {
if (space != null) {
@@ -697,8 +461,7 @@ private static void parseSourceFiles(MTRoot root, MTSpace space, List commands = new HashMap<>();
+
+ public boolean help = false;
+ public boolean version = false;
+ public boolean verbose = false;
+ public List sourceFileNames = new ArrayList<>();
+ public boolean advanceSchemaVersion = false;
+ public boolean deleteSchema = false;
+ public String configurationName;
+ public String templateToRun;
+ private static List templateSearchPaths = new ArrayList<>();
+
+ public CommandLine() {
+ addCommand(new CLHelp(this));
+ addCommand(new CLInit(this));
+ addCommand(new CLBuild(this));
+ addCommand(new CLSchema(this));
+ addCommand(new CLSetup(this));
+ addCommand(new CLFormat(this));
+ addCommand(new CLStatus(this));
+ addCommand(new CLInfo(this));
+ }
+
+ private void addCommand(CLCommand command) {
+ commands.put(command.getName(), command);
+ }
+
+ public static void AddToTemplateSearchPath(String path) {
+ templateSearchPaths.add(path);
+ }
+
+ public static final List GetTemplateSearchPaths() {
+ return templateSearchPaths;
+ }
+
+ public void run(String[] args) {
+ if (args.length == 0) {
+ printUsage();
+ exit(0);
+ }
+
+ reset(); // in case it is executed multiple times in a single java vm
+
+ String commandName = args[0];
+
+ if (commandName.equals("-h") || commandName.equals("-help") || commandName.equals("--help")) {
+ printUsage();
+ exit(0);
+ }
+
+ if (commandName.equals("-v") || commandName.equals("-version") || commandName.equals("--version")) {
+ System.out.println("ec compiler version " + COMPILER_VERSION + ", language version " + LANGUAGE_VERSION);
+ exit(0);
+ }
+
+ if (!commands.containsKey(commandName)) {
+ System.err.println("Unknown command: " + commandName);
+ printUsage();
+ exit(1);
+ }
+
+ CLCommand command = commands.get(commandName);
+ String cmdArgString = args.length == 1 ?
+ null :
+ args[1];
+
+ if (cmdArgString != null && (cmdArgString.equals("-h") || cmdArgString.equals("-help") || cmdArgString.equals(
+ "--help"))) {
+ command.printUsage();
+ exit(0);
+ }
+
+ String[] cmdArgsArray = new String[args.length - 1];
+ for (int i = 1; i < args.length; i++) {
+ cmdArgsArray[i - 1] = args[i];
+ }
+ command.run(cmdArgsArray);
+ }
+
+ public void printUsage() {
+ System.out.println("usage: ec [--version] [--help] [--verbose]");
+ System.out.println(" []");
+ System.out.println();
+ System.out.println("The following commands are available:");
+ int maxLen = 0;
+ for (String cmdName : commands.keySet()) {
+ if (cmdName.length() > maxLen) {
+ maxLen = cmdName.length();
+ }
+ }
+ for (String cmdName : commands.keySet()) {
+ CLCommand cmd = commands.get(cmdName);
+ System.out.println(
+ " " + cmd.getName() + ECStringUtil.RepeatString(" ", maxLen + 3 - cmd.getName().length())
+ + cmd.getSummary());
+ }
+ }
+
+ public final CLCommand getCommandByName(String name) {
+ return commands.get(name);
+ }
+
+ private static void reset() {
+ templateSearchPaths.clear();
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLBuild.java b/src/main/java/org/entityc/compiler/cmdline/command/CLBuild.java
new file mode 100644
index 0000000..9914129
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLBuild.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.entityc.compiler.EntityCompiler;
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.model.MTRoot;
+import org.entityc.compiler.model.config.MTConfiguration;
+import org.entityc.compiler.project.ProjectManager;
+import org.entityc.compiler.repository.RepositoryFile;
+import org.entityc.compiler.util.ECLog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CLBuild extends CLCommand {
+
+ public CLBuild(CommandLine commandLine) {
+ super(commandLine,
+ "build",
+ "Builds an Entity Compiler project.",
+ "Builds the Entity Compiler project using the specified configuration name.");
+ }
+
+ @Override
+ public void run(String[] args) {
+
+ // must have at least one argument
+ if (args.length == 0) {
+ printUsage();
+ return;
+ }
+
+ String configurationName = args[0];
+ List defines = new ArrayList<>();
+ boolean quietMode = false;
+
+ // Gather the source file names
+ ArrayList sourceFilenames = new ArrayList<>();
+ for (int i = 1; i < args.length; i++) {
+ String arg = args[i];
+ if (!arg.startsWith("-")) {
+ if (arg.contains("*")) {
+ sourceFilenames.addAll(super.processWildcardArg(arg));
+ } else {
+ sourceFilenames.add(arg);
+ }
+ } else if (arg.equals("-D")) {
+ defines.add(args[++i]);
+ } else if (arg.startsWith("-D")) {
+ defines.add(arg.substring(2));
+ } else if (arg.equals("-q") || arg.equals("--quiet")) {
+ quietMode = true;
+ } else if (arg.equals("-tp")) {
+ if (i == args.length-1) {
+ ECLog.logFatal("Missing template path.");
+ }
+ String paths = args[++i];
+ for (String path : paths.split(":")) {
+ commandLine.AddToTemplateSearchPath(path);
+ }
+
+ }
+ }
+
+ // set the global name/value pairs from command line
+ for (String defineStatement : defines) {
+ String[] nameValue = defineStatement.split("=");
+ if (nameValue.length != 2) {
+ ECLog.logFatal("-D option must be of the form =.");
+ }
+ EntityCompiler.SetDefineValue(nameValue[0], nameValue[1]);
+ }
+
+ // startup our project
+ ProjectManager.getInstance().start(quietMode);
+
+ // Convert them to repository imports
+ ArrayList repositoryFiles = new ArrayList<>();
+ for (String sourceFilename : sourceFilenames) {
+ repositoryFiles.add(new RepositoryFile(sourceFilename, false));
+ }
+
+ // create the root node and run the parser
+ MTRoot root = new MTRoot(null);
+ EntityCompiler.parseSourceFiles(root, null, repositoryFiles, false);
+
+ // Get the configuration that was requested and make sure it is there
+ MTConfiguration configuration = root.getConfiguration(configurationName);
+ if (configuration == null) {
+ ECLog.logFatal(
+ "Unable to find a configuration named \"" + configurationName + "\" in the specified files.");
+ }
+
+ // Run the compiler for our configuration
+ ProjectManager.getInstance().beginConfiguration(configurationName);
+ EntityCompiler.RunConfiguration(configuration);
+ ProjectManager.getInstance().endActiveConfiguration();
+
+ // If the configuration include a protoc block
+ EntityCompiler.RunProtoc(root, configuration);
+
+ // close out our session
+ ProjectManager.getInstance().close();
+ if (!quietMode) {
+ ECLog.log(colorize("Success", StdoutColor.GreenForeground));
+ }
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments(" [ ...] [-tp ][-q,--quiet][-D= ...]");
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLCommand.java b/src/main/java/org/entityc/compiler/cmdline/command/CLCommand.java
new file mode 100644
index 0000000..c405e83
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLCommand.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.apache.commons.io.filefilter.WildcardFileFilter;
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.util.ECLog;
+import org.entityc.compiler.util.ECStringUtil;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static java.lang.System.exit;
+
+public abstract class CLCommand {
+
+ protected final static int DISPLAY_LINE_WIDTH = 80;
+ protected final CommandLine commandLine;
+ private final String name;
+ private final String summary;
+ private final String description;
+
+ CLCommand(CommandLine commandLine, String name, String summary, String description) {
+ this.commandLine = commandLine;
+ this.name = name;
+ this.summary = summary;
+ this.description = description;
+ }
+
+ public static void displayItems(String message, Set listOfItems) {
+ displayItems(message, listOfItems, StdoutColor.Default);
+ }
+
+ public static void displayItems(String message, Set listOfItems, StdoutColor itemColor) {
+ ECLog.log("");
+ ECLog.log(ECStringUtil.WrapString(message + ":", "", DISPLAY_LINE_WIDTH));
+ Collection sortedNames = listOfItems.stream().sorted().collect(Collectors.toList());
+ for (String name : sortedNames) {
+ ECLog.log(" " + colorize(name, itemColor));
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ abstract public void printUsage();
+
+ abstract public void run(String[] args);
+
+ void printUsageWithArguments(String arguments) {
+ printCommandHelpHeader();
+ final String prefix = "usage: ec " + name;
+ final String spacing = " ";
+ final String indent = ECStringUtil.RepeatString(" ", prefix.length() + spacing.length());
+ String wrappedUsage = ECStringUtil.WrapString(arguments, indent, DISPLAY_LINE_WIDTH);
+ ECLog.log(prefix + spacing + wrappedUsage);
+ ECLog.log("");
+ }
+
+ void printCommandHelpHeader() {
+ ECLog.log("");
+ final String prefix = name;
+ final String spacing = " -- ";
+ final String indent = ECStringUtil.RepeatString(" ", prefix.length() + spacing.length());
+ String wrappedUsage = ECStringUtil.WrapString(description, indent, DISPLAY_LINE_WIDTH);
+ System.out.print(prefix + spacing);
+ System.out.println(wrappedUsage);
+ ECLog.log("");
+ }
+
+ protected List processWildcardArg(String arg) {
+ String[] args = arg.split("\\/");
+ if (args.length == 1) {
+ return processSingleDirWildcardArg(arg, ".");
+ } else {
+ int lastSegmentIndex = args.length - 1;
+ if (!args[lastSegmentIndex].contains("*")) {
+ System.err.println("ERROR: wildcards only supported in last path segment.");
+ exit(1);
+ }
+ String dirPath = args[0];
+ for (int i = 1; i < args.length - 1; i++) {
+ dirPath += File.separator + args[i];
+ }
+ return processSingleDirWildcardArg(args[lastSegmentIndex], dirPath);
+ }
+ }
+
+ protected List processSingleDirWildcardArg(String arg, String dirpath) {
+ ArrayList sourceFileNames = new ArrayList<>();
+ File dir = new File(dirpath);
+ FileFilter fileFilter = new WildcardFileFilter(arg);
+ File[] files = dir.listFiles(fileFilter);
+ for (File file : files) {
+ sourceFileNames.add(dirpath + File.separator + file.getName());
+ }
+ return sourceFileNames;
+ }
+
+ protected static String colorize(String text, StdoutColor color) {
+ return color.getStringValue() + text + StdoutColor.Default.getStringValue();
+ }
+
+ public enum StdoutColor {
+ Default(0),
+ Brighter(1),
+ Underlined(4),
+ Flashing(5),
+ BlackForeground(30),
+ RedForeground(31),
+ GreenForeground(32),
+ YellowForeground(33),
+ BlueForeground(34),
+ PurpleForeground(35),
+ CyanForeground(36),
+ WhiteForeground(37),
+ BlackBackground(40),
+ RedBackground(41),
+ GreenBackground(42),
+ YellowBackground(43),
+ BlueBackground(44),
+ PurpleBackground(45),
+ CyanBackground(46),
+ WhiteBackground(47),
+ ;
+
+ final int ansiCode;
+ final String stringValue;
+
+ StdoutColor(int ansiCode) {
+ this.ansiCode = ansiCode;
+ this.stringValue = "\033[1;" + ansiCode + "m";
+ }
+
+ public int getAnsiCode() {
+ return ansiCode;
+ }
+
+ public String getStringValue() {
+ return stringValue;
+ }
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLFormat.java b/src/main/java/org/entityc/compiler/cmdline/command/CLFormat.java
new file mode 100644
index 0000000..e060f3b
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLFormat.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.model.MTCodeFormat;
+import org.entityc.compiler.model.MTRoot;
+import org.entityc.compiler.model.config.MTConfiguration;
+import org.entityc.compiler.model.config.MTFile;
+import org.entityc.compiler.model.config.MTSpace;
+import org.entityc.compiler.model.config.MTTemplate;
+import org.entityc.compiler.transform.TransformManager;
+import org.entityc.compiler.transform.template.FileTemplateTransform;
+import org.entityc.compiler.transform.template.tree.FTTemplate;
+import org.entityc.compiler.transform.template.tree.FTTransformSession;
+import org.entityc.compiler.util.ECLog;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CLFormat extends CLCommand {
+
+ public CLFormat(CommandLine commandLine) {
+ super(commandLine,
+ "format",
+ "Formats template source files.",
+ "Formats template source files given formatting preferences.");
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments("[-o ] [ ...]");
+ }
+
+ @Override
+ public void run(String[] args) {
+
+ // process arguments
+ List filenames = new ArrayList<>();
+ String outputDirectory = null;
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equals("-o")) {
+ if (i == args.length) {
+ ECLog.logFatal("Missing output directory.");
+ }
+ outputDirectory = args[++i];
+ } else {
+ if (arg.contains("*")) {
+ filenames.addAll(processWildcardArg(arg));
+ } else {
+ filenames.add(arg);
+ }
+ }
+ }
+
+ // setup root node, space and configuration
+ MTRoot root = new MTRoot(null);
+ MTSpace space = new MTSpace(null, "formatterSpace");
+ root.setSpace(space);
+ MTConfiguration config = new MTConfiguration(null, root, "formatter");
+ root.addConfiguration(config);
+
+ // process each file specified
+ MTFile file = null;
+ for (String filename : filenames) {
+ File f = new File(filename);
+ if (f.exists()) {
+ file = new MTFile(null, f);
+ } else {
+ ECLog.logFatal("The specified template file to format does not exist: "
+ + filename);
+ }
+
+ // setup, parse and load template into memory
+ MTTemplate mtTemplate = new MTTemplate(null, config, file);
+ TransformManager.AddTransform(new FileTemplateTransform(config, mtTemplate, file.getPath()));
+ FTTemplate ftTemplate = mtTemplate.parse((FTTransformSession) null, true);
+ File outFile = null;
+ if (outputDirectory != null) {
+ outFile = new File(outputDirectory + File.separator + file.getPath());
+ } else {
+ outFile = new File(file.getPath());
+ }
+
+ // Use the default code format and perform the formatting
+ MTCodeFormat codeFormat = root.getCodeFormat("Default");
+ ftTemplate.formatCodeToFile(outFile, codeFormat);
+ }
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLHelp.java b/src/main/java/org/entityc/compiler/cmdline/command/CLHelp.java
new file mode 100644
index 0000000..236458d
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLHelp.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.util.ECLog;
+
+public class CLHelp extends CLCommand {
+
+ public CLHelp(CommandLine commandLine) {
+ super(commandLine,
+ "help",
+ "Provides help on usage for this app.",
+ "Provides usage help on a specific command or on the entire app.");
+ }
+
+ @Override
+ public void run(String[] args) {
+ if (args.length == 0) {
+ printUsage();
+ return;
+ }
+
+ String commandName = args[0];
+ CLCommand command = commandLine.getCommandByName(commandName);
+ if (command == null) {
+ ECLog.logError("Unknown command line command: " + commandName);
+ commandLine.printUsage();
+ System.exit(1);
+ }
+
+ command.printUsage();
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments("[]");
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLInfo.java b/src/main/java/org/entityc/compiler/cmdline/command/CLInfo.java
new file mode 100644
index 0000000..9a7665c
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLInfo.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.project.GeneratedFile;
+import org.entityc.compiler.project.ProjectManager;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class CLInfo extends CLCommand {
+
+ public CLInfo(CommandLine commandLine) {
+ super(commandLine,
+ "info",
+ "Displays some info about this Entity Compiler project.",
+ "Displays various types of info about this Entity Compiler project.");
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments("[-s,--sources] [-c,--configs] [-t,--templates] [-g,--generated] [-a,--all]");
+ }
+
+ @Override
+ public void run(String[] args) {
+
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.start(false);
+
+ boolean showSources = false;
+ boolean showConfigs = false;
+ boolean showTemplates = false;
+ boolean showGeneratedFiles = false;
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equals("-c") || arg.equals("--configs")) {
+ showConfigs = true;
+ } else if (arg.equals("-s") || arg.equals("--sources")) {
+ showSources = true;
+ } else if (arg.equals("-t") || arg.equals("--templates")) {
+ showTemplates = true;
+ } else if (arg.equals("-g") || arg.equals("--generated")) {
+ showGeneratedFiles = true;
+ } else if (arg.equals("-a") || arg.equals("--all")) {
+ showConfigs = true;
+ showSources = true;
+ showTemplates = true;
+ showGeneratedFiles = true;
+ }
+ }
+
+ if (!showConfigs && !showTemplates && !showGeneratedFiles) {
+ showSources = true;
+ }
+
+ projectManager.loadProjectFiles();
+
+ if (showSources) {
+ displayItems("Source Files", projectManager.getSourceFiles());
+ }
+
+ if (showGeneratedFiles) {
+ final List files = projectManager.getGeneratedFiles();
+ Set filenames = new HashSet<>();
+ for (GeneratedFile file : files) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ProjectManager.getInstance().getRelativePath(new File(file.getFilepath())));
+ Set configurationNames = file.getConfigurationNames();
+ if (configurationNames.size() > 1) {
+ sb.append(" (" + configurationNames.size() + " configurations)");
+ }
+ filenames.add(sb.toString());
+ }
+ displayItems("Generated Files", filenames, StdoutColor.GreenForeground);
+ }
+
+ if (showConfigs) {
+ displayItems("Configurations", projectManager.getConfigurationNames(), StdoutColor.CyanForeground);
+ }
+
+ if (showTemplates) {
+ displayItems("Templates", projectManager.getTemplateUris(), StdoutColor.BlueForeground);
+ }
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLInit.java b/src/main/java/org/entityc/compiler/cmdline/command/CLInit.java
new file mode 100644
index 0000000..4b3560b
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLInit.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.project.ProjectManager;
+import org.entityc.compiler.util.ECLog;
+
+import java.io.File;
+import java.io.IOException;
+
+public class CLInit extends CLCommand {
+
+ public CLInit(CommandLine commandLine) {
+ super(commandLine,
+ "init",
+ "Initializes a directory as an Entity Compiler project.",
+ "Initializes the current working directory to be an Entity Compiler project directory. "
+ + "This will allow the Entity Compiler to keep track of build sessions for this project and keep other "
+ + "project information specific to the Entity Compiler in one place.");
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments("[-f,--force]");
+ }
+
+ @Override
+ public void run(String[] args) {
+
+ boolean force = args.length > 0 && (args[0].equals("-f") || args[0].equals("--force"));
+ String invocationDirectory = null;
+ try {
+ invocationDirectory = new File(".").getCanonicalPath();
+ String projectBaseDirPath = ProjectManager.getInstance().findECDirectory(invocationDirectory);
+ if (projectBaseDirPath != null && projectBaseDirPath.equals(invocationDirectory)) {
+ ECLog.log("Project directory already established here.");
+ } else if (projectBaseDirPath == null || (force && !projectBaseDirPath.equals(invocationDirectory))) {
+ if (force) {
+ ProjectManager.getInstance().setProjectBaseDirPath(invocationDirectory);
+ }
+ ProjectManager.getInstance().start(false);
+ ProjectManager.getInstance().close();
+ ECLog.log("This directory (" + invocationDirectory + ") is now an Entity Compiler project directory.");
+ } else {
+ ECLog.logError("There is already a project directory above this directory: " + projectBaseDirPath);
+ ECLog.log("If you still want to initialize this directory (" + invocationDirectory
+ + ") as a project directory use the -f option.");
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLSchema.java b/src/main/java/org/entityc/compiler/cmdline/command/CLSchema.java
new file mode 100644
index 0000000..7198ce3
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLSchema.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.project.ProjectManager;
+import org.entityc.compiler.structure.sql.SSSchemaVersioning;
+import org.entityc.compiler.util.ECLog;
+
+import java.util.Scanner;
+import java.util.Set;
+
+import static org.entityc.compiler.structure.sql.SSSchemaVersioning.LoadSchemaVersion;
+
+public class CLSchema extends CLCommand {
+
+ public CLSchema(CommandLine commandLine) {
+ super(commandLine, "schema", "Used to manage the database schema of the project.", "");
+ }
+
+ @Override
+ public void run(String[] args) {
+
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.start(false);
+
+ Set directories = projectManager.getSchemaDirectories();
+ if (directories.size() == 0) {
+ ECLog.log("No schema directories found. You may need to run a build so that it will be created.");
+ }
+
+ if (directories.size() > 1) {
+ ECLog.logWarning("Multiple schemas are currently not supported. Only the first one found will be used.");
+ }
+
+ SSSchemaVersioning.setBasePath(directories.stream().findFirst().get());
+
+ if (args.length > 0) {
+ String subCommand = args[0];
+ if (subCommand.equals("advance")) {
+ if (args.length > 2) {
+ ECLog.logFatal(getName() + " " + subCommand + " has too many arguments");
+ }
+ if (args.length == 1) {
+ SSSchemaVersioning.SaveAdvanceRequest(true);
+ } else {
+ String subCommandArg = args[1];
+ if (subCommandArg.equals("cancel")) {
+ SSSchemaVersioning.SaveAdvanceRequest(false);
+ } else {
+ ECLog.logFatal("The " + getName() + " " + subCommand + " command does not accept option: "
+ + subCommandArg);
+ }
+ }
+ } else if (subCommand.equals("delete")) {
+ boolean doTheDelete = false;
+ if (args.length > 1) {
+ String deleteOption = args[1];
+ if (deleteOption.equals("-f") || deleteOption.equals("--force")) {
+ doTheDelete = true;
+ } else {
+ ECLog.logFatal("Unknown option for delete: " + deleteOption);
+ }
+ }
+ if (!doTheDelete) {
+ System.out.print(
+ "Are you sure you want to delete your schema? To confirm enter the word 'delete': ");
+ Scanner scanner = new Scanner(System.in);
+ String value = scanner.nextLine();
+ if (value.equals("delete")) {
+ doTheDelete = true;
+ }
+ }
+ if (doTheDelete) {
+ SSSchemaVersioning.DeleteEntireSchema();
+ ECLog.log(
+ "Entire schema has been " + CLCommand.StdoutColor.RedForeground.getStringValue() + "DELETED"
+ + StdoutColor.Default.getStringValue());
+ } else {
+ ECLog.log("Delete aborted.");
+ return;
+ }
+ } else {
+ ECLog.logFatal("Command " + getName() + " does not support sub-command: " + subCommand);
+ }
+ }
+ for (String schemaDirectory : directories) {
+ SSSchemaVersioning.setBasePath(schemaDirectory);
+ int readVersion = LoadSchemaVersion(SSSchemaVersioning.SchemaPointer.Read);
+ ECLog.log("");
+ ECLog.log("Schema Directory: " + schemaDirectory);
+ ECLog.log(" Previous version: " + ((readVersion > 1) ?
+ readVersion :
+ "(none)"));
+ ECLog.log(" Current version: " + LoadSchemaVersion(SSSchemaVersioning.SchemaPointer.Write));
+ ECLog.log(" Version advance directive: " + (SSSchemaVersioning.LoadAdvanceRequest() ?
+ colorize("advance if schema changes",
+ StdoutColor.GreenForeground) :
+ colorize("don't advance", StdoutColor.RedForeground)));
+ }
+ ECLog.log("");
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments("[advance [cancel]] | [delete [-f,--force]]");
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLSetup.java b/src/main/java/org/entityc/compiler/cmdline/command/CLSetup.java
new file mode 100644
index 0000000..b5af7a8
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLSetup.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.stream.JsonReader;
+import org.entityc.compiler.EntityCompiler;
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.model.MTRoot;
+import org.entityc.compiler.model.config.MTConfiguration;
+import org.entityc.compiler.model.config.MTDirectory;
+import org.entityc.compiler.model.config.MTRepository;
+import org.entityc.compiler.model.config.MTRepositoryImport;
+import org.entityc.compiler.model.config.MTSpace;
+import org.entityc.compiler.project.ProjectManager;
+import org.entityc.compiler.repository.RepositoryCache;
+import org.entityc.compiler.repository.RepositoryFile;
+import org.entityc.compiler.repository.RepositoryImportManager;
+import org.entityc.compiler.util.ECLog;
+import org.entityc.compiler.util.ECStringUtil;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Scanner;
+
+public class CLSetup extends CLCommand {
+
+ private final HashMap setupMap = new HashMap<>();
+ private MTRoot root = null;
+ private MTSpace space = null;
+ private MTRepository setupRepository = null;
+
+ public CLSetup(CommandLine commandLine) {
+ super(commandLine,
+ "setup",
+ "Runs a setup file to install a new project to a directory.",
+ "Allows you to very quickly setup a project based on a pre-defined project template. "
+ + "You specify the project template using a URI that can fetch all necessary files over the network.");
+ }
+
+ @Override
+ public void run(String[] args) {
+
+ if (args.length == 0) {
+ printUsage();
+ return;
+ }
+
+ String setupNameOrUri = args[0];
+
+ loadSetups();
+
+ if (setupNameOrUri.equals("-l") || setupNameOrUri.equals("--list")) {
+ listAvailableSetups();
+ return;
+ }
+ String setupUri = setupNameOrUri;
+ if (setupMap.containsKey(setupNameOrUri)) {
+ SetupInfo setupInfo = setupMap.get(setupNameOrUri);
+ setupUri = setupInfo.uri;
+ }
+
+ // site : organization / repo-name / path-to-setup-edl
+ ECLog.logInfo("Fetching setup: " + setupUri);
+ RepositoryFile repositoryFile = getFileFromRepositoryUri(setupUri, "edl", false);
+
+ String directoryName = repositoryFile.getRepository().getSetupFilename();
+ if (args.length < 2) {
+ System.out.print("Enter project directory name [" + directoryName + "]: ");
+ Scanner scanner = new Scanner(System.in);
+ String value = scanner.nextLine();
+ if (value.trim().length() != 0) {
+ directoryName = value;
+ }
+ } else {
+ directoryName = args[1];
+ }
+ EntityCompiler.ensureDirectory(directoryName);
+
+ ProjectManager.getInstance().setProjectBaseDirPath(directoryName);
+ ProjectManager.getInstance().start(false);
+
+ configureSetupRepo(setupUri);
+
+ String configurationName = "Setup";
+
+ ArrayList sourceFilenames = new ArrayList<>();
+ sourceFilenames.add(repositoryFile.getFilepath());
+ // more to put here
+ ArrayList repositoryFiles = new ArrayList<>();
+ for (String sourceFilename : sourceFilenames) {
+ repositoryFiles.add(new RepositoryFile(sourceFilename, false));
+ }
+ EntityCompiler.parseSourceFiles(root, null, repositoryFiles, true);
+
+ MTConfiguration configuration = root.getConfiguration(configurationName);
+
+ if (configuration == null) {
+ ECLog.logFatal("Unable to find a configuration named \"" + configurationName + "\" in the setup file.");
+ }
+
+ // Update output directories to include our project directory
+ MTDirectory setupTargetDirectory = configuration.getOutputByName("SetupTargetDir");
+ if (setupTargetDirectory == null) {
+ ECLog.logFatal("Setup file is missing an output defined by the name of \"SetupTargetDir\".");
+ }
+ setupTargetDirectory.setPath(directoryName + "/" + setupTargetDirectory.getPath());
+
+ MTDirectory projectTopDirectory = configuration.getOutputByName("ProjectTopDir");
+ if (projectTopDirectory != null) {
+ projectTopDirectory.setPath(directoryName + "/" + projectTopDirectory.getPath());
+ }
+
+ // Run the compiler for our configuration
+ EntityCompiler.RunConfiguration(configuration);
+
+ // close out our session
+ ProjectManager.getInstance().close();
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments("[-l,--list] []");
+ }
+
+ private void loadSetups() {
+ String uri = "github:entityc/entity-compiler:main/setups";
+ RepositoryFile setupListFile = getFileFromRepositoryUri(uri, "json", true);
+ if (setupListFile == null) {
+ ECLog.logFatal("Unable to find the list of available setups from: " + uri);
+ }
+ String filepath = setupListFile.getFilepath();
+ JsonObject setupList = null;
+ Gson gson = new Gson();
+ try {
+ FileInputStream fis = new FileInputStream(filepath);
+ JsonReader reader = new JsonReader(new InputStreamReader(fis, StandardCharsets.UTF_8));
+ setupList = gson.fromJson(reader, JsonObject.class);
+ reader.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ for (String setupName : setupList.keySet()) {
+ JsonObject setup = setupList.getAsJsonObject(setupName);
+ if (!addSetupInfo(setupName, setup)) {
+ continue;
+ }
+ }
+ }
+
+ private void listAvailableSetups() {
+ ECLog.log("The following project templates are available: ");
+ ECLog.log("");
+ if (setupMap.size() == 0) {
+ ECLog.log("no setups available");
+ } else {
+ for (String setupName : setupMap.keySet()) {
+ SetupInfo setup = setupMap.get(setupName);
+ ECLog.log(" " + setup.identifier);
+ String indent = " ";
+ ECLog.log(indent + setup.title);
+ ECLog.log("");
+ String wrappedDescription = ECStringUtil.WrapString(setup.description, indent, DISPLAY_LINE_WIDTH);
+ ECLog.log(indent + wrappedDescription);
+ ECLog.log("");
+ ECLog.log(indent + setup.uri);
+ ECLog.log("");
+ }
+ }
+ }
+
+ private RepositoryFile getFileFromRepositoryUri(String uri, String extension, boolean quietly) {
+ MTRepository repository = new MTRepository(uri);
+ repository.setName("SetupRepo");
+ MTRepositoryImport repositoryImport = new MTRepositoryImport(null, false);
+ repositoryImport.setQuietly(quietly);
+ MTSpace space = new MTSpace(null, "Setup");
+ MTRoot root = new MTRoot(null);
+ root.setSpace(space);
+ space.addRepository(repository);
+ repositoryImport.setRepositoryName(repository.getName());
+ repositoryImport.setFilename(repository.getSetupFilename());
+ RepositoryImportManager importManager = new RepositoryImportManager(
+ RepositoryCache.CacheStructure.TempDirectory);
+ RepositoryFile repositoryFile = importManager.importFromRepository(space,
+ repositoryImport, extension, false);
+ return repositoryFile;
+ }
+
+ private void configureSetupRepo(String uri) {
+ this.setupRepository = new MTRepository(uri);
+ this.setupRepository.setName("SetupRepo");
+ MTRepositoryImport repositoryImport = new MTRepositoryImport(null, false);
+ repositoryImport.setQuietly(true);
+ this.space = new MTSpace(null, "Setup");
+ this.root = new MTRoot(null);
+ root.setSpace(space);
+ space.addRepository(this.setupRepository);
+ }
+
+ private boolean addSetupInfo(String identifier, JsonObject jsonObject) {
+ String title = jsonObject.get("title").getAsString();
+ String description = jsonObject.get("description").getAsString();
+ String setupUri = jsonObject.get("uri").getAsString();
+ if (title == null || description == null || setupUri == null) {
+ return false;
+ }
+ SetupInfo setupInfo = new SetupInfo(identifier, title, description, setupUri);
+ setupMap.put(setupInfo.identifier, setupInfo);
+ return true;
+ }
+
+ private class SetupInfo {
+
+ String identifier;
+ String title;
+ String description;
+ String uri;
+
+ SetupInfo(String identifier, String title, String description, String uri) {
+ this.identifier = identifier;
+ this.title = title;
+ this.description = description;
+ this.uri = uri;
+ }
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/cmdline/command/CLStatus.java b/src/main/java/org/entityc/compiler/cmdline/command/CLStatus.java
new file mode 100644
index 0000000..03b3bf3
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/cmdline/command/CLStatus.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.cmdline.command;
+
+import org.entityc.compiler.cmdline.CommandLine;
+import org.entityc.compiler.project.ProjectManager;
+import org.entityc.compiler.util.ECLog;
+
+public class CLStatus extends CLCommand {
+
+ public CLStatus(CommandLine commandLine) {
+ super(commandLine,
+ "status",
+ "Displays the status of an Entity Compiler project.",
+ "Displays the status of this Entity Compiler project (if exists).");
+ }
+
+ @Override
+ public void printUsage() {
+ super.printUsageWithArguments("");
+ }
+
+ @Override
+ public void run(String[] args) {
+
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.start(false);
+ ECLog.log("Project directory: " + ProjectManager.getInstance().getProjectBaseDirPath());
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/model/config/MTRepository.java b/src/main/java/org/entityc/compiler/model/config/MTRepository.java
index 241a60a..fe01f72 100644
--- a/src/main/java/org/entityc/compiler/model/config/MTRepository.java
+++ b/src/main/java/org/entityc/compiler/model/config/MTRepository.java
@@ -30,6 +30,7 @@ public class MTRepository extends MTNode {
private String repoName;
private boolean indexedTemplates = false;
private String setupFilename;
+ private String commitSHA1;
public MTRepository(ParserRuleContext ctx, String name) {
super(ctx);
@@ -48,7 +49,7 @@ public MTRepository(String setupUri) {
type = MTRepositoryType.GITHUB;
Integer firstPathDelimIndex = setupUri.indexOf("/");
if (firstPathDelimIndex == -1) {
- ECLog.logFatal("Invalid setup URI - nothing after organization name");
+ ECLog.logFatal("Invalid setup URI - nothing after organization name.");
}
organization = setupUri.substring(colonIndex + 1, firstPathDelimIndex);
Integer tagDelimIndex = setupUri.indexOf(":", colonIndex + 1);
@@ -57,20 +58,21 @@ public MTRepository(String setupUri) {
}
Integer secondPathDelimIndex = setupUri.indexOf("/", firstPathDelimIndex + 1);
boolean hasNoPath = secondPathDelimIndex == -1;
+ if (hasNoPath) {
+ ECLog.logFatal("Invalid setup URI - it requires a path to a setup file.");
+ }
tag = setupUri.substring(tagDelimIndex + 1, hasNoPath ?
setupUri.length() :
secondPathDelimIndex);
repoName = setupUri.substring(firstPathDelimIndex + 1, tagDelimIndex);
- path = "";
- if (!hasNoPath) {
- path = setupUri.substring(secondPathDelimIndex + 1);
- Integer lastPathDelimIndex = path.lastIndexOf("/");
- if (lastPathDelimIndex == -1) {
- setupFilename = "Setup";
- } else {
- setupFilename = path.substring(lastPathDelimIndex + 1);
- path = path.substring(0, lastPathDelimIndex);
- }
+ path = setupUri.substring(secondPathDelimIndex + 1);
+ Integer lastPathDelimIndex = path.lastIndexOf("/");
+ if (lastPathDelimIndex == -1) {
+ setupFilename = path;
+ path = "";
+ } else {
+ setupFilename = path.substring(lastPathDelimIndex + 1);
+ path = path.substring(0, lastPathDelimIndex);
}
}
@@ -188,9 +190,6 @@ public void indexTemplateFilesInGithubDirectory(GHRepository repo, List 0) {
+ builder.append("/");
+ builder.append(path);
+ }
return builder.toString();
}
+
+ public String getCommitSHA1() {
+ return commitSHA1;
+ }
+
+ public void setCommitSHA1(String commitSHA1) {
+ this.commitSHA1 = commitSHA1;
+ }
}
diff --git a/src/main/java/org/entityc/compiler/model/config/MTRepositoryImport.java b/src/main/java/org/entityc/compiler/model/config/MTRepositoryImport.java
index 00cb565..1079362 100644
--- a/src/main/java/org/entityc/compiler/model/config/MTRepositoryImport.java
+++ b/src/main/java/org/entityc/compiler/model/config/MTRepositoryImport.java
@@ -15,12 +15,15 @@
import org.entityc.compiler.model.visitor.MTVisitor;
@ModelClass(type = ModelClassType.CONFIGURATION,
- description = "Contains configuration for importing files from a repository.")
+ description = "Contains configuration for importing files from a repository.")
public class MTRepositoryImport extends MTNode {
private String filename;
private String repositoryName;
private boolean includeOnly;
+ private boolean quietly;
+
+ private String directoryPath;
public MTRepositoryImport(ParserRuleContext ctx, boolean includeOnly) {
super(ctx);
@@ -28,11 +31,11 @@ public MTRepositoryImport(ParserRuleContext ctx, boolean includeOnly) {
}
@ModelMethod(category = ModelMethodCategory.CONFIGURATION,
- description =
- "Indicates whether this import should only use the file as like a header file or where everything in "
- + "the imported source file is essentially declared as extern. This would be used in the case of "
- + "entities where you don't intend to implement them in code directly but need to "
- + "know how they are defined so code knows how to interface with them in some way.")
+ description =
+ "Indicates whether this import should only use the file as like a header file or where everything in "
+ + "the imported source file is essentially declared as extern. This would be used in the case of "
+ + "entities where you don't intend to implement them in code directly but need to "
+ + "know how they are defined so code knows how to interface with them in some way.")
public boolean isIncludeOnly() {
return includeOnly;
}
@@ -50,15 +53,23 @@ public void setFilename(String filename) {
this.filename = filename;
}
+ public String getDirectoryPath() {
+ return directoryPath;
+ }
+
+ public void setDirectoryPath(String directoryPath) {
+ this.directoryPath = directoryPath;
+ }
+
@ModelMethod(category = ModelMethodCategory.CONFIGURATION,
- description = "Returns an identifer which is basically the *repository name*`.`*filename*.")
+ description = "Returns an identifer which is basically the *repository name*`.`*filename*.")
public String getIdentifier() {
return repositoryName + "." + filename;
}
@ModelMethod(category = ModelMethodCategory.CONFIGURATION,
- description = "Returns the declared name of the repository object that this import operation will use as "
- + "its source repository.")
+ description = "Returns the declared name of the repository object that this import operation will use as "
+ + "its source repository.")
public String getRepositoryName() {
return repositoryName;
}
@@ -67,6 +78,14 @@ public void setRepositoryName(String repositoryName) {
this.repositoryName = repositoryName;
}
+ public boolean isQuietly() {
+ return quietly;
+ }
+
+ public void setQuietly(boolean quietly) {
+ this.quietly = quietly;
+ }
+
@Override
public void accept(MTVisitor visitor) {
diff --git a/src/main/java/org/entityc/compiler/model/config/MTTemplate.java b/src/main/java/org/entityc/compiler/model/config/MTTemplate.java
index 63433f2..b4e1679 100644
--- a/src/main/java/org/entityc/compiler/model/config/MTTemplate.java
+++ b/src/main/java/org/entityc/compiler/model/config/MTTemplate.java
@@ -23,7 +23,7 @@ public class MTTemplate extends MTTransform {
private boolean contextual;
private MTRepositoryImport repositoryImport;
- private String directoryName;
+ private String directoryPath;
private MTFile file;
public MTTemplate(ParserRuleContext ctx, MTConfiguration configuration, String name) {
@@ -40,24 +40,24 @@ public MTFile getFile() {
}
@ModelMethod(category = ModelMethodCategory.CONFIGURATION,
- description = "Returns the filename of the template which is preceded by a directory name if available.")
+ description = "Returns the filename of the template which is preceded by a directory name if available.")
public String getFilename() {
String filename = "";
- if (this.getDirectoryName() != null) {
- filename = this.getDirectoryName() + "/";
+ if (this.getDirectoryPath() != null) {
+ filename = this.getDirectoryPath() + "/";
}
filename += this.getName();
return filename;
}
@ModelMethod(category = ModelMethodCategory.CONFIGURATION,
- description = "Returns the directory name if available. Otherwise returns `null`")
- public String getDirectoryName() {
- return directoryName;
+ description = "Returns the directory path if available. Otherwise returns `null`")
+ public String getDirectoryPath() {
+ return directoryPath;
}
- public void setDirectoryName(String directoryName) {
- this.directoryName = directoryName;
+ public void setDirectoryPath(String directoryPath) {
+ this.directoryPath = directoryPath;
}
public boolean isNotDeclared() {
@@ -65,7 +65,7 @@ public boolean isNotDeclared() {
}
@ModelMethod(category = ModelMethodCategory.CONFIGURATION,
- description = "Returns an object that defines how the template will be imported.")
+ description = "Returns an object that defines how the template will be imported.")
public MTRepositoryImport getRepositoryImport() {
return repositoryImport;
}
@@ -82,16 +82,19 @@ public boolean isContextual() {
@Deprecated
public void setContextual(boolean contextual) {
this.contextual = contextual;
+ if (contextual) {
+ ECLog.logWarning("Contextual templates have been deprecated.");
+ }
}
@ModelMethod(category = ModelMethodCategory.CONFIGURATION,
- description = "Returns the output directory considered to be the primary output for the template.")
+ description = "Returns the output directory considered to be the primary output for the template.")
public MTDirectory getPrimaryOutputDirectory() {
- String directoryName = getOutputNameByLocalName("primary");
- if (directoryName == null) {
+ String outputName = getOutputNameByLocalName("primary");
+ if (outputName == null) {
return null;
}
- return this.configuration.getOutputByName(directoryName);
+ return this.configuration.getOutputByName(outputName);
}
public FTTemplate parse(FTTransformSession session, boolean suppressImport) {
diff --git a/src/main/java/org/entityc/compiler/project/GeneratedFile.java b/src/main/java/org/entityc/compiler/project/GeneratedFile.java
new file mode 100644
index 0000000..c1b3895
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/project/GeneratedFile.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.project;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class GeneratedFile {
+
+ final private String filepath;
+ final private List origins = new ArrayList<>();
+
+ public GeneratedFile(String filepath, String configurationName, String templateUri) {
+ this.filepath = filepath;
+ this.origins.add(new GenerationOrigin(configurationName, templateUri));
+ }
+
+ public GeneratedFile(String filepath) {
+ this.filepath = filepath;
+ }
+
+ public String getFilepath() {
+ return filepath;
+ }
+
+ public boolean hasTemplateOrigin(String templateUri) {
+ for (GenerationOrigin origin : origins) {
+ if (origin.matchesTemplateWithoutTag(templateUri)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasConfigurationOrigin(String configurationName) {
+ for (GenerationOrigin origin : origins) {
+ if (origin.getConfigurationName().equals(configurationName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasSingleConfigurationOrigin(String configurationName) {
+ if (origins.size() > 1) {
+ return false;
+ }
+ for (GenerationOrigin origin : origins) {
+ if (origin.getConfigurationName().equals(configurationName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Set getConfigurationNames() {
+ HashSet configurationNames = new HashSet<>();
+ for (GenerationOrigin origin : origins) {
+ configurationNames.add(origin.getConfigurationName());
+ }
+ return configurationNames;
+ }
+
+ public Set getTemplateUris() {
+ HashSet templateUris = new HashSet<>();
+ for (GenerationOrigin origin : origins) {
+ templateUris.add(origin.getTemplateUri());
+ }
+ return templateUris;
+ }
+
+ public GeneratedFile extractForConfiguration(String configurationName, boolean remove) {
+ GeneratedFile singleConfigurationGeneratedFile = new GeneratedFile(this.filepath);
+ for (GenerationOrigin origin : origins) {
+ if (origin.getConfigurationName().equals(configurationName)) {
+ singleConfigurationGeneratedFile.origins.add(origin);
+ }
+ }
+ if (remove) {
+ origins.removeAll(singleConfigurationGeneratedFile.origins);
+ }
+ return singleConfigurationGeneratedFile;
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/project/GenerationOrigin.java b/src/main/java/org/entityc/compiler/project/GenerationOrigin.java
new file mode 100644
index 0000000..6633db6
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/project/GenerationOrigin.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+package org.entityc.compiler.project;
+
+public class GenerationOrigin {
+
+ private String configurationName;
+ private String templateUri;
+
+ public GenerationOrigin(String configurationName, String templateUri) {
+ this.configurationName = configurationName;
+ this.templateUri = templateUri;
+ }
+
+ public String getConfigurationName() {
+ return configurationName;
+ }
+
+ public String getTemplateUri() {
+ return templateUri;
+ }
+
+ public boolean matchesTemplateWithoutTag(String otherTemplateUri) {
+ return stripVersion(templateUri).equals(stripVersion(otherTemplateUri));
+ }
+
+ public String stripVersion(String uri) {
+ int lastColon = uri.lastIndexOf(':');
+ return uri.substring(0, lastColon) + uri.substring(
+ uri.indexOf('/', lastColon) + 1);
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/project/ProjectManager.java b/src/main/java/org/entityc/compiler/project/ProjectManager.java
new file mode 100644
index 0000000..858945d
--- /dev/null
+++ b/src/main/java/org/entityc/compiler/project/ProjectManager.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+/*
+ * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.md file in the project root.
+ */
+
+package org.entityc.compiler.project;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import org.apache.commons.io.FileUtils;
+import org.entityc.compiler.cmdline.command.CLCommand;
+import org.entityc.compiler.util.ECLog;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class ProjectManager {
+
+ private static final String ECDirectoryName = ".ec";
+ private static final String GeneratedFilename = "generated.json";
+ private static final String SchemaFilename = "schema.json";
+ private static final ProjectManager instance = new ProjectManager();
+ private final String[] cwdParts;
+ private List generatedFiles = new ArrayList<>();
+ private Set configurationNames;
+ private Set templateUris;
+ private File projectDirectory; // the directory with the .ec directory in it
+ private File ecDirectory;
+ private List activeConfigurationPreviouslyGeneratedFiles;
+ private String activeConfigurationName;
+ private Set schemaDirectories = new HashSet<>();
+
+ private boolean quietMode = false;
+
+ private ProjectManager() {
+ String cwdPath = (new File(".")).getAbsolutePath();
+ cwdParts = cwdPath.split(File.separator);
+ }
+
+ public void start(boolean quietMode) {
+ this.quietMode = quietMode;
+ if (projectDirectory == null) {
+ try {
+ String invocationDirectory = new File(".").getCanonicalPath();
+ String projectDirectoryPath = findECDirectory(invocationDirectory);
+ if (projectDirectoryPath == null) {
+ projectDirectoryPath = invocationDirectory;
+ }
+ projectDirectory = new File(projectDirectoryPath);
+ } catch (IOException e) {
+ ECLog.logFatal("Unable to locate current working directory");
+ }
+ }
+
+ ecDirectory = new File(projectDirectory.getAbsolutePath() + File.separator + ECDirectoryName);
+ ecDirectory.mkdirs();
+ loadProjectFiles();
+ }
+
+ public void loadProjectFiles() {
+ validate();
+ this.generatedFiles = loadFile(GeneratedFilename, new TypeToken>() {
+ }.getType(), new ArrayList<>());
+ this.schemaDirectories = loadFile(SchemaFilename, new TypeToken>() {
+ }.getType(), new HashSet<>());
+ }
+
+ private T loadFile(String filename, java.lang.reflect.Type type, T defaultValue) {
+ T object = defaultValue;
+ final String errorMessage = "Unable to load project file: " + filename;
+ File projectFile = new File(ecDirectory.getPath() + File.separator + filename);
+ if (projectFile.exists()) {
+ Gson gson = new Gson();
+ try {
+ FileInputStream fis = new FileInputStream(projectFile);
+ JsonReader reader = new JsonReader(new InputStreamReader(fis, StandardCharsets.UTF_8));
+ object = gson.fromJson(reader, type);
+ reader.close();
+ } catch (FileNotFoundException e) {
+ ECLog.logFatal(errorMessage);
+ } catch (IOException e) {
+ ECLog.logFatal(errorMessage);
+ }
+ }
+ return object;
+ }
+
+ public void validate() {
+ if (!ecDirectory.exists()) {
+ ECLog.logFatal("No project directory found.");
+ }
+ }
+
+ public void beginConfiguration(String configurationName) {
+ this.activeConfigurationName = configurationName;
+ this.activeConfigurationPreviouslyGeneratedFiles = extractGeneratedFilesForConfiguration(configurationName,
+ true, true);
+ }
+
+ public List extractGeneratedFilesForConfiguration(String configurationName, boolean onlyTiedToThisConfiguration, boolean remove) {
+ List singleConfigurationGeneratedFiles = new ArrayList<>();
+ for (GeneratedFile generatedFile : generatedFiles) {
+ boolean onlyThisConfig = generatedFile.hasSingleConfigurationOrigin(configurationName);
+ if (generatedFile.hasConfigurationOrigin(configurationName)) {
+ GeneratedFile singleConfigurationGeneratedFile = generatedFile.extractForConfiguration(
+ configurationName, remove);
+ if (onlyTiedToThisConfiguration && onlyThisConfig) {
+ singleConfigurationGeneratedFiles.add(singleConfigurationGeneratedFile);
+ }
+ }
+ }
+ return singleConfigurationGeneratedFiles;
+ }
+
+ public void endActiveConfiguration() {
+ List activeConfigurationGeneratedFiles = extractGeneratedFilesForConfiguration(
+ activeConfigurationName, true, false);
+ Set prevConfigurationOnlyGeneratedFiles = new HashSet<>();
+ for (GeneratedFile previouslyGeneratedFile : this.activeConfigurationPreviouslyGeneratedFiles) {
+ boolean found = false;
+ // TODO: make sure we only remove generated files that belong only to this configuration
+ for (GeneratedFile generatedFile : activeConfigurationGeneratedFiles) {
+ if (previouslyGeneratedFile.getFilepath().equals(generatedFile.getFilepath())) {
+ found = true;
+ }
+ }
+ if (!found) {
+ prevConfigurationOnlyGeneratedFiles.add(previouslyGeneratedFile);
+ }
+ }
+ if (!quietMode) {
+ ECLog.log("Number of files generated: " + activeConfigurationGeneratedFiles.size());
+ }
+ if (prevConfigurationOnlyGeneratedFiles.size() == 0) {
+ //ECLog.log("No files need to be removed.");
+ } else {
+ Set removedFilenames = new HashSet<>();
+ for (GeneratedFile fileToRemove : prevConfigurationOnlyGeneratedFiles) {
+ File file = new File(fileToRemove.getFilepath());
+ if (file.exists()) {
+ file.delete();
+ removedFilenames.add(getRelativePath(file));
+ }
+ }
+ CLCommand.displayItems(
+ "The following files were previously generated but are now no longer part of "
+ + "the project and so were deleted.",
+ removedFilenames, CLCommand.StdoutColor.RedForeground);
+ }
+ }
+
+ public String getRelativePath(File sourceFile) {
+ String absolutePath = sourceFile.getAbsolutePath();
+ String[] sourceParts = absolutePath.split(File.separator);
+
+ int lastMatchingIndex = -1;
+ for (int i = 0; i < cwdParts.length; i++) {
+ if (i + 1 == sourceParts.length) {
+ break;
+ }
+ if (!cwdParts[i].equals(sourceParts[i])) {
+ break;
+ }
+ lastMatchingIndex = i;
+ }
+ int numBackDirs = cwdParts.length - 1 - (lastMatchingIndex + 1);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < numBackDirs; i++) {
+ sb.append("..");
+ sb.append(File.separator);
+ }
+ for (int i = lastMatchingIndex + 1; i < sourceParts.length; i++) {
+ sb.append(sourceParts[i]);
+ if (i != (sourceParts.length) - 1) {
+ sb.append(File.separator);
+ }
+ }
+ String relativePath = sb.toString();
+ return relativePath;
+ }
+
+ public String findECDirectory(String fromHerePath) {
+ if (fromHerePath.equals(File.separator)) {
+ return null; // can't go up any more
+ }
+ File ecDirectory = new File(fromHerePath + File.separator + ECDirectoryName);
+ if (ecDirectory.exists()) {
+ return fromHerePath;
+ }
+ File parentDirectory = new File(fromHerePath + File.separator + "..");
+ try {
+ return findECDirectory(parentDirectory.getCanonicalPath());
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ public void addGeneratedFile(String path, String configurationName, String templateUri) {
+ generatedFiles.add(new GeneratedFile(path, configurationName, templateUri));
+ configurationNames = null;
+ templateUris = null;
+ }
+
+ public void close() {
+ saveFile(GeneratedFilename, generatedFiles);
+ saveFile(SchemaFilename, schemaDirectories);
+ }
+
+ private void saveFile(String filename, T object) {
+ Gson gson = new Gson();
+ String filepath = ecDirectory.getPath() + File.separator + filename;
+ try {
+ FileOutputStream fos = new FileOutputStream(filepath);
+ JsonWriter writer = new JsonWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8));
+ gson.toJson(object, ArrayList.class, writer);
+ writer.flush();
+ fos.close();
+ } catch (FileNotFoundException e) {
+ ECLog.logWarning("Unable to save project files.");
+ } catch (IOException e) {
+ ECLog.logWarning("Unable to save project files.");
+ }
+ }
+
+ public Set getConfigurationNames() {
+ if (configurationNames == null) {
+ configurationNames = new HashSet<>();
+
+ for (GeneratedFile file : generatedFiles) {
+ Set names = file.getConfigurationNames();
+ configurationNames.addAll(names);
+ }
+ }
+ return configurationNames;
+ }
+
+ public Set getTemplateUris() {
+ if (templateUris == null) {
+ templateUris = new HashSet<>();
+
+ for (GeneratedFile file : generatedFiles) {
+ Set uris = file.getTemplateUris();
+ templateUris.addAll(uris);
+ }
+ }
+ return templateUris;
+ }
+
+ public List getGeneratedFilesByTemplateUri(String templateUri) {
+ ArrayList files = new ArrayList<>();
+ for (GeneratedFile file : generatedFiles) {
+ if (file.hasTemplateOrigin(templateUri)) {
+ files.add(file);
+ }
+ }
+ return files;
+ }
+
+ public List getGeneratedFilesByConfigurationName(String configurationName) {
+ ArrayList files = new ArrayList<>();
+ for (GeneratedFile file : generatedFiles) {
+ if (file.hasConfigurationOrigin(configurationName)) {
+ files.add(file);
+ }
+ }
+ return files;
+ }
+
+ public final List getGeneratedFiles() {
+ return generatedFiles;
+ }
+
+ public Set getSourceFiles() {
+ Set sourceFilenames = new HashSet<>();
+ Collection sourceFiles = FileUtils.listFiles(
+ new File(ProjectManager.getInstance().getProjectBaseDirPath()),
+ new String[]{"eml", "edl"}, true);
+ for (File sourceFile : sourceFiles) {
+ String relativePath = getRelativePath(sourceFile);
+ sourceFilenames.add(relativePath);
+ }
+ return sourceFilenames;
+ }
+
+ public String getProjectBaseDirPath() {
+ return projectDirectory.getAbsolutePath();
+ }
+
+ public static ProjectManager getInstance() {
+ return instance;
+ }
+
+ public void setProjectBaseDirPath(String projectDirectoryPath) {
+ this.projectDirectory = new File(projectDirectoryPath);
+ }
+
+ public boolean isQuietMode() {
+ return quietMode;
+ }
+
+ public void setQuietMode(boolean quietMode) {
+ this.quietMode = quietMode;
+ }
+
+ public void registerSchemaDirectory(String path) {
+ if (schemaDirectories == null) {
+ schemaDirectories = new HashSet<>();
+ }
+ schemaDirectories.add(path);
+ }
+
+ public Set getSchemaDirectories() {
+ return schemaDirectories;
+ }
+}
diff --git a/src/main/java/org/entityc/compiler/repository/GitHubRepositoryImporter.java b/src/main/java/org/entityc/compiler/repository/GitHubRepositoryImporter.java
index da3adbd..f580957 100644
--- a/src/main/java/org/entityc/compiler/repository/GitHubRepositoryImporter.java
+++ b/src/main/java/org/entityc/compiler/repository/GitHubRepositoryImporter.java
@@ -6,12 +6,14 @@
package org.entityc.compiler.repository;
+import org.apache.commons.io.IOUtils;
import org.entityc.compiler.EntityCompiler;
import org.entityc.compiler.model.config.MTRepository;
import org.entityc.compiler.model.config.MTRepositoryImport;
import org.entityc.compiler.util.ECLog;
-import org.apache.commons.io.IOUtils;
+import org.kohsuke.github.GHBranch;
import org.kohsuke.github.GHContent;
+import org.kohsuke.github.GHRef;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
@@ -38,11 +40,11 @@ public RepositoryFile importFromRepository(MTRepository repository, MTRepository
"Unable to connect to GitHub: " + repository.getOrganization() + "/" + repository.getRepoName()
+ "\n" + e.getMessage());
}
- String pathPart = alternatePath != null ?
- (alternatePath + "/") :
- repository.getPath() != null && !repository.getPath().isEmpty() ?
- repository.getPath() + "/" :
- "";
+ String pathPart = alternatePath != null ?
+ (alternatePath + "/") :
+ repository.getPath() != null && !repository.getPath().isEmpty() ?
+ repository.getPath() + "/" :
+ "";
String gitRepoPath = pathPart + repositoryImport.getFilename() + "." + extension;
GHRepository repo = null;
try {
@@ -52,13 +54,16 @@ public RepositoryFile importFromRepository(MTRepository repository, MTRepository
+ repository.getRepoName());
}
try {
- ECLog.logInfo("Downloading file: " + gitRepoPath + " " + repository.getTag());
+ if (!repositoryImport.isQuietly()) {
+ ECLog.logInfo("Downloading file: " + gitRepoPath + " " + repository.getTag());
+ }
GHContent fileContent = repo.getFileContent(gitRepoPath, repository.getTag());
if (fileContent == null) {
ECLog.logFatal(repositoryImport,
"Could not find file in repository: " + cachedRepositoryFile.getFilepath() + " with tag "
+ repository.getTag());
}
+
String outputFilepath = cachedRepositoryFile.getFilepath();
// in case the filename has sub directories, make sure they are created
if (outputFilepath.contains(File.separator)) {
@@ -88,6 +93,50 @@ public RepositoryFile importFromRepository(MTRepository repository, MTRepository
return cachedRepositoryFile;
}
+ @Override
+ public void updateRepositoryCommitSHA1(MTRepository repository) {
+
+ if (repository.getCommitSHA1() != null) {
+ return; // we are good
+ }
+
+ try {
+ if (github == null) {
+ github = GitHub.connect();
+ }
+ } catch (IOException e) {
+ ECLog.logFatal(
+ "Unable to connect to GitHub: " + repository.getOrganization() + "/" + repository.getRepoName()
+ + "\n" + e.getMessage());
+ }
+
+ GHRepository repo = null;
+ try {
+ repo = github.getRepository(repository.getOrganization() + "/" + repository.getRepoName());
+ } catch (IOException e) {
+ ECLog.logFatal("Unable to connect to repository: " + repository.getOrganization() + "/"
+ + repository.getRepoName());
+ }
+
+ String sha1 = null;
+ try {
+ GHBranch branch = repo.getBranch(repository.getTag());
+ if (branch != null) {
+ sha1 = branch.getSHA1();
+ }
+ } catch (IOException e) {
+ // could not find the commit, maybe its not a branch name
+ }
+ try {
+ GHRef ref = repo.getRef("tags/" + repository.getTag());
+ sha1 = ref.getObject().getSha();
+ } catch (IOException e) {
+ // must not be a tag
+ }
+
+ repository.setCommitSHA1(sha1);
+ }
+
@Override
public void close() {
github = null;
diff --git a/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java b/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java
index 7c8c7f9..fdb8667 100644
--- a/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java
+++ b/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java
@@ -11,6 +11,7 @@
import org.entityc.compiler.model.config.MTRepository;
import org.entityc.compiler.model.config.MTRepositoryImport;
import org.entityc.compiler.util.ECLog;
+import org.entityc.compiler.util.ECStringUtil;
import java.io.File;
import java.io.FileInputStream;
@@ -23,14 +24,11 @@ public class LocalRepositoryImporter implements RepositoryImporter {
public RepositoryFile importFromRepository(MTRepository repository, MTRepositoryImport repositoryImport, RepositoryFile cachedRepositoryFile, String extension, String alternatePath) {
String outputFilepath = cachedRepositoryFile.getFilepath();
// in case the filename has sub directories, make sure they are created
- if (outputFilepath.contains(File.separator)) {
-
- int index = outputFilepath.lastIndexOf(File.separatorChar);
- if (index > 0) {
- String dirPath = outputFilepath.substring(0, index);
- if (!EntityCompiler.ensureDirectory(dirPath)) {
- ECLog.logFatal("Not able to create directory for template file: " + outputFilepath);
- }
+
+ String directoryPath = ECStringUtil.DirectoryPath(outputFilepath);
+ if (directoryPath != null) {
+ if (!EntityCompiler.ensureDirectory(directoryPath)) {
+ ECLog.logFatal("Not able to create directory for template file: " + outputFilepath);
}
}
@@ -54,6 +52,11 @@ public RepositoryFile importFromRepository(MTRepository repository, MTRepository
return cachedRepositoryFile;
}
+ @Override
+ public void updateRepositoryCommitSHA1(MTRepository repository) {
+ // nothing to do for this type of repository
+ }
+
@Override
public void close() {
}
diff --git a/src/main/java/org/entityc/compiler/repository/RepositoryCache.java b/src/main/java/org/entityc/compiler/repository/RepositoryCache.java
index 0e9b585..7caf1f4 100644
--- a/src/main/java/org/entityc/compiler/repository/RepositoryCache.java
+++ b/src/main/java/org/entityc/compiler/repository/RepositoryCache.java
@@ -6,10 +6,13 @@
package org.entityc.compiler.repository;
+import org.apache.commons.io.FileUtils;
import org.entityc.compiler.model.config.MTRepository;
import org.entityc.compiler.model.config.MTRepositoryType;
+import org.entityc.compiler.util.ECLog;
import java.io.File;
+import java.io.IOException;
import java.util.UUID;
public class RepositoryCache {
@@ -32,10 +35,6 @@ public RepositoryCache(CacheStructure structure) {
baseCacheDirectory.mkdirs();
}
- public File getBaseCacheDirectory() {
- return baseCacheDirectory;
- }
-
public RepositoryFile getRepositoryFile(MTRepository repository, String filename, boolean asInclude) {
String outputFilepath = baseCacheDirectory.getAbsolutePath() + File.separator;
@@ -44,7 +43,9 @@ public RepositoryFile getRepositoryFile(MTRepository repository, String filename
outputFilepath += filename;
break;
case UserCache: {
- String pathPart = repository.getPath() != null && !repository.getPath().isEmpty() ? repository.getPath() + File.separator : "";
+ String pathPart = repository.getPath() != null && !repository.getPath().isEmpty() ?
+ repository.getPath() + File.separator :
+ "";
String completeFilename = pathPart + filename;
if (repository.getType() == MTRepositoryType.LOCAL) {
outputFilepath = completeFilename;
@@ -52,7 +53,7 @@ public RepositoryFile getRepositoryFile(MTRepository repository, String filename
outputFilepath += getRepositoryCachePath(repository) + File.separator + completeFilename;
}
}
- break;
+ break;
}
RepositoryFile repositoryFile = new RepositoryFile(repository, outputFilepath, asInclude);
@@ -60,7 +61,56 @@ public RepositoryFile getRepositoryFile(MTRepository repository, String filename
}
private String getRepositoryCachePath(MTRepository repository) {
- return repository.getOrganization() + File.separator + repository.getRepoName() + File.separator + repository.getTag();
+ return repository.getOrganization() + File.separator + repository.getRepoName() + File.separator
+ + repository.getTag();
+ }
+
+ public void validateRepositoryInCache(MTRepository repository) {
+ if (structure != CacheStructure.UserCache || repository.getType() == MTRepositoryType.LOCAL || !repository.isValid()) {
+ return; // not this one
+ }
+ String commitSha1Filename = getBaseCacheDirectory().getAbsolutePath() + File.separator + getRepositoryCachePath(
+ repository) + File.separator + ".commitSha1";
+ File file = new File(commitSha1Filename);
+ String cacheSHA1 = null;
+ if (file.exists()) {
+ try {
+ cacheSHA1 = FileUtils.readFileToString(file);
+ } catch (IOException e) {
+ // oh well, assume it is not there
+ }
+ }
+ String repositoryCommitSHA1 = repository.getCommitSHA1();
+ if (repositoryCommitSHA1 == null || cacheSHA1 == null || !repository.getCommitSHA1().equals(cacheSHA1)) {
+ invalidateCacheDirectory(repository);
+ if (repositoryCommitSHA1 != null) {
+ try {
+ FileUtils.write(file, repositoryCommitSHA1);
+ } catch (IOException e) {
+ ECLog.logWarning("Unable to record repository sha1 in cache directory: " + commitSha1Filename);
+ }
+ }
+ }
+ }
+
+ public void invalidateCacheDirectory(MTRepository repository) {
+ if (structure != CacheStructure.UserCache) {
+ return;
+ }
+ String fullPath = getBaseCacheDirectory().getAbsolutePath() + File.separator + getRepositoryCachePath(
+ repository);
+ File file = new File(fullPath);
+ if (file.exists()) {
+ try {
+ FileUtils.cleanDirectory(file);
+ } catch (IOException e) {
+ ECLog.logWarning("Unable to remove cache directory: " + fullPath);
+ }
+ }
+ }
+
+ public File getBaseCacheDirectory() {
+ return baseCacheDirectory;
}
public enum CacheStructure {
diff --git a/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java b/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java
index 14a5e3c..24f1baa 100644
--- a/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java
+++ b/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java
@@ -47,6 +47,11 @@ public RepositoryFile getRepositoryFileByName(String identifier) {
return repositoryFilesByIdentifier.get(identifier);
}
+ public void updateRepositoryCommitSHA1(MTRepository repository) {
+ RepositoryImporter repositoryImporter = importersByType.get(repository.getType());
+ repositoryImporter.updateRepositoryCommitSHA1(repository);
+ }
+
public RepositoryFile importFromRepository(MTSpace space, MTRepositoryImport repositoryImport,
String extension, boolean asInclude) {
@@ -67,15 +72,20 @@ public RepositoryFile importFromRepository(MTSpace space, MTRepositoryImport rep
&& type == MTRepositoryType.LOCAL;
MTRepository sourceRepository = repository;
- String alternatePath = null;
+ String alternatePath = null;
if (shouldUseSpaceRepository) {
sourceRepository = space.getRepositoryThatImportedThisSpace();
- alternatePath = repository.getPath();
+ alternatePath = repository.getPath();
}
RepositoryImporter repositoryImporter = importersByType.get(sourceRepository.getType());
- RepositoryFile cacheRepositoryFile = repositoryCache.getRepositoryFile(sourceRepository, filename, asInclude);
- if (sourceRepository.getType() != MTRepositoryType.LOCAL && cacheRepositoryFile.exists()) { // check if it exists in the cache already
+ repositoryImporter.updateRepositoryCommitSHA1(
+ sourceRepository); // if it has one, fetch it so the cache will know if it needs to invalidate itself
+ repositoryCache.validateRepositoryInCache(sourceRepository);
+ RepositoryFile cacheRepositoryFile = repositoryCache.getRepositoryFile(sourceRepository, filename,
+ asInclude);
+ if (sourceRepository.getType() != MTRepositoryType.LOCAL
+ && cacheRepositoryFile.exists()) { // check if it exists in the cache already
if (EntityCompiler.isVerbose()) {
ECLog.logInfo("Found file already in cache: " + cacheRepositoryFile.getFilepath());
}
@@ -84,7 +94,7 @@ public RepositoryFile importFromRepository(MTSpace space, MTRepositoryImport rep
}
RepositoryFile file = repositoryImporter.importFromRepository(sourceRepository, repositoryImport,
- cacheRepositoryFile, extension, alternatePath);
+ cacheRepositoryFile, extension, alternatePath);
if (file == null || !file.exists()) {
String nameOrPath = repository.getType() == MTRepositoryType.LOCAL ?
repository.getPath() :
diff --git a/src/main/java/org/entityc/compiler/repository/RepositoryImporter.java b/src/main/java/org/entityc/compiler/repository/RepositoryImporter.java
index cb0d387..4e09580 100644
--- a/src/main/java/org/entityc/compiler/repository/RepositoryImporter.java
+++ b/src/main/java/org/entityc/compiler/repository/RepositoryImporter.java
@@ -12,6 +12,7 @@
public interface RepositoryImporter {
RepositoryFile importFromRepository(MTRepository repository, MTRepositoryImport repositoryImport, RepositoryFile cachedRepositoryFile, String extension, String alternatePath);
+ void updateRepositoryCommitSHA1(MTRepository repository);
void close();
}
diff --git a/src/main/java/org/entityc/compiler/structure/sql/SSSchemaVersioning.java b/src/main/java/org/entityc/compiler/structure/sql/SSSchemaVersioning.java
index 98a0009..0024ed9 100644
--- a/src/main/java/org/entityc/compiler/structure/sql/SSSchemaVersioning.java
+++ b/src/main/java/org/entityc/compiler/structure/sql/SSSchemaVersioning.java
@@ -117,8 +117,10 @@ public boolean accept(File pathname) {
return pathname.getName().startsWith("v") && pathname.getName().endsWith("_schema.json");
}
});
- for (File f : schemaFiles) {
- f.delete();
+ if (schemaFiles != null) {
+ for (File f : schemaFiles) {
+ f.delete();
+ }
}
File f = new File(schemaDirectoryPath + File.separator + "readVersion.json");
f.delete();
@@ -134,8 +136,10 @@ public boolean accept(File pathname) {
return pathname.getName().startsWith("V") && pathname.getName().endsWith("__model.sql");
}
});
- for (File fd : modelFiles) {
- fd.delete();
+ if (modelFiles != null) {
+ for (File fd : modelFiles) {
+ fd.delete();
+ }
}
}
}
diff --git a/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java b/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java
index 06460b6..e082bc7 100644
--- a/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java
+++ b/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java
@@ -26,6 +26,7 @@
import org.entityc.compiler.model.entity.MTRelationship;
import org.entityc.compiler.model.entity.MTType;
import org.entityc.compiler.model.entity.MTUniqueness;
+import org.entityc.compiler.project.ProjectManager;
import org.entityc.compiler.structure.sql.SSColumn;
import org.entityc.compiler.structure.sql.SSComment;
import org.entityc.compiler.structure.sql.SSForeignKey;
@@ -65,12 +66,13 @@ public void start() {
super.start();
- MTTransform config = getConfiguration().getTransformByName(getName());
- String outputName = config.getOutputNameByLocalName("primary");
+ MTTransform transform = getConfiguration().getTransformByName(getName());
+ String outputName = transform.getOutputNameByLocalName("primary");
MTDirectory output = getConfiguration().getOutputByName(outputName);
- String schemaOutputName = config.getOutputNameByLocalName("schema");
+ String schemaOutputName = transform.getOutputNameByLocalName("schema");
MTDirectory schemaOutput = getConfiguration().getOutputByName(schemaOutputName);
SSSchemaVersioning.setBasePath(schemaOutput.getPath());
+ ProjectManager.getInstance().registerSchemaDirectory(schemaOutput.getPath());
boolean requestToAdvance = SSSchemaVersioning.LoadAdvanceRequest();
advanceSchemaVersion = EntityCompiler.ShouldAdvanceSchemaVersion();
diff --git a/src/main/java/org/entityc/compiler/transform/TransformManager.java b/src/main/java/org/entityc/compiler/transform/TransformManager.java
index 3657989..938643b 100644
--- a/src/main/java/org/entityc/compiler/transform/TransformManager.java
+++ b/src/main/java/org/entityc/compiler/transform/TransformManager.java
@@ -7,6 +7,7 @@
package org.entityc.compiler.transform;
import org.entityc.compiler.EntityCompiler;
+import org.entityc.compiler.cmdline.CommandLine;
import org.entityc.compiler.model.MTRoot;
import java.io.File;
@@ -50,7 +51,7 @@ private static File SearchForTemplateFile(File directory, String templateFilenam
}
public static File FindTemplateFile(String templateFilename) {
- for (String searchPath : EntityCompiler.GetTemplateSearchPaths()) {
+ for (String searchPath : CommandLine.GetTemplateSearchPaths()) {
File dir = new File(searchPath);
File foundFile = SearchForTemplateFile(dir, templateFilename);
if (foundFile != null) {
diff --git a/src/main/java/org/entityc/compiler/transform/template/FileTemplateTransform.java b/src/main/java/org/entityc/compiler/transform/template/FileTemplateTransform.java
index 8b09acf..4566a59 100644
--- a/src/main/java/org/entityc/compiler/transform/template/FileTemplateTransform.java
+++ b/src/main/java/org/entityc/compiler/transform/template/FileTemplateTransform.java
@@ -57,7 +57,7 @@ public void load() {
public void load(boolean suppressImport) {
- //ECLog.logInfo("Parsing template: " + getName());
+ //ECLog.logInfo("Parsing template: " + getName() + " that has directory path: " + mtTemplate.getDirectoryName());
if (!findTemplateFile()) {
ECLog.logFatal("ERROR: Unable to find a template file with the name: " + templateFilename);
@@ -70,7 +70,7 @@ public void load(boolean suppressImport) {
} catch (IOException e) {
ECLog.logFatal("Unable to open template source file: " + file.getAbsolutePath() + " (" + mtTemplate.getName() + ": " + templateFilename + ")");
}
- loadFromStream(mtTemplate.getName(), file.getName(), input, suppressImport);
+ loadFromStream(mtTemplate.getName(), mtTemplate.getDirectoryPath(), file.getName(), input, suppressImport);
}
public void formatCode(MTCodeFormat codeFormat) {
diff --git a/src/main/java/org/entityc/compiler/transform/template/StringTemplateTransform.java b/src/main/java/org/entityc/compiler/transform/template/StringTemplateTransform.java
index bfdeefd..c6daa3d 100644
--- a/src/main/java/org/entityc/compiler/transform/template/StringTemplateTransform.java
+++ b/src/main/java/org/entityc/compiler/transform/template/StringTemplateTransform.java
@@ -57,7 +57,7 @@ public void load() {
public void load(boolean suppressImport) {
CharStream input = CharStreams.fromString(inputStringValue);
- loadFromStream("", "String", input, suppressImport);
+ loadFromStream("", null, "String", input, suppressImport);
}
public String getOutputStringValue() {
diff --git a/src/main/java/org/entityc/compiler/transform/template/TemplateASTVisitor.java b/src/main/java/org/entityc/compiler/transform/template/TemplateASTVisitor.java
index 34e0b10..86da69d 100644
--- a/src/main/java/org/entityc/compiler/transform/template/TemplateASTVisitor.java
+++ b/src/main/java/org/entityc/compiler/transform/template/TemplateASTVisitor.java
@@ -402,10 +402,7 @@ public Object visitImportTag(TemplateGrammer.ImportTagContext ctx) {
if (this.suppressImport) {
return null;
}
- String templateName = templatePath;
- if (templateName.contains("/")) {
- templateName = templateName.substring(templateName.lastIndexOf('/') + 1);
- }
+ String templateName = ECStringUtil.FilenameFromPath(templatePath);
if (false && EntityCompiler.isVerbose()) {
ECLog.logInfo(ctx, "Found Import of template: " + templatePath + " from repository " + fromRepositoryName);
if (fromRepositoryName == null) {
@@ -433,6 +430,7 @@ public Object visitImportTag(TemplateGrammer.ImportTagContext ctx) {
}
FTTemplate importedTemplate = configuration.parseTemplate(null, new MTFile(null, templateFile),
fromRepositoryName);
+ importedTemplate.setDirectoryPath(ECStringUtil.DirectoryPath(templatePath));
importedTemplate.setImported(true);
currentContainer(ctx).addChild(importedTemplate);
currentContainer(ctx).resolveFunctionCalls(importedTemplate);
diff --git a/src/main/java/org/entityc/compiler/transform/template/TemplateTransform.java b/src/main/java/org/entityc/compiler/transform/template/TemplateTransform.java
index 180ace1..5beba68 100644
--- a/src/main/java/org/entityc/compiler/transform/template/TemplateTransform.java
+++ b/src/main/java/org/entityc/compiler/transform/template/TemplateTransform.java
@@ -120,7 +120,7 @@ private void applyConfig(FTTransformSession session, JsonObject config) {
}
}
- protected void loadFromStream(String templateName, String filename, CharStream input, boolean suppressImport) {
+ protected void loadFromStream(String templateName, String directoryName, String filename, CharStream input, boolean suppressImport) {
ECANTLRErrorListener errorListener = new ECANTLRErrorListener(filename);
TemplateLexer lexer = new TemplateLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -141,6 +141,7 @@ protected void loadFromStream(String templateName, String filename, CharStream i
TemplateASTVisitor visitor = new TemplateASTVisitor(templateName, getConfiguration(), root.getSpace().getRepositoryByName(sourceRepositoryName), suppressImport);
template = (FTTemplate) visitor.visit(templateContext);
template.setName(getName());
+ template.setDirectoryPath(directoryName);
template.processIndents(true);
}
}
diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/FTInstall.java b/src/main/java/org/entityc/compiler/transform/template/tree/FTInstall.java
index 77f65ef..0976334 100644
--- a/src/main/java/org/entityc/compiler/transform/template/tree/FTInstall.java
+++ b/src/main/java/org/entityc/compiler/transform/template/tree/FTInstall.java
@@ -27,6 +27,7 @@
import org.entityc.compiler.transform.template.tree.expression.FTConstant;
import org.entityc.compiler.transform.template.tree.expression.FTExpression;
import org.entityc.compiler.util.ECLog;
+import org.entityc.compiler.util.ECStringUtil;
import java.io.File;
import java.io.IOException;
@@ -35,18 +36,18 @@
import static org.entityc.compiler.transform.template.formatter.ConfigurableElement.RequiredSpace;
@TemplateInstruction(category = TemplateInstructionCategory.FILE_IO,
- name = "install",
- usage = "`install `[`copy`]` `*sourceExpression*` `*destExpression*",
- summary = "Provides an easy way to install files into your local project.",
- description = "When setting up a project using files from a library, this instruction makes it easy "
- + "to install files from that library into the project directory structure. The files being installed "
- + "have their native file extension (not the one we use for templates) so they are easily "
- + "viewable and edited (using the code highlighter appropriate for them). You can also include "
- + "template code in them and the template code will execute during the install process. "
- + "Of course, the presence of the template code may interfere with the code highlighter and "
- + "as well, the template code will not be appropriately highlighted but when the amount of "
- + "template code is relatively small it can be very advantageous to use this install method over "
- + "just making it a template and running the template.")
+ name = "install",
+ usage = "`install `[`copy`]` `*sourceExpression*` `*destExpression*",
+ summary = "Provides an easy way to install files into your local project.",
+ description = "When setting up a project using files from a library, this instruction makes it easy "
+ + "to install files from that library into the project directory structure. The files being installed "
+ + "have their native file extension (not the one we use for templates) so they are easily "
+ + "viewable and edited (using the code highlighter appropriate for them). You can also include "
+ + "template code in them and the template code will execute during the install process. "
+ + "Of course, the presence of the template code may interfere with the code highlighter and "
+ + "as well, the template code will not be appropriately highlighted but when the amount of "
+ + "template code is relatively small it can be very advantageous to use this install method over "
+ + "just making it a template and running the template.")
public class FTInstall extends FTNode {
private final FTExpression sourceExpression;
@@ -56,16 +57,16 @@ public class FTInstall extends FTNode {
public FTInstall(ParserRuleContext ctx,
@TemplateInstructionArgument(optional = true, keyword = true,
- description = "If specified, the file will be copied verbatim without trying to execute "
- + "any template code.")
- Boolean copy,
+ description = "If specified, the file will be copied verbatim without trying to execute "
+ + "any template code.")
+ Boolean copy,
@TemplateInstructionArgument(
- description = "Defines the path and filename with extension of the source file. The path "
- + "is relative to the directory in which the template was configured.")
- FTExpression sourceExpression,
+ description = "Defines the path and filename with extension of the source file. The path "
+ + "is relative to the directory in which the template was configured.")
+ FTExpression sourceExpression,
@TemplateInstructionArgument(
- description = "Defines the destination path and directory name to copy the file into. "
- + "The path is relative to the directory in which the template was configured.")
+ description = "Defines the destination path and directory name to copy the file into. "
+ + "The path is relative to the directory in which the template was configured.")
FTExpression destExpression) {
super(ctx);
this.copyOnly = copy;
@@ -97,10 +98,7 @@ public void transform(FTTransformSession session) {
String destFilepath = (String) destFilepathObject;
String sourceFilePath = ((FTConstant) sourceExpression).getStringValue();
- String filename = sourceFilePath;
- if (filename.contains("/")) {
- filename = filename.substring(filename.lastIndexOf('/') + 1);
- }
+ String directoryPath = ECStringUtil.DirectoryPath(sourceFilePath);
if (sourceRepositoryName == null) {
ECLog.logFatal(this, "Cannot install files without an associated Repository.");
@@ -124,15 +122,14 @@ public void transform(FTTransformSession session) {
sourceFilePath = sourceFilePath.substring(0, lastExtensionIndex);
if (lastPathSeparatorIndex != -1) {
sourceFilename = sourceFilePath.substring(lastPathSeparatorIndex + 1);
- }
- else {
+ } else {
sourceFilename = sourceFilePath;
}
}
}
RepositoryImportManager importManager = new RepositoryImportManager(
- RepositoryCache.CacheStructure.UserCache);
+ RepositoryCache.CacheStructure.UserCache);
MTRepositoryImport repositoryImport = new MTRepositoryImport(null, false);
repositoryImport.setRepositoryName(sourceRepositoryName);
repositoryImport.setFilename(sourceFilePath);
@@ -153,20 +150,12 @@ public void transform(FTTransformSession session) {
ECLog.logFatal(this, e.getMessage());
}
- FTTemplate template = new FTTemplate(null);
- template.setName(sourceFilename + "." + sourceFileExtension);
- if (domain != null) {
- template.setDefaultDomainName(domain.getName());
- }
- if (language != null) {
- template.setLanguage(language.getName());
- }
-
MTDirectory directoryOfTemplateFile = new MTDirectory(null, "something");
directoryOfTemplateFile.setPath(destFilepath);
MTFile templateFile = new MTFile(directoryOfTemplateFile, fileToInstall);
- MTTemplate mtTemplate = new MTTemplate(null, session.getConfiguration(), templateFile);
+ MTTemplate mtTemplate = new MTTemplate(null, session.getConfiguration(), templateFile);
+ mtTemplate.setDirectoryPath(directoryPath);
MTRepositoryImport mtRepositoryImport = new MTRepositoryImport(null, false);
mtRepositoryImport.setRepositoryName(repository.getName());
mtTemplate.setRepositoryImport(mtRepositoryImport);
@@ -190,6 +179,7 @@ public void transform(FTTransformSession session) {
}
return;
}
+ ftTemplate.setDirectoryPath(directoryPath);
ftTemplate.insertTopContainer(ftFile);
ftTemplate.transform(session); // run it with this session
}
diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/FTTemplate.java b/src/main/java/org/entityc/compiler/transform/template/tree/FTTemplate.java
index 9736f67..2822bc4 100644
--- a/src/main/java/org/entityc/compiler/transform/template/tree/FTTemplate.java
+++ b/src/main/java/org/entityc/compiler/transform/template/tree/FTTemplate.java
@@ -23,6 +23,7 @@
import org.entityc.compiler.transform.template.TemplateDocExtractor;
import org.entityc.compiler.transform.template.TemplatePublishing;
import org.entityc.compiler.transform.template.formatter.TemplateFormatController;
+import org.entityc.compiler.util.ECStringUtil;
import org.entityc.compiler.util.ECVersion;
import java.io.File;
@@ -43,10 +44,12 @@
description = "Represents an actual template containing code to execute.")
public class FTTemplate extends FTContainerNode implements MTNamed {
+ private static DocumentationManager documentationManager = new DocumentationManager();
private final List calledExternalFunctions = new ArrayList<>();
private final Map publishers = new HashMap<>();
private final List authors = new ArrayList<>();
private String name;
+ private String directoryPath;
private ECVersion version;
private String language;
private String defaultDomainName;
@@ -55,9 +58,8 @@ public class FTTemplate extends FTContainerNode implements MTNamed {
private Map functionsByName = new HashMap<>();
private List referencedTags = new ArrayList<>();
private Set importedTemplates = new HashSet<>();
- private boolean hasOnlyFunctions = false;
- private MTRepository repository;
- private static DocumentationManager documentationManager = new DocumentationManager();
+ private boolean hasOnlyFunctions = false;
+ private MTRepository repository;
public FTTemplate(ParserRuleContext ctx) {
super(ctx, null);
@@ -189,17 +191,6 @@ public void transform(FTTransformSession session) {
}
}
- @Override
- @ModelMethod(category = ModelMethodCategory.TEMPLATE,
- description = "Returns the name of this template.")
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
public ECVersion getVersion() {
return version;
}
@@ -352,18 +343,37 @@ public static int GetTemplateLexerSymbol() {
return 0;
}
- public void setRepository(MTRepository repository) {
- this.repository = repository;
- }
-
public MTRepository getRepository() {
return repository;
}
+ public void setRepository(MTRepository repository) {
+ this.repository = repository;
+ }
+
public String getUri() {
if (repository != null) {
- return repository.getUri() + "/" + getName();
+ return repository.getUri() + File.separator + ECStringUtil.PathWithSeparator(directoryPath) + getName();
}
return getName();
}
+
+ @Override
+ @ModelMethod(category = ModelMethodCategory.TEMPLATE,
+ description = "Returns the name of this template.")
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDirectoryPath() {
+ return directoryPath;
+ }
+
+ public void setDirectoryPath(String directoryPath) {
+ this.directoryPath = directoryPath;
+ }
}
diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java b/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java
index 7438113..d0e8e03 100644
--- a/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java
+++ b/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java
@@ -18,11 +18,10 @@
import org.entityc.compiler.model.entity.MTEntity;
import org.entityc.compiler.model.entity.MTRelationship;
import org.entityc.compiler.model.language.MTLanguage;
+import org.entityc.compiler.project.ProjectManager;
import org.entityc.compiler.protobuf.PBASTVisitor;
import org.entityc.compiler.protobuf.PBLoaderExtractor;
import org.entityc.compiler.util.ECLog;
-import org.entityc.compiler.util.ECSessionFiles;
-import org.entityc.compiler.util.ECSessionManager;
import java.util.ArrayList;
import java.util.Arrays;
@@ -42,7 +41,6 @@ public class FTTransformSession {
private final Stack scopeStack = new Stack<>();
private final Stack bodyBlockStack = new Stack<>();
private final Map receiveMap = new HashMap<>();
- private final ECSessionFiles sessionFiles;
private final Map authorScopeMap = new HashMap<>();
private FTTemplate template;
private MTTransform templateTransform;
@@ -56,15 +54,15 @@ public class FTTransformSession {
private boolean debugMode;
public FTTransformSession(MTRoot root, MTConfiguration configuration, FTTemplate template) {
- this.space = root.getSpace();
+ this.space = root.getSpace();
this.configuration = configuration;
- this.template = template;
+ this.template = template;
if (EntityCompiler.isVerbose()) {
ECLog.logInfo("============= CREATED SCOPE FOR template: " + template.getName() + " ==================");
}
pushScope(new Scope());
if (configuration != null) {
- this.configuration = configuration;
+ this.configuration = configuration;
this.templateTransform = configuration.getTransformByName(template.getName());
this.templateTransform.setVersion(this.template.getVersion());
String outputName = this.templateTransform.getOutputNameByLocalName("primary");
@@ -81,7 +79,13 @@ public FTTransformSession(MTRoot root, MTConfiguration configuration, FTTemplate
}
addReadonlyNamedValue("true", Boolean.TRUE);
addReadonlyNamedValue("false", Boolean.FALSE);
- sessionFiles = ECSessionManager.getInstance().getSessionFiles(template.getName());
+ }
+
+ private void pushScope(Scope scope) {
+ if (false && EntityCompiler.isVerbose()) {
+ ECLog.logInfo("++++++ PUSHED SCOPE");
+ }
+ scopeStack.push(scope);
}
public void addReadonlyNamedValue(String name, Object value) {
@@ -122,12 +126,17 @@ public void setDebugMode(boolean debugMode) {
not going to execute its generating template code because it has the ifnotexist set.
*/
public void registerFileBlock(FTFile fileBlock) {
- sessionFiles.addFilePath(fileBlock.getFullFilePath());
+ ProjectManager.getInstance().addGeneratedFile(fileBlock.getFullFilePath(), configuration.getName(),
+ this.template.getUri()
+ );
}
+
public void pushFileBlock(FTFile fileBlock) {
fileBlock.getBody().clear();
bodyBlockStack.push(fileBlock);
- sessionFiles.addFilePath(fileBlock.getFullFilePath());
+ ProjectManager.getInstance().addGeneratedFile(fileBlock.getFullFilePath(), configuration.getName(),
+ this.template.getUri()
+ );
}
public void popFileBlock() {
@@ -250,13 +259,15 @@ public void popPreserveBlock(FTTransformSession session) {
String commentStart = "//";
String commentEnd = null;
if (language == null) {
- ECLog.logError(session.getTemplate(), "Cannot find language \"" + session.getTemplate().getLanguage() + "\" so defaulting line comment to //");
+ ECLog.logError(session.getTemplate(), "Cannot find language \"" + session.getTemplate().getLanguage()
+ + "\" so defaulting line comment to //");
} else if (language.getLineComment() == null) {
if (language.getBlockCommentStart() != null && language.getBlockCommentEnd() != null) {
commentStart = language.getBlockCommentStart();
- commentEnd = language.getBlockCommentEnd();
+ commentEnd = language.getBlockCommentEnd();
} else {
- ECLog.logError("Cannot find declaration of line or block comment for language \"" + session.getTemplate().getLanguage() + "\" so defaulting line comment to //");
+ ECLog.logError("Cannot find declaration of line or block comment for language \""
+ + session.getTemplate().getLanguage() + "\" so defaulting line comment to //");
}
} else {
commentStart = language.getLineComment();
@@ -277,7 +288,9 @@ public boolean test(FTBodyBlock ftBodyBlock) {
Optional extractedTextOptional = fileBlock.extract(startMarker, endMarker);
if (!extractedTextOptional.isPresent() && preserve.getDeprecatedNames().size() > 0) {
for (String deprecatedName : preserve.getDeprecatedNames()) {
- extractedTextOptional = fileBlock.extract(preserve.getStartMarker(commentStart, commentEnd, deprecatedName), preserve.getEndMarker(commentStart, commentEnd, deprecatedName));
+ extractedTextOptional = fileBlock.extract(
+ preserve.getStartMarker(commentStart, commentEnd, deprecatedName),
+ preserve.getEndMarker(commentStart, commentEnd, deprecatedName));
if (extractedTextOptional.isPresent()) {
break;
}
@@ -378,9 +391,11 @@ public Object getValue(String variableName) {
// if (debugMode) {
// ECLog.logInfo("DEBUG>> Getting value for \"" + variableName + "\" => " + scopeStack.peek().namedValues.get(variableName));
// }
- Scope currentScope = scopeStack.peek();
+ Scope currentScope = scopeStack.peek();
boolean isInternalVariable = variableName.startsWith("__");
- for (Scope scope = currentScope; scope != null; scope = isInternalVariable ? scope.parentScopeForInternalVariables : scope.parentScope) {
+ for (Scope scope = currentScope; scope != null; scope = isInternalVariable ?
+ scope.parentScopeForInternalVariables :
+ scope.parentScope) {
Object value = scope.namedValues.get(variableName);
if (value != null) {
// if (scope.name != null) {
@@ -451,7 +466,9 @@ public String getOutputStringValue() {
public void pushFunctionScope(FTFunction function) {
Scope newScope = new Scope();
- newScope.parentScopeForInternalVariables = scopeStack.size() > 0 ? scopeStack.peek() : null;
+ newScope.parentScopeForInternalVariables = scopeStack.size() > 0 ?
+ scopeStack.peek() :
+ null;
//ECLog.logInfo("------------- Pushing Function Scope: " + function.getName());
pushScope(newScope);
}
@@ -460,34 +477,30 @@ public void popFunctionScope() {
popScope();
}
+ private void popScope() {
+ if (false && EntityCompiler.isVerbose()) {
+ ECLog.logInfo("------ POPPED SCOPE");
+ }
+ scopeStack.pop();
+ }
+
public void pushAuthorScope(FTAuthor author) {
String publisherId = author.getTopAuthor().getUniqueId();
Scope scopeToUse = null;
if (!authorScopeMap.containsKey(publisherId)) {
- scopeToUse = new Scope();
+ scopeToUse = new Scope();
scopeToUse.name = publisherId;
authorScopeMap.put(publisherId, scopeToUse);
} else {
scopeToUse = authorScopeMap.get(publisherId);
}
- scopeToUse.parentScope = scopeStack.size() > 0 ? scopeStack.peek() : null;
+ scopeToUse.parentScope = scopeStack.size() > 0 ?
+ scopeStack.peek() :
+ null;
scopeToUse.parentScopeForInternalVariables = scopeToUse.parentScope;
pushScope(scopeToUse);
}
- private void pushScope(Scope scope) {
- if (false && EntityCompiler.isVerbose()) {
- ECLog.logInfo("++++++ PUSHED SCOPE");
- }
- scopeStack.push(scope);
- }
-
- private void popScope() {
- if (false && EntityCompiler.isVerbose()) {
- ECLog.logInfo("------ POPPED SCOPE");
- }
- scopeStack.pop();
- }
public void popAuthorScope() {
popScope(); // its removed from the stack but not from the map
}
diff --git a/src/main/java/org/entityc/compiler/util/ECANTLRErrorListener.java b/src/main/java/org/entityc/compiler/util/ECANTLRErrorListener.java
index 3e8499d..379bdcb 100644
--- a/src/main/java/org/entityc/compiler/util/ECANTLRErrorListener.java
+++ b/src/main/java/org/entityc/compiler/util/ECANTLRErrorListener.java
@@ -20,7 +20,7 @@ public ECANTLRErrorListener(String filename) {
@Override
public void syntaxError(Recognizer, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
- System.err.println(filename + ":" + line + "," + charPositionInLine + " " + msg);
+ ECLog.logFatal(filename + ":" + line + "," + charPositionInLine + " " + msg);
// super.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e);
}
}
diff --git a/src/main/java/org/entityc/compiler/util/ECLog.java b/src/main/java/org/entityc/compiler/util/ECLog.java
index a46f2cd..837a799 100644
--- a/src/main/java/org/entityc/compiler/util/ECLog.java
+++ b/src/main/java/org/entityc/compiler/util/ECLog.java
@@ -6,9 +6,10 @@
package org.entityc.compiler.util;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.entityc.compiler.cmdline.command.CLCommand;
import org.entityc.compiler.model.MTNode;
import org.entityc.compiler.transform.template.tree.FTNode;
-import org.antlr.v4.runtime.ParserRuleContext;
import java.io.File;
@@ -20,7 +21,7 @@ public class ECLog {
private static final String INFO = "INFO";
private static final String WARNING = "WARNING";
private static final String ERROR = "ERROR";
- private static final String FATAL = "ERROR";
+ private static final String FATAL = "FATAL";
static boolean exitOnFatal = true;
@@ -29,16 +30,16 @@ public static void SetExitOnFatal(boolean shouldExit) {
}
public static void logInfo(ParserRuleContext ctx, String message) {
- log("INFO", ctx, message, false);
+ log(INFO, ctx, message, false);
}
private static void log(String level, ParserRuleContext ctx, String message, boolean fatal) {
if (ctx == null) {
- System.out.println(level + ": " + message);
+ log(level, message, fatal);
} else {
String filename = filenameFromFullPath(ctx.getStart().getTokenSource().getSourceName());
System.out.println(level + ": " + filename + "(" + ctx.getStart().getLine() + "," + (
- ctx.getStart().getCharPositionInLine() + 1) + ") " + message);
+ ctx.getStart().getCharPositionInLine() + 1) + ") " + message + endColorization());
}
if (fatal) {
if (exitOnFatal) {
@@ -49,6 +50,17 @@ private static void log(String level, ParserRuleContext ctx, String message, boo
}
}
+ private static void log(String level, String message, boolean fatal) {
+ if (level.isEmpty()) {
+ System.out.println(message);
+ } else {
+ System.out.println(colorizedLevel(level) + ": " + message + endColorization());
+ }
+ if (fatal) {
+ exit(1);
+ }
+ }
+
private static String filenameFromFullPath(String fullPath) {
if (fullPath == null) {
return "??";
@@ -60,6 +72,19 @@ private static String filenameFromFullPath(String fullPath) {
return fullPath.substring(lastSlash + 1);
}
+ private static String endColorization() {
+ return CLCommand.StdoutColor.Default.getStringValue();
+ }
+
+ private static String colorizedLevel(String level) {
+ if (level.equals(WARNING)) {
+ level = CLCommand.StdoutColor.YellowForeground.getStringValue() + level;
+ } else if (level.equals(ERROR) || level.equals(FATAL)) {
+ level = CLCommand.StdoutColor.RedForeground.getStringValue() + level;
+ }
+ return level;
+ }
+
public static void logWarning(ParserRuleContext ctx, String message) {
log(WARNING, ctx, message, false);
}
@@ -84,18 +109,7 @@ private static void log(String level, FTNode node, String message, boolean fatal
String filename = filenameFromFullPath(node.getSourceName());
System.out.println(
level + ": " + filename + "(" + node.getStartLineNumber() + "," + node.getStartCharPosition() + ") "
- + message);
- if (fatal) {
- exit(1);
- }
- }
-
- private static void log(String level, String message, boolean fatal) {
- if (level.isEmpty()) {
- System.out.println(message);
- } else {
- System.out.println(level + ": " + message);
- }
+ + message + endColorization());
if (fatal) {
exit(1);
}
@@ -124,8 +138,9 @@ private static void log(String level, MTNode node, String message, boolean fatal
}
String filename = filenameFromFullPath(node.getSourceName());
System.out.println(
- level + ": " + filename + "(" + node.getStartLineNumber() + "," + node.getStartCharPosition() + ") "
- + message);
+ colorizedLevel(level) + ": " + filename + "(" + node.getStartLineNumber() + ","
+ + node.getStartCharPosition() + ") "
+ + message + endColorization());
if (fatal) {
exit(1);
}
diff --git a/src/main/java/org/entityc/compiler/util/ECSessionFiles.java b/src/main/java/org/entityc/compiler/util/ECSessionFiles.java
deleted file mode 100644
index 3080640..0000000
--- a/src/main/java/org/entityc/compiler/util/ECSessionFiles.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
- * Use of this file is governed by the BSD 3-clause license that
- * can be found in the LICENSE.md file in the project root.
- */
-
-package org.entityc.compiler.util;
-
-import com.google.gson.Gson;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonWriter;
-import org.entityc.compiler.EntityCompiler;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Set;
-
-public class ECSessionFiles {
-
- /**
- * Name of the session that will be used in the naming of the session file.
- */
- private final String sessionName;
- /**
- * The location to store a session file containing the list of files generated in the session.
- */
- private final String sessionSaveDirFilepath;
- Set filePaths = new HashSet<>();
-
- public ECSessionFiles(String sessionName, String sessionSaveDirFilepath) {
- this.sessionName = sessionName;
- this.sessionSaveDirFilepath = sessionSaveDirFilepath;
- }
-
- public void addFilePath(String filePath) {
- filePaths.add(filePath);
- }
-
- public void removeOldFiles() {
- Set filesNotInLatestSessionFiles = load();
- if (filesNotInLatestSessionFiles == null) {
- return;
- }
- filesNotInLatestSessionFiles.removeAll(this.filePaths);
-
- for (String pathOfFileToRemove : filesNotInLatestSessionFiles) {
- //ECLog.logInfo("Deleting previously generated file no longer being generated: " + pathOfFileToRemove);
- java.io.File file = new File(pathOfFileToRemove);
- if (EntityCompiler.isVerbose() && !file.delete()) {
- ECLog.logWarning("Unable to delete old generated file: " + pathOfFileToRemove);
- }
- }
- }
-
- private Set load() {
- Set returnSet = new HashSet<>();
- Gson gson = new Gson();
- String filepath = sessionFilename();
- try {
- FileInputStream fis = new FileInputStream(filepath);
- JsonReader reader = new JsonReader(new InputStreamReader(fis, StandardCharsets.UTF_8));
- returnSet = gson.fromJson(reader, Set.class);
- reader.close();
- } catch (FileNotFoundException e) {
- // will happen the first time since the file doesn't exist
- } catch (IOException e) {
- }
- return returnSet;
- }
-
- private String sessionFilename() {
- return sessionSaveDirFilepath + File.separator + sessionName + ".json";
- }
-
- public void save() {
- ArrayList sortedFilePaths = new ArrayList<>(this.filePaths);
- sortedFilePaths.sort(new Comparator() {
- @Override
- public int compare(String o1, String o2) {
- return o1.compareTo(o2);
- }
- });
- Gson gson = new Gson();
- String filepath = sessionFilename();
- try {
- EntityCompiler.ensureDirectory(sessionSaveDirFilepath);
- FileOutputStream fos = new FileOutputStream(filepath);
- JsonWriter writer = new JsonWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8));
- writer.setIndent(" ");
- gson.toJson(sortedFilePaths, ArrayList.class, writer);
- writer.flush();
- fos.close();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/src/main/java/org/entityc/compiler/util/ECSessionManager.java b/src/main/java/org/entityc/compiler/util/ECSessionManager.java
deleted file mode 100644
index 43b4e76..0000000
--- a/src/main/java/org/entityc/compiler/util/ECSessionManager.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2019-2022 The EntityC Project. All rights reserved.
- * Use of this file is governed by the BSD 3-clause license that
- * can be found in the LICENSE.md file in the project root.
- */
-
-package org.entityc.compiler.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-public class ECSessionManager {
-
- private static final String ECDirectoryName = ".ec";
- private static final String SessionsDirectoryName = "sessions";
- private static final ECSessionManager instance = new ECSessionManager();
- private final Map sessionsByName = new HashMap<>();
- private String projectBaseDirPath; // the directory with the .ec directory in it
- private File ecSessionsDirectory;
- private boolean createIfDoesntExist = false;
-
- private ECSessionManager() {
- }
-
- public static ECSessionManager getInstance() {
- return instance;
- }
-
- public boolean isCreateIfDoesntExist() {
- return createIfDoesntExist;
- }
-
- public void setCreateIfDoesntExist(boolean createIfDoesntExist) {
- this.createIfDoesntExist = createIfDoesntExist;
- }
-
- public String getProjectBaseDirPath() {
- return projectBaseDirPath;
- }
-
- public void setProjectBaseDirPath(String projectBaseDirPath) {
- this.projectBaseDirPath = projectBaseDirPath;
- }
-
- public void start() {
- if (projectBaseDirPath == null) {
- try {
- String invocationDirectory = new File(".").getCanonicalPath();
- projectBaseDirPath = findECDirectory(invocationDirectory);
- if (projectBaseDirPath == null) {
- projectBaseDirPath = invocationDirectory;
- }
- } catch (IOException e) {
- ECLog.logFatal("Unable to locate current working directory");
- }
- }
-
- if (ecSessionsDirectory == null) {
- ecSessionsDirectory = new File(
- projectBaseDirPath + File.separator + ECDirectoryName + File.separator + SessionsDirectoryName);
- }
- ecSessionsDirectory.mkdirs();
- }
-
- private String findECDirectory(String fromHerePath) {
- if (fromHerePath.equals(File.separator)) {
- return null; // can't go up any more
- }
- File ecDirectory = new File(fromHerePath + File.separator + ECDirectoryName);
- if (ecDirectory.exists()) {
- return fromHerePath;
- }
- File parentDirectory = new File(fromHerePath + File.separator + "..");
- try {
- return findECDirectory(parentDirectory.getCanonicalPath());
- } catch (IOException e) {
- return null;
- }
- }
-
- public ECSessionFiles getSessionFiles(String sessionName) {
- //we need to make sure all paths added to this session are relative to the found single project base path
-
- if (!sessionsByName.containsKey(sessionName)) {
- sessionsByName.put(sessionName, new ECSessionFiles(sessionName, ecSessionsDirectory.getAbsolutePath()));
- }
- return sessionsByName.get(sessionName);
- }
-
- public void close() {
- for (ECSessionFiles sessionFiles : sessionsByName.values()) {
- sessionFiles.removeOldFiles();
- sessionFiles.save();
- }
- }
-}
diff --git a/src/main/java/org/entityc/compiler/util/ECStringUtil.java b/src/main/java/org/entityc/compiler/util/ECStringUtil.java
index a5d1436..2c65f82 100644
--- a/src/main/java/org/entityc/compiler/util/ECStringUtil.java
+++ b/src/main/java/org/entityc/compiler/util/ECStringUtil.java
@@ -8,6 +8,7 @@
import org.atteo.evo.inflector.English;
+import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -339,4 +340,35 @@ public static boolean IsUncapitalized(String text) {
}
return Character.isAlphabetic(text.charAt(0)) && !Character.isUpperCase(text.charAt(0));
}
+
+ public static String RepeatString(String str, int times) {
+ StringBuilder sb = new StringBuilder();
+ for (int i=0;i cmdLine = new ArrayList<>();
+ cmdLine.add("build");
+ cmdLine.add("Tutorial");
+ cmdLine.add("--quiet");
+
+ cmdLine.add("-tp");
+ cmdLine.add(TestResourceDir);
for (String filename : files) {
cmdLine.add(TestResourceDir + File.separator + filename);
}
- cmdLine.add("-c");
- cmdLine.add("Tutorial");
- cmdLine.add("-tp");
- cmdLine.add(TestResourceDir);
- cmdLine.add("-D");
- cmdLine.add("TEMP_DIR=" + strTmp);
+ cmdLine.add("-DTEMP_DIR=" + strTmp);
EntityCompiler.main(cmdLine.toArray(new String[0]));
diff --git a/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt b/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt
index 5084417..e878dc4 100644
--- a/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt
+++ b/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt
@@ -469,8 +469,8 @@ These methods relate to a part of application configuration.
| Method/Property |
|---|
-| `String` **`directoryName`** |
-| Returns the directory name if available. Otherwise returns `null` |
+| `String` **`directoryPath`** |
+| Returns the directory path if available. Otherwise returns `null` |
|
|
| `String` **`filename`** |
| Returns the filename of the template which is preceded by a directory name if available. |
@@ -943,6 +943,9 @@ These methods relate to relationships.
| `boolean` **`hasParentRelationship`** |
| Indicates whether it has a least one relationship declared as parent. |
|
|
+| `boolean` [**`hasParentRelationshipToEntity(MTEntity parentEntity)`**](#class_MTEntity_hasParentRelationshipToEntity) |
+| Indicates whether it has a least one relationship declared as parent to the specified entity. |
+|
|
| `boolean` **`hasPrimaryParentRelationship`** |
| Indicates whether this entity has a primary parent relationship. A primary parent relationship is one which is declared `parent` and **not** declared `optional`. |
|
|
@@ -1025,6 +1028,16 @@ Given an entity object, this method will try to find and return a relationship o
+
+#### Method `boolean hasParentRelationshipToEntity(MTEntity parentEntity)`
+
+
+Indicates whether it has a least one relationship declared as parent to the specified entity.
+
+| Parameter | Description |
+|-----|-----|
+|`MTEntity parentEntity` | *no description* |
+
@@ -1632,6 +1645,9 @@ These methods relate to data types.
| `MTEnum` **`enumType`** |
| If this type is an enum type then it returns the enum type object. Otherwise it returns `null`. |
|
|
+| `boolean` **`isBooleanType`** |
+| Indicates whether this type is one of the integer data types. |
+|
|
| `boolean` **`isByteArrayType`** |
| Indicates whether this type is both an array type and also `byte` data type. |
|
|
@@ -1666,6 +1682,7 @@ These methods relate to data types.
+
#### Method `boolean isNativeDataType(DataType dataType)`
@@ -3010,7 +3027,7 @@ These methods relate to an outlet.
| Indicates whether this author has child authors that connect to an outlet. |
|
|
| `boolean` **`hasChildOutletsWithIntermediateParents`** |
-| Indicates whether this author has children authors that connect to an outlet and there are intermediate parent authors (that is authors that don't connect to an outlet). |
+| Indicates whether this author has children authors that connect to an outlet and there are intermediate parent authors (that is, authors that don't connect to an outlet). |
|
|
| `boolean` **`isOutletAuthor`** |
| Indicates whether this author connects to an outlet. |
diff --git a/test/resources/compiler/main/TemplateCodeFormatting/TemplateCodeFormattingExpected.eml b/test/resources/compiler/main/TemplateCodeFormatting/TemplateCodeFormattingExpected.eml
index 08ba037..6906ca8 100644
--- a/test/resources/compiler/main/TemplateCodeFormatting/TemplateCodeFormattingExpected.eml
+++ b/test/resources/compiler/main/TemplateCodeFormatting/TemplateCodeFormattingExpected.eml
@@ -13,22 +13,22 @@ Enum: ${enum.name}
${qualifier}Entity: ${entity.name}
$[foreach attribute in entity.attributes]
$[switch attribute.type]
- $[case string]
- $[let typeLongName = "String of characters"]
+ $[case uuid]
+ $[let typeLongName = "Unique Identifier - 128 bits"]
$[case int32]
$[let typeLongName = "32-bit Integer"]
$[case int64]
$[let typeLongName = "64-bit Integer"]
- $[case double]
- $[let typeLongName = "64-bit Floating Point"]
$[case float]
$[let typeLongName = "32-bit Floating Point"]
- $[case uuid]
- $[let typeLongName = "Unique Identifier - 128 bits"]
- $[case typedef]
- $[let typeLongName = "Typedef named " + attribute.type.name]
+ $[case double]
+ $[let typeLongName = "64-bit Floating Point"]
+ $[case string]
+ $[let typeLongName = "String of characters"]
$[case enum]
$[let typeLongName = "Enum named " + attribute.type.name]
+ $[case typedef]
+ $[let typeLongName = "Typedef named " + attribute.type.name]
$[case entity]
$[let typeLongName = "Entity named " + attribute.type.name]
$[default]