Commit addae100 authored by Alexander David Hellwig's avatar Alexander David Hellwig

Merge branch 'master' into ML_clustering

# Conflicts:
#	README.md
#	pom.xml
#	src/main/java/de/monticore/lang/monticar/generator/middleware/DistributedTargetGenerator.java
#	src/main/java/de/monticore/lang/monticar/generator/middleware/cli/DistributedTargetGeneratorCli.java
#	src/main/java/de/monticore/lang/monticar/generator/middleware/helpers/RosHelper.java
#	src/test/java/de/monticore/lang/monticar/generator/middleware/GenerationTest.java
parents 6fa1b264 70f8eb21
Pipeline #115570 failed with stages
in 29 seconds
stages:
- windows
- linux
masterJobLinux:
stage: linux
image: maven:3-jdk-8
script:
- mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean deploy --settings settings.xml
- cat target/site/jacoco/index.html
- mvn package sonar:sonar -s settings.xml
only:
- master
- linuxCompile
- integration
- linuxDeploy
masterJobWindows:
stage: windows
......@@ -19,11 +11,39 @@ masterJobWindows:
tags:
- Windows10
BranchJobLinux:
stage: linux
CompileJobLinux:
stage: linuxCompile
image: maven:3-jdk-8
artifacts:
paths:
- target/
expire_in: 1 day
script:
- mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean install --settings settings.xml
- cat target/site/jacoco/index.html
except:
- master
\ No newline at end of file
DeployJobLinux:
stage: linuxDeploy
image: maven:3-jdk-8
dependencies:
- CompileJobLinux
script:
- mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B deploy --settings settings.xml
only:
- master
RosIntegrationJob:
stage: integration
image: registry.git.rwth-aachen.de/monticore/embeddedmontiarc/generators/emam2middleware/ema-ros-kinetic
dependencies:
- CompileJobLinux
script:
- ./src/test/bash/integrationTestRos.sh
Ros2IntegrationJob:
stage: integration
image: registry.git.rwth-aachen.de/monticore/embeddedmontiarc/generators/emam2middleware/ema-ros-crystal
dependencies:
- CompileJobLinux
script:
- ./src/test/bash/integrationTestRos2.sh
......@@ -11,8 +11,11 @@ It also supports automatic clustering of the subcomponents to deploy on differen
see [TUTORIAL_ADD_MIDDLEWARE.md](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Middleware/blob/master/TUTORIAL_ADD_MIDDLEWARE.md)
## Dependencies needed to compile the generated projects
### Note
The generator creates compile scripts for all supported compilers. A project with ROS Middleware contains `compile.sh`, as only Linux is supported by ROS. A project with ROS2 contains `compile.sh` and `compileMsbuild.bat` as Linux and Windows(with Msbuild) are supported.
If you are having problems compiling on Windows because of the path length limit, use `substCompileMsbuild.bat` or `substCompileMingw.bat`.
### All generated projects
CMake, Make,a C++ compiler, and Armadillo are required to compile the generated projects.
CMake, Make, a C++ compiler, and Armadillo are required to compile the generated projects.
#### Linux
Gcc is recommended as the C++ compiler.
Example install of all needed packages for ubuntu:
......@@ -33,13 +36,6 @@ $ ls "$Armadillo_HOME/include"
armadillo_bits armadillo.h
```
Compiling a generated project:
```bash
cd /path/to/build/directory
cmake /path/to/generated/project/source
make
```
#### Windows
Mingw64 gcc is recommended as the C++ compiler. Download a version with all needed tools from [here](https://rwth-aachen.sciebo.de/s/igDWzLpdO5zYHBj/download?path=%2Fwin64&files=mingw64.zip).
......@@ -64,18 +60,45 @@ armadillo.h
...
```
Compiling a generated project:
Alternatively Msbuild can be used as a compiler. Download and install Build Tools für Visual Studio 2017 by visiting [this](https://visualstudio.microsoft.com/de/downloads/) site, and navigating to `Tools for Visual Studio 2017`.
Set the environment variable `msbuild_HOME` to the Folder containing `vcvars64.bat`(Standard destination: "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build")
To check everything is installed correctly use where/dir:
```batch
cd C:\path\to\build\directory
cmake C:\path\to\generated\project\source -G "MinGW Makefiles"
make
> where cmake
C:\Program Files\CMake\bin\cmake.exe
> dir /b "%Armadillo_HOME%\include"
armadillo
armadillo.h
...
> dir /b "%msbuild_HOME%"
vcvars32.bat
vcvars64.bat
...
> call "%msbuild_HOME%\vcvars64.bat"
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.0
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
> where msbuild
C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe
```
Please note: It is highly recommended, you stick to the exact versions as stated above. Otherwise you might run into trouble regarding the interplay between cmake/make and the Armadillo library. In particular problems have been reported using Cygwin.
### Projects with roscpp generator
Only for generated projects that contain a ROS adapter(e.g. -g=cpp,roscpp).
Only for generated projects that contain a ROS adapter(e.g. "generators":["cpp","roscpp"]).
ROS Kinetic currently only supports Linux and the installation is described [here](http://wiki.ros.org/kinetic/Installation/Ubuntu).
Set the environment varialble `ROS_HOME` to the base of your ROS installation.
### Projects with ros2cpp/rclcpp generator
Only for generated projects that contain a ROS2 adapter(e.g. "generators":["cpp","rclcpp"]).
Tested under ROS2 Bouncy and Crystal with Windows 10 and Ubuntu 18.04 respectively and the installation is described [here](https://index.ros.org/doc/ros2/Installation/).
ROS2 under Windows can only be compiled with msbuild.
Set the environment varialble `ROS2_HOME` to the base of your ROS2 installation.
## Usage
### CLI
......@@ -197,22 +220,11 @@ Look at [GenerationTest::testMiddlewareGenerator](https://git.rwth-aachen.de/mon
#### Use-case 2: Creating multiple executables for distributed systems
Look at [GenerationTest::testDistributedTargetGenerator](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Middleware/blob/master/src/test/java/de/monticore/lang/monticar/generator/middleware/GenerationTest.java). The component is defined in [src/test/resources/dist/DistComp.emam](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Middleware/blob/master/src/test/resources/tests/dist/DistComp.emam) and the tags for the connection to ros are defined in [src/test/resources/tests/dist/SimpleDist.tag](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Middleware/blob/master/src/test/resources/tests/dist/SimpleDist.tag)
#### Compile and run the generated ROS Projects
1. install needed software:
* ROS Kinetic(http://wiki.ros.org/kinetic/Installation)
* CMake(https://cmake.org/)
* Armadillo 8 or higher( www.arma.sourceforge.net)
* creating a copy of the library named armadillo.h might be necessary.
1. source your ros environment(http://wiki.ros.org/ROS/Tutorials/InstallingandConfiguringROSEnvironment , 2.)
1. a) run src/test/resources/TargetCompilation.sh from **this project's** root
1. or b) compile a single project by
* changing to the **generated project's** root
* create a folder build/ and change into it
* run: cmake ../src
* run: make
1. Start ros and the other nodes
* minimal working example: run: roscore
1. If the project was created by a MiddlewareGenerator, run the executable(s) at build/coordinator(/<subcomp.name>)/Coordinator_<(sub)component.name>
2.
## Running the Integration tests locally
To run the integration tests locally, `docker` needs to be installed. Install instructions can be found [here](https://docs.docker.com/install/).
Run the tests by executing [dockerLocalIntegrationTestRos.sh](src/test/bash/dockerLocalIntegrationTestRos.sh) or [dockerLocalIntegrationTestRos2.sh](src/test/bash/dockerLocalIntegrationTestRos2.sh) as root:
```bash
sudo src/test/bash/dockerLocalIntegrationTestRos.sh
sudo src/test/bash/dockerLocalIntegrationTestRos2.sh
```
\ No newline at end of file
......@@ -9,7 +9,7 @@
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc-math-middleware-generator</artifactId>
<version>0.0.14-SNAPSHOT</version>
<version>0.0.20-SNAPSHOT</version>
<!-- == PROJECT DEPENDENCIES ============================================= -->
......@@ -20,10 +20,10 @@
<se-commons.version>1.7.7</se-commons.version>
<embedded-montiarc.version>0.1.9-SNAPSHOT</embedded-montiarc.version>
<Embedded-montiarc-math-generator.version>0.1.3-SNAPSHOT</Embedded-montiarc-math-generator.version>
<Embedded-montiarc-math-roscpp-generator.version>0.1.1-SNAPSHOT</Embedded-montiarc-math-roscpp-generator.version>
<EMADL.version>0.2.4</EMADL.version>
<EMADL2CPP.version>0.2.6-SNAPSHOT</EMADL2CPP.version>
<Embedded-montiarc-math-generator.version>0.1.7-SNAPSHOT</Embedded-montiarc-math-generator.version>
<Embedded-montiarc-math-roscpp-generator.version>0.1.3-SNAPSHOT</Embedded-montiarc-math-roscpp-generator.version>
<EMADL2CPP.version>0.2.8</EMADL2CPP.version>
<EMADL.version>0.2.6</EMADL.version>
<embedded-montiarc-component-clustering.version>0.0.1-SNAPSHOT</embedded-montiarc-component-clustering.version>
<!-- .. Libraries .................................................. -->
......
......@@ -38,7 +38,7 @@ public class CMakeGenerator extends StarBridgeGenerator {
content.append("cmake_minimum_required(VERSION 3.5)\n");
//TODO setProjectName?
content.append("project (default)\n");
content.append("set (CMAKE_CXX_STANDARD 11)\n");
content.append("set (CMAKE_CXX_STANDARD 14)\n");
getGeneratorImpls().stream()
.filter(gen -> gen.willAccept(componentInstanceSymbol))
......
......@@ -5,11 +5,14 @@ import de.monticore.lang.monticar.clustering.*;
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.middleware.cli.ClusteringParameters;
import de.monticore.lang.monticar.generator.middleware.cli.ResultChoosingStrategy;
import de.monticore.lang.monticar.generator.middleware.compile.CompilationGenerator;
import de.monticore.lang.monticar.generator.middleware.helpers.*;
import de.monticore.lang.monticar.generator.middleware.impls.GeneratorImpl;
import de.monticore.lang.monticar.generator.middleware.impls.RclCppGenImpl;
import de.monticore.lang.monticar.generator.middleware.impls.RosCppGenImpl;
import de.monticore.lang.monticar.generator.middleware.impls.MiddlewareTagGenImpl;
import de.monticore.lang.tagging._symboltable.TaggingResolver;
import org.apache.commons.io.FileUtils;
import de.se_rwth.commons.logging.Log;
import java.io.File;
import java.io.IOException;
......@@ -44,7 +47,14 @@ public class DistributedTargetGenerator extends CMakeGenerator {
@Override
public void setGenerationTargetPath(String path) {
super.setGenerationTargetPath(path);
String res = path;
if(res.endsWith("/") || res.endsWith("\\")){
res = res.substring(0,res.length() - 1);
}
if(res.endsWith("/src") || res.endsWith("\\src")){
res = res.substring(0, res.length() - 4);
}
super.setGenerationTargetPath(res);
}
@Override
......@@ -72,12 +82,6 @@ public class DistributedTargetGenerator extends CMakeGenerator {
subDirs.add(NameHelper.getNameTargetLanguage(comp.getFullName()));
}
//generate rosMsg CMake iff a .msg file was generated
if(files.stream().anyMatch(f -> f.getName().endsWith(".msg"))){
subDirs.add("rosMsg");
files.add(generateRosMsgGen());
}
if(generateMiddlewareTags){
MiddlewareTagGenImpl middlewareTagGen = new MiddlewareTagGenImpl();
middlewareTagGen.setGenerationTargetPath(generationTargetPath + "emam/");
......@@ -86,6 +90,7 @@ public class DistributedTargetGenerator extends CMakeGenerator {
}
files.add(generateCMake(componentInstanceSymbol));
files.addAll(generateCompileScripts());
return files;
}
......@@ -140,7 +145,7 @@ public class DistributedTargetGenerator extends CMakeGenerator {
private GeneratorImpl createFullGenerator(String subdir) {
MiddlewareGenerator res = new MiddlewareGenerator();
res.setGenerationTargetPath(generationTargetPath + (subdir.endsWith("/") ? subdir : subdir + "/"));
res.setGenerationTargetPath(generationTargetPath + "src/" + (subdir.endsWith("/") ? subdir : subdir + "/"));
this.getGeneratorImpls().forEach(gen -> res.add(gen, this.getImplSubdir(gen)));
......@@ -148,7 +153,7 @@ public class DistributedTargetGenerator extends CMakeGenerator {
}
private void fixComponentInstance(EMAComponentInstanceSymbol componentInstanceSymbol) {
RosHelper.fixRosConnectionSymbols(componentInstanceSymbol);
RosHelper.fixRosConnectionSymbols(componentInstanceSymbol, this.getGeneratorImpls().stream().anyMatch(g -> g instanceof RclCppGenImpl));
}
@Override
......@@ -170,7 +175,32 @@ public class DistributedTargetGenerator extends CMakeGenerator {
fileContent.setFileContent(content.toString());
return FileHelper.generateFile(generationTargetPath, fileContent);
return FileHelper.generateFile(generationTargetPath + "src/", fileContent);
}
protected List<File> generateCompileScripts(){
List<File> res = new ArrayList<>();
boolean useRos = this.getGeneratorImpls().stream().anyMatch(impl -> impl instanceof RosCppGenImpl);
boolean useRos2 = this.getGeneratorImpls().stream().anyMatch(impl -> impl instanceof RclCppGenImpl);
List<CompilationGenerator> generators = CompilationGenerator.getInstanceOfAllGenerators();
generators.forEach(g -> g.setUseRos(useRos));
generators.forEach(g -> g.setUseRos2(useRos2));
generators.stream()
.peek(g -> g.setUseRos(useRos))
.peek(g -> g.setUseRos2(useRos2))
.filter(CompilationGenerator::isValid)
.forEach(g -> {
try {
res.addAll(FileHelper.generateFiles(generationTargetPath ,g.getCompilationScripts()));
} catch (IOException e) {
Log.error("0xD4BAA: Error generating compile scripts!", e);
}
});
return res;
}
}
......@@ -24,13 +24,22 @@ public class MiddlewareGenerator extends CMakeGenerator {
}, subdir);
List<File> files = super.generate(componentInstanceSymbol, taggingResolver);
files.add(FileHelper.generateFile(generationTargetPath + subdir, generateIAdapter(componentInstanceSymbol)));
files.add(FileHelper.generateFile(generationTargetPath + subdir, generateIAdapterHeader(componentInstanceSymbol)));
files.add(FileHelper.generateFile(generationTargetPath + subdir, generateIAdapterCpp(componentInstanceSymbol)));
files.add(FileHelper.generateFile(generationTargetPath + subdir, generateCoordinator(componentInstanceSymbol, files)));
files.add(FileHelper.generateFile(generationTargetPath + subdir, generateCoordinatorCMakeList(componentInstanceSymbol, files)));
return files;
}
private FileContent generateIAdapter(EMAComponentInstanceSymbol componentInstanceSymbol) {
private FileContent generateIAdapterCpp(EMAComponentInstanceSymbol componentInstanceSymbol) {
FileContent res = new FileContent();
String name = NameHelper.getNameTargetLanguage(componentInstanceSymbol.getFullName());
res.setFileName("IAdapter_" + name + ".cpp");
res.setFileContent("#include \"IAdapter_" + name + ".h\"");
return res;
}
private FileContent generateIAdapterHeader(EMAComponentInstanceSymbol componentInstanceSymbol) {
FileContent res = new FileContent();
String name = NameHelper.getNameTargetLanguage(componentInstanceSymbol.getFullName());
res.setFileName("IAdapter_" + name + ".h");
......
......@@ -9,6 +9,7 @@ import de.monticore.lang.monticar.generator.middleware.impls.CPPGenImpl;
import de.monticore.lang.monticar.generator.middleware.impls.EMADLGeneratorImpl;
import de.monticore.lang.monticar.generator.middleware.impls.ODVGenImpl;
import de.monticore.lang.monticar.generator.middleware.impls.RosCppGenImpl;
import de.monticore.lang.monticar.generator.middleware.impls.*;
import de.monticore.lang.monticar.generator.order.simulator.AbstractSymtab;
import de.monticore.lang.monticar.generator.roscpp.helper.TagHelper;
import de.monticore.lang.tagging._symboltable.TaggingResolver;
......@@ -45,6 +46,9 @@ public final class DistributedTargetGeneratorCli {
public static final String GENERATOR_EMADL = "emadlcpp";
public static final String GENERATOR_ROSCPP = "roscpp";
public static final String GENERATOR_ODV = "odv";
//ros2cpp is an alias for rclcpp
public static final String GENERATOR_RCLCPP = "rclcpp";
public static final String GENERATOR_ROS2CPP = "ros2cpp";
private DistributedTargetGeneratorCli() {}
......@@ -81,6 +85,8 @@ public final class DistributedTargetGeneratorCli {
res.add(GENERATOR_EMADL);
res.add(GENERATOR_ROSCPP);
res.add(GENERATOR_ODV);
res.add(GENERATOR_ROS2CPP);
res.add(GENERATOR_RCLCPP);
return res;
}
......@@ -91,7 +97,8 @@ public final class DistributedTargetGeneratorCli {
}
String fullModelsDirPath = expandHomeDir(cliParameters.getModelsDir());
if(cliParameters.getGenerators().size() == 0){
Set<String> generators = cliParameters.getGenerators();
if(generators.size() == 0){
Log.error("0x6178E: No generator was specified!");
return;
}
......@@ -102,7 +109,7 @@ public final class DistributedTargetGeneratorCli {
}
TaggingResolver taggingResolver;
if (cliParameters.getGenerators().contains(GENERATOR_EMADL)) {
if (generators.contains(GENERATOR_EMADL)) {
taggingResolver = EMADLAbstractSymtab.createSymTabAndTaggingResolver(fullModelsDirPath);
}
else{
......@@ -115,9 +122,13 @@ public final class DistributedTargetGeneratorCli {
Set<String> validGenNames = getGeneratorNames();
cliParameters.getGenerators().forEach(genName -> {
generators.forEach(genName -> {
if (validGenNames.contains(genName)) {
Log.warn("Using generator " + genName);
if(genName.equals(GENERATOR_ROS2CPP)) {
Log.warn("Using generator " + GENERATOR_RCLCPP + " since " + genName + " is an alias!");
}else {
Log.warn("Using generator " + genName);
}
} else {
Log.error("0xE28B6: Not a valid generator Name:" + genName +".");
return;
......@@ -127,15 +138,21 @@ public final class DistributedTargetGeneratorCli {
EMAComponentInstanceSymbol componentInstanceSymbol = taggingResolver.<EMAComponentInstanceSymbol>resolve(cliParameters.getRootModel(), EMAComponentInstanceSymbol.KIND).orElse(null);
if (componentInstanceSymbol == null) {
String[] parts = cliParameters.getRootModel().split("\\.");
String componentInstanceName = parts[parts.length - 1];
if(Character.isUpperCase(componentInstanceName.charAt(0))){
parts[parts.length - 1] = componentInstanceName.substring(0,1).toLowerCase() + componentInstanceName.substring(1);
Log.warn("The given ComponentInstance name " + componentInstanceName + " starts with an upper case letter(Invalid). Did you mean " + String.join(".", parts) + "?");
}
Log.error("0x5FFAE: The given component cannot be resolved.");
return;
}
if (cliParameters.getGenerators().contains(GENERATOR_CPP)) {
generator.add(new CPPGenImpl(), "cpp");
if (generators.contains(GENERATOR_CPP)) {
generator.add(new CPPGenImpl(cliParameters.getModelsDir()), "cpp");
}
if (cliParameters.getGenerators().contains(GENERATOR_EMADL)) {
if (generators.contains(GENERATOR_EMADL)) {
if(cliParameters.getEmadlBackend() != null && !cliParameters.getEmadlBackend().equals("")) {
generator.add(new EMADLGeneratorImpl(fullModelsDirPath, cliParameters.getEmadlBackend()), "cpp");
}else{
......@@ -144,13 +161,19 @@ public final class DistributedTargetGeneratorCli {
}
}
if (cliParameters.getGenerators().contains(GENERATOR_ROSCPP)) {
if (generators.contains(GENERATOR_ROSCPP)) {
generator.add(new RosCppGenImpl(), "roscpp");
RosToEmamTagSchema.registerTagTypes(taggingResolver);
TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
}
if (cliParameters.getGenerators().contains(GENERATOR_ODV)) {
if (generators.contains(GENERATOR_RCLCPP) || generators.contains(GENERATOR_ROS2CPP)) {
generator.add(new RclCppGenImpl(), "rclcpp");
RosToEmamTagSchema.registerTagTypes(taggingResolver);
TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
}
if (generators.contains(GENERATOR_ODV)) {
generator.add(new ODVGenImpl(), "odv");
}
......
package de.monticore.lang.monticar.generator.middleware.compile;
import de.monticore.lang.monticar.generator.middleware.helpers.TemplateHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BashCompilationGenerator extends CompilationGenerator {
private String PATH_TEMPLATE = "if [ -n \"$<new_exe>_HOME\" ]\n" +
"then\n"+
"\texport PATH=\"$<new_exe>_HOME:$PATH\"\n" +
"fi";
private String CHECK_EXE_TEMPLATE = "if [[ `command -v <exe>` ]]\n" +
"then\n" +
"\techo \"Found <exe>\"\n" +
"else\n" +
"\techo \"Can not find <exe> in PATH! Aborting.\"\n" +
"<additional_error>" +
"\texit 1\n" +
"fi";
private String SOURCE_ENV_VARS_TEMPLATE = "source <env_file>";
@Override
public boolean supportsRos() {
return true;
}
@Override
public boolean supportsRos2() {
return true;
}
@Override
protected String getPathTemplate() {
return PATH_TEMPLATE;
}
@Override
protected String getCheckExeTemplate() {
return CHECK_EXE_TEMPLATE;
}
@Override
protected String getSourceEnvVarsTemplate() {
return SOURCE_ENV_VARS_TEMPLATE;
}
@Override
protected String getScriptTemplate() {
return TemplateHelper.getCompilationBashTemplate().replace("\r\n", "\n");
}
@Override
protected List<String> getAdditionalPathDirs() {
setAdditionalErrorMsg("roscore", defaultErrorMsg("ROS"));
setAdditionalErrorMsg("ros2", defaultErrorMsg("ROS2"));
return Arrays.asList("cmake","make");
}
@Override
protected String getFileName() {
return "compile.sh";
}
@Override
protected String getNewlineDelimiter() {
return "\n";
}
@Override
protected List<String> getPostSourceExecutables() {
ArrayList<String> res = new ArrayList<>();
if(useRos()){
res.add("roscore");
}
if(useRos2()){
res.add("ros2");
}
return res;
}
@Override
protected List<String> getEnvironmentFiles() {
List<String> res = new ArrayList<>();
if(useRos()){
res.add("\"$ROS_HOME\"/setup.bash");
}
if(useRos2()){
res.add("\"$ROS2_HOME\"/setup.bash");
}
return res;
}
@Override
protected List<String> getExecutables() {
return Arrays.asList("cmake","make");
}
}
package de.monticore.lang.monticar.generator.middleware.compile;
import de.monticore.lang.monticar.generator.FileContent;
import java.util.*;
import java.util.stream.Collectors;
public abstract class CompilationGenerator {
private boolean useRos = false;
private boolean useRos2 = false;
private Map<String, String> additionalErrorMsg = new HashMap<>();
public abstract boolean supportsRos();
public abstract boolean supportsRos2();
public boolean isValid() {
return (supportsRos() || !useRos()) && (supportsRos2() || !useRos2());
}
protected void setAdditionalErrorMsg(String executable, String errorMsg) {
additionalErrorMsg.put(executable, errorMsg);
}
protected String getAdditionalErrorMsg(String executable) {
String s = additionalErrorMsg.getOrDefault(executable, defaultErrorMsg(executable));
return "\techo \"" + s + "\"" + getNewlineDelimiter();
}
protected abstract String getPathTemplate();
protected abstract String getCheckExeTemplate();
protected abstract String getSourceEnvVarsTemplate();
protected abstract String getScriptTemplate();
protected abstract List<String> getAdditionalPathDirs();
protected abstract String getFileName();
protected abstract String getNewlineDelimiter();
public boolean useRos() {
return useRos;
}
public void setUseRos(boolean useRos) {
this.useRos = useRos;
}
public boolean useRos2() {
return useRos2;
}
public void setUseRos2(boolean useRos2) {
this.useRos2 = useRos2;
}
protected String fillPathTemplate(String newExe) {
return getPathTemplate().replace("<new_exe>", newExe);
}
protected String fillCheckExeTemplate(String exe) {
return getCheckExeTemplate()
.replace("<exe>", exe)
.replace("<additional_error>", getAdditionalErrorMsg(exe));
}
protected String fillSourceEnvVarsTemplate(String envFile) {
return getSourceEnvVarsTemplate().replace("<env_file>", envFile);
}
protected String fillScriptTemplate(String additional_executables, String executable_checks, String additional_env, String post_executable_checks) {
return getScriptTemplate()
.replace("<additional_executables>", additional_executables)
.replace("<executable_checks>", executable_checks)
.replace("<additional_env>", additional_env)
.replace("<post_executable_checks>", post_executable_checks);
}
public List<FileContent> getCompilationScripts() {
FileContent res = new FileContent();
String additional_executables = getAdditionalPathDirs().stream()
.map(this::fillPathTemplate)
.collect(Collectors.joining(getNewlineDelimiter()));
String executable_checks = getExecutables().stream()
.map(this::fillCheckExeTemplate)
.collect(Collectors.joining(getNewlineDelimiter()));
String additional_env = getEnvironmentFiles().stream()
.map(this::fillSourceEnvVarsTemplate)
.collect(Collectors.joining(getNewlineDelimiter()));
String post_executable_checks = getPostSourceExecutables().stream()
.map(this::fillCheckExeTemplate)
.collect(Collectors.joining(getNewlineDelimiter()));
res.setFileName(getFileName());
res.setFileContent(fillScriptTemplate(additional_executables, executable_checks, additional_env, post_executable_checks));
return Arrays.asList(res);
}
protected abstract List<String> getPostSourceExecutables();
protected abstract List<String> getEnvironmentFiles();
protected abstract List<String> getExecutables();
public static List<CompilationGenerator> getInstanceOfAllGenerators() {
List<CompilationGenerator> res = new ArrayList<>();
res.add(new BashCompilationGenerator());
res.add(new MingwCompilationGenerator());
res.add(new MsbuildCompilationGenerator());
return res;