Transform Cli from options(e.g. -g=cpp) to json

parent e6a8e572
Pipeline #95695 passed with stages
in 10 minutes and 12 seconds
...@@ -82,16 +82,23 @@ ROS Kinetic currently only supports Linux and the installation is described [her ...@@ -82,16 +82,23 @@ ROS Kinetic currently only supports Linux and the installation is described [her
Maven generates the jar `embedded-montiarc-math-middleware-generator-{Version}-jar-with-dependencies.jar` Maven generates the jar `embedded-montiarc-math-middleware-generator-{Version}-jar-with-dependencies.jar`
and the cli is located in `de.monticore.lang.monticar.generator.middleware.DistributedTargetGeneratorCli`. and the cli is located in `de.monticore.lang.monticar.generator.middleware.DistributedTargetGeneratorCli`.
CLI Options: Parameters: `${file path to config json}` OR `-r ${raw json config string}`
* -m/--models-dir: full path to directory with EMAM models ```
* -r/--root-model: fully qualified name of the root model Schema of config json:
* -o/--output-dir: full path to output directory for generated files {
* -g/--generators: identifiers for the generators that should be used 'modelsDir':'<path to directory with EMAM models>',
* currently supported: 'outputDir':'<path to output directory for generated files>',
* cpp 'rootModel':'<fully qualified name of the root model>',
* roscpp 'generators':['<identifier for first generator>', '<identifier for second generator>',...],
* seperated by ',' 'emadlBackend':'<deep-learning-framework backend. Options: MXNET, CAFFE2>'
* example: cpp,roscpp }
```
Generator Options:
- Behaviour generators:
- 'cpp': EMAM2CPP
- 'emadlcpp': EMADL2CPP
- Middleware generators:
- 'roscpp': EMAM2Roscpp
Example: [CliUsage.sh](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Middleware/blob/master/src/test/resources/CliUsage.sh) Example: [CliUsage.sh](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Middleware/blob/master/src/test/resources/CliUsage.sh)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<groupId>de.monticore.lang.monticar</groupId> <groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc-math-middleware-generator</artifactId> <artifactId>embedded-montiarc-math-middleware-generator</artifactId>
<version>0.0.12-SNAPSHOT</version> <version>0.0.13-SNAPSHOT</version>
<!-- == PROJECT DEPENDENCIES ============================================= --> <!-- == PROJECT DEPENDENCIES ============================================= -->
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
<guava.version>18.0</guava.version> <guava.version>18.0</guava.version>
<junit.version>4.12</junit.version> <junit.version>4.12</junit.version>
<logback.version>1.1.2</logback.version> <logback.version>1.1.2</logback.version>
<gson.version>2.8.5</gson.version>
<!-- .. Plugins ....................................................... --> <!-- .. Plugins ....................................................... -->
<assembly.plugin>2.5.4</assembly.plugin> <assembly.plugin>2.5.4</assembly.plugin>
...@@ -51,6 +52,13 @@ ...@@ -51,6 +52,13 @@
</properties> </properties>
<dependencies> <dependencies>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.jgrapht</groupId> <groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId> <artifactId>jgrapht-core</artifactId>
...@@ -119,12 +127,6 @@ ...@@ -119,12 +127,6 @@
<version>2.3.23</version> <version>2.3.23</version>
</dependency> </dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<!-- .. Test Libraries ............................................... --> <!-- .. Test Libraries ............................................... -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
......
package de.monticore.lang.monticar.generator.middleware;
import java.util.Set;
public class CliParameters {
private String modelsDir;
private String outputDir;
private String rootModel;
private Set<String> generators;
private String emadlBackend;
public CliParameters() {
}
public CliParameters(String modelsDir, String outputDir, String rootModel, Set<String> generators) {
this(modelsDir, outputDir, rootModel, generators, "MXNET");
}
public CliParameters(String modelsDir, String outputDir, String rootModel, Set<String> generators, String emadlBackend) {
this.modelsDir = modelsDir;
this.outputDir = outputDir;
this.rootModel = rootModel;
this.generators = generators;
this.emadlBackend = emadlBackend;
}
public String getModelsDir() {
return modelsDir;
}
public String getOutputDir() {
return outputDir;
}
public String getRootModel() {
return rootModel;
}
public Set<String> getGenerators() {
return generators;
}
public String getEmadlBackend() {
return emadlBackend;
}
}
package de.monticore.lang.monticar.generator.middleware; package de.monticore.lang.monticar.generator.middleware;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol; import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.tagging.middleware.ros.RosToEmamTagSchema; import de.monticore.lang.embeddedmontiarc.tagging.middleware.ros.RosToEmamTagSchema;
import de.monticore.lang.monticar.emadl.generator.EMADLAbstractSymtab; import de.monticore.lang.monticar.emadl.generator.EMADLAbstractSymtab;
...@@ -14,6 +16,8 @@ import de.monticore.lang.tagging._symboltable.TaggingResolver; ...@@ -14,6 +16,8 @@ import de.monticore.lang.tagging._symboltable.TaggingResolver;
import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.Log;
import org.apache.commons.cli.*; import org.apache.commons.cli.*;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
...@@ -22,47 +26,23 @@ import java.util.HashSet; ...@@ -22,47 +26,23 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/**
* java -cp target/embedded-montiarc-math-middleware-generator-0.0.1-SNAPSHOT-jar-with-dependencies.jar \
* de.monticore.lang.monticar.generator.middleware.DistributedTargetGeneratorCli \
* --models-dir=src/test/resources/ \
* --root-model=tests.a.addComp \
* --output-dir=target/cli-test/src \
* --generators=cpp,roscpp
*/
public final class DistributedTargetGeneratorCli { public final class DistributedTargetGeneratorCli {
private static final Option OPTION_MODELS_PATH = Option.builder("m") private static final String helpString = "Parameters: <file path to config json> OR -r <raw json config string>\n\n" +
.longOpt("models-dir") "Schema of config json:\n" +
.desc("full path to directory with EMAM models") "{\n" +
.hasArg(true) " 'modelsDir':'<path to directory with EMAM models>',\n" +
.required(true) " 'outputDir':'<path to output directory for generated files>',\n" +
.build(); " 'rootModel':'<fully qualified name of the root model>',\n" +
" 'generators':['<identifier for first generator>', '<identifier for second generator>',...],\n" +
private static final Option OPTION_ROOT_MODEL = Option.builder("r") " 'emadlBackend':'<deep-learning-framework backend. Options: MXNET, CAFFE2>'\n" +
.longOpt("root-model") "}\n\n" +
.desc("fully qualified name of the root model") "Generator Options:\n" +
.hasArg(true) "Behaviour generators:\n" +
.required(true) " 'cpp': EMAM2CPP\n" +
.build(); " 'emadlcpp': EMADL2CPP\n" +
"Middleware generators:\n" +
private static final Option OPTION_OUTPUT_PATH = Option.builder("o") " 'roscpp': EMAM2Roscpp";
.longOpt("output-dir")
.desc("full path to output directory for generated files")
.hasArg(true)
.required(true)
.build();
private static final Option OPTION_GENERATORS = Option.builder("g")
.longOpt("generators")
.desc("identifiers for the generators that should be used")
.hasArg(true)
.required(true)
.numberOfArgs(10)
.valueSeparator(',')
.build();
private static final Option OPTION_EMADL_BACKEND = EMADLGeneratorCli.OPTION_BACKEND;
public static final String GENERATOR_CPP = "cpp"; public static final String GENERATOR_CPP = "cpp";
public static final String GENERATOR_EMADL = "emadlcpp"; public static final String GENERATOR_EMADL = "emadlcpp";
...@@ -73,23 +53,30 @@ public final class DistributedTargetGeneratorCli { ...@@ -73,23 +53,30 @@ public final class DistributedTargetGeneratorCli {
public static void main(String[] args) { public static void main(String[] args) {
System.out.println(Arrays.toString(args)); System.out.println(Arrays.toString(args));
Gson gson = new Gson();
CliParameters parameters = null;
//File name only
if(args.length == 1){
String filePath = expandHomeDir(args[0]);
try {
JsonReader jsonReader = new JsonReader(new FileReader(filePath));
parameters = gson.fromJson(jsonReader, CliParameters.class);
} catch (FileNotFoundException e) {
Log.error("0x49E6A: Can not find specified config file: " + args[0] + "!");
}
Options options = getOptions();
CommandLineParser parser = new DefaultParser();
CommandLine cliArgs = parseArgs(options, parser, args);
if (cliArgs != null) {
runGenerator(cliArgs);
} }
} //raw mode
else if(args.length == 2 && args[0].equals("-r")){
parameters = gson.fromJson(args[1], CliParameters.class);
}else{
System.out.println(helpString);
}
private static Options getOptions() { if(parameters != null){
Options options = new Options(); runGenerator(parameters);
options.addOption(OPTION_MODELS_PATH); }
options.addOption(OPTION_ROOT_MODEL);
options.addOption(OPTION_OUTPUT_PATH);
options.addOption(OPTION_GENERATORS);
options.addOption(OPTION_EMADL_BACKEND);
return options;
} }
private static Set<String> getGeneratorNames() { private static Set<String> getGeneratorNames() {
...@@ -101,70 +88,72 @@ public final class DistributedTargetGeneratorCli { ...@@ -101,70 +88,72 @@ public final class DistributedTargetGeneratorCli {
return res; return res;
} }
private static CommandLine parseArgs(Options options, CommandLineParser parser, String[] args) { public static void runGenerator(CliParameters cliParameters) {
CommandLine cliArgs; if(cliParameters.getModelsDir() == null){
try { Log.error("0xEB6FE: No models dir specified!");
cliArgs = parser.parse(options, args); return;
} catch (ParseException e) {
Log.error("0x9A1AC: Argument parsing exception", e);
return null;
} }
return cliArgs; String fullModelsDirPath = expandHomeDir(cliParameters.getModelsDir());
}
private static void runGenerator(CommandLine cliArgs) { if(cliParameters.getGenerators().size() == 0){
String modelsDirPath = expandHomeDir(cliArgs.getOptionValue(OPTION_MODELS_PATH.getOpt())); Log.error("0x6178E: No generator was specified!");
if(!Files.isDirectory(Paths.get(modelsDirPath))){ return;
Log.error("0x6444B: Models dir does not exist: " + modelsDirPath); }
if(!Files.isDirectory(Paths.get(fullModelsDirPath))){
Log.error("0x6444B: Models dir does not exist: " + fullModelsDirPath);
return; return;
} }
String outputPath = expandHomeDir(cliArgs.getOptionValue(OPTION_OUTPUT_PATH.getOpt()));
String rootModelName = cliArgs.getOptionValue(OPTION_ROOT_MODEL.getOpt());
Set<String> generators = Arrays.stream(cliArgs.getOptionValues(OPTION_GENERATORS.getOpt())).collect(Collectors.toSet());
TaggingResolver taggingResolver; TaggingResolver taggingResolver;
if (generators.contains(GENERATOR_EMADL)) { if (cliParameters.getGenerators().contains(GENERATOR_EMADL)) {
taggingResolver = EMADLAbstractSymtab.createSymTabAndTaggingResolver(modelsDirPath); taggingResolver = EMADLAbstractSymtab.createSymTabAndTaggingResolver(fullModelsDirPath);
} }
else{ else{
taggingResolver = AbstractSymtab.createSymTabAndTaggingResolver(modelsDirPath); taggingResolver = AbstractSymtab.createSymTabAndTaggingResolver(fullModelsDirPath);
} }
DistributedTargetGenerator generator = new DistributedTargetGenerator(); DistributedTargetGenerator generator = new DistributedTargetGenerator();
generator.setGenerationTargetPath(outputPath); generator.setGenerationTargetPath(cliParameters.getOutputDir());
Set<String> validGenNames = getGeneratorNames(); Set<String> validGenNames = getGeneratorNames();
generators.forEach(genName -> {
cliParameters.getGenerators().forEach(genName -> {
if (validGenNames.contains(genName)) { if (validGenNames.contains(genName)) {
Log.warn("Using generator " + genName); Log.warn("Using generator " + genName);
} else { } else {
Log.error("0xE28B6: Not a valid generator Name:" + genName +"."); Log.error("0xE28B6: Not a valid generator Name:" + genName +".");
return;
} }
}); });
ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.<ExpandedComponentInstanceSymbol>resolve(rootModelName, ExpandedComponentInstanceSymbol.KIND).orElse(null); ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.<ExpandedComponentInstanceSymbol>resolve(cliParameters.getRootModel(), ExpandedComponentInstanceSymbol.KIND).orElse(null);
if (componentInstanceSymbol == null) { if (componentInstanceSymbol == null) {
Log.error("0x5FFAE: The given component cannot be resolved."); Log.error("0x5FFAE: The given component cannot be resolved.");
return; return;
} }
if (generators.contains(GENERATOR_CPP)) { if (cliParameters.getGenerators().contains(GENERATOR_CPP)) {
generator.add(new CPPGenImpl(), "cpp"); generator.add(new CPPGenImpl(), "cpp");
} }
if (generators.contains(GENERATOR_EMADL)) { if (cliParameters.getGenerators().contains(GENERATOR_EMADL)) {
String backendString = cliArgs.getOptionValue(OPTION_EMADL_BACKEND.getOpt()); if(cliParameters.getEmadlBackend() != null && !cliParameters.getEmadlBackend().equals("")) {
generator.add(new EMADLGeneratorImpl(cliArgs.getOptionValue(OPTION_MODELS_PATH.getOpt()), backendString), "cpp"); generator.add(new EMADLGeneratorImpl(fullModelsDirPath, cliParameters.getEmadlBackend()), "cpp");
}else{
Log.error("0x0D839: Generator EMADL was specified but no backend was selected!");
return;
}
} }
if (generators.contains(GENERATOR_ROSCPP)) { if (cliParameters.getGenerators().contains(GENERATOR_ROSCPP)) {
generator.add(new RosCppGenImpl(), "roscpp"); generator.add(new RosCppGenImpl(), "roscpp");
RosToEmamTagSchema.registerTagTypes(taggingResolver); RosToEmamTagSchema.registerTagTypes(taggingResolver);
TagHelper.resolveTags(taggingResolver, componentInstanceSymbol); TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
} }
if (generators.contains(GENERATOR_ODV)) { if (cliParameters.getGenerators().contains(GENERATOR_ODV)) {
generator.add(new ODVGenImpl(), "odv"); generator.add(new ODVGenImpl(), "odv");
} }
...@@ -173,7 +162,6 @@ public final class DistributedTargetGeneratorCli { ...@@ -173,7 +162,6 @@ public final class DistributedTargetGeneratorCli {
} catch (IOException e) { } catch (IOException e) {
Log.error("Error generating files", e); Log.error("Error generating files", e);
} }
} }
private static String expandHomeDir(String path) { private static String expandHomeDir(String path) {
......
...@@ -2,89 +2,115 @@ package de.monticore.lang.monticar.generator.middleware; ...@@ -2,89 +2,115 @@ package de.monticore.lang.monticar.generator.middleware;
import de.monticore.lang.embeddedmontiarc.LogConfig; import de.monticore.lang.embeddedmontiarc.LogConfig;
import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Finding;
import de.se_rwth.commons.logging.Log;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.junit.*; import org.junit.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class CliTest{ public class CliTest {
private static final String VALID_MODELS_DIR_OPTION = "--models-dir=src/test/resources/"; private static final String VALID_MODELS_DIR_OPTION = "src/test/resources/";
private static final String VALID_ROOT_MODEL_OPTION = "--root-model=tests.a.addComp"; private static final String VALID_ROOT_MODEL_OPTION = "tests.a.addComp";
private static final String VALID_GENERATOR_CPP_OPTION = "--generators=cpp"; private static final List<String> VALID_GENERATOR_CPP_OPTION = Arrays.asList("cpp");
private static final String VALID_GENERATOR_ALL_OPTION = "--generators=cpp,roscpp,odv"; private static final List<String> VALID_GENERATOR_ALL_OPTION = Arrays.asList("cpp", "roscpp", "odv");
private static final String INVALID_MODELS_DIR_OPTION = "--models-dir=src/invalid/resources/"; private static final String INVALID_MODELS_DIR_OPTION = "src/invalid/resources/";
private static final String INVALID_ROOT_MODEL_OPTION = "--root-model=invalid.invalid.addComp"; private static final String INVALID_ROOT_MODEL_OPTION = "invalid.invalid.addComp";
private static final String INVALID_GENERATOR_OPTION = "--generators=invalid"; private static final List<String> INVALID_GENERATOR_OPTION = Arrays.asList("invalid");
private static final String INVALID_GENERATOR_EMPTY_OPTION = "--generators="; private static final List<String> INVALID_GENERATOR_EMPTY_OPTION = new ArrayList<>();
public static final String RESNET_MODELNAME = "tests.emadlTests.resNet34"; public static final String RESNET_MODELNAME = "tests.emadlTests.resNet34";
private String buildParameterJson(String modelsDir, String rootModel, Collection<String> generators, String outputDir) {
return buildParameterJson(modelsDir, rootModel, generators, outputDir, null);
}
private String buildParameterJson(String modelsDir, String rootModel, Collection<String> generators, String outputDir, String emadlBackend) {
String result = "{";
result += "'modelsDir': '" + modelsDir + "', ";
result += "'rootModel': '" + rootModel + "', ";
result += "'generators': [" + generators.stream().map(g -> "'" + g + "'").collect(Collectors.joining(", ")) + "], ";
if (emadlBackend != null) {
result += "'emadlBackend': '" + emadlBackend + "', ";
}
result += "'outputDir': '" + outputDir + "'";
result += "}";
return result;
}
@BeforeClass @BeforeClass
public static void initLog(){ public static void initLog() {
LogConfig.init(); LogConfig.init();
LogConfig.enableFailQuick(false); LogConfig.enableFailQuick(false);
} }
@Before @Before
public void clearFindings(){ public void clearFindings() {
LogConfig.getFindings().clear(); LogConfig.getFindings().clear();
} }
@AfterClass @AfterClass
public static void resetLog(){ public static void resetLog() {
LogConfig.getFindings().clear(); LogConfig.getFindings().clear();
LogConfig.enableFailQuick(true); LogConfig.enableFailQuick(true);
} }
@Test @Test
public void testParserError(){ public void testParserError() {
String[] args = { String[] args = {
"invalidParsingArg"}; "invalidParsingArg"};
DistributedTargetGeneratorCli.main(args); DistributedTargetGeneratorCli.main(args);
assertTrue(LogConfig.getErrorCount() == 1); assertTrue(LogConfig.getErrorCount() == 1);
assertTrue(LogConfig.getFindings().stream().map(Finding::getMsg).anyMatch(msg -> msg.contains("0x9A1AC"))); assertTrue(LogConfig.getFindings().stream().map(Finding::getMsg).anyMatch(msg -> msg.contains("0x49E6A")));
} }
@Test @Test
public void testNoGenerators(){ public void testNoGenerators() {
String[] args = { String json = buildParameterJson(
VALID_MODELS_DIR_OPTION, VALID_MODELS_DIR_OPTION,
VALID_ROOT_MODEL_OPTION, VALID_ROOT_MODEL_OPTION,
INVALID_GENERATOR_EMPTY_OPTION, INVALID_GENERATOR_EMPTY_OPTION,
"--output-dir=target/cliTest/NoGenerators/"}; "target/cliTest/NoGenerators/");
DistributedTargetGeneratorCli.main(args);
DistributedTargetGeneratorCli.main(new String[]{"-r", json});
assertTrue(LogConfig.getErrorCount() == 1); assertTrue(LogConfig.getErrorCount() == 1);
assertTrue(LogConfig.getFindings().stream().map(Finding::getMsg).anyMatch(msg -> msg.contains("0xE28B6")));