diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java index 59e26fca69..80f13185ed 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java @@ -49,6 +49,11 @@ protected boolean supportsEnclaves() { return true; } + @Override + protected boolean supportsDockerOption() { + return true; + } + @Test @Override public void runBasicTests() { diff --git a/core/src/main/java/org/lflang/generator/docker/DockerComposeGenerator.java b/core/src/main/java/org/lflang/generator/docker/DockerComposeGenerator.java index 2255f3ce3b..d63a733740 100644 --- a/core/src/main/java/org/lflang/generator/docker/DockerComposeGenerator.java +++ b/core/src/main/java/org/lflang/generator/docker/DockerComposeGenerator.java @@ -128,16 +128,19 @@ public void createLauncher() { var binPath = fileConfig.binPath; FileUtil.createDirectoryIfDoesNotExist(binPath.toFile()); var file = binPath.resolve(fileConfig.name).toFile(); + + final var relPath = + FileUtil.toUnixString(fileConfig.binPath.relativize(fileConfig.getOutPath())); + var script = """ #!/bin/bash set -euo pipefail cd $(dirname "$0") - cd .. - cd "%s" + cd "%s/%s" docker compose up """ - .formatted(packageRoot.relativize(srcGenPath)); + .formatted(relPath, packageRoot.relativize(srcGenPath)); var messageReporter = context.getErrorReporter(); try { var writer = new BufferedWriter(new FileWriter(file)); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 799d0125c2..83223c93ea 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -11,6 +11,7 @@ import org.lflang.target.property.NoRuntimeValidationProperty import org.lflang.target.property.PrintStatisticsProperty import org.lflang.target.property.TracingProperty import org.lflang.toDefinition +import org.lflang.toUnixString import java.nio.file.Path /** Abstract class for generating platform specific files and invoking the target compiler. */ @@ -24,6 +25,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { protected val mainReactor = generator.mainDef.reactorClass.toDefinition() open val srcGenPath: Path = generator.fileConfig.srcGenPath + protected val relativeBinDir = fileConfig.outPath.relativize(fileConfig.binPath).toUnixString() abstract fun generatePlatformFiles() diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt index 4be02961ef..7ff170c3de 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt @@ -39,7 +39,7 @@ class CppRos2Generator(generator: CppGenerator) : CppPlatformGenerator(generator ) val scriptPath = if (targetConfig.get(DockerProperty.INSTANCE).enabled) - fileConfig.srcGenPath.resolve("bin").resolve(fileConfig.name) + fileConfig.srcGenPath.resolve(relativeBinDir).resolve(fileConfig.name) else fileConfig.binPath.resolve(fileConfig.name) FileUtil.writeToFile(packageGenerator.generateBinScript(), scriptPath) @@ -58,7 +58,8 @@ class CppRos2Generator(generator: CppGenerator) : CppPlatformGenerator(generator return false } val colconCommand = commandFactory.createCommand( - "colcon", colconArgs(), fileConfig.outPath) + "colcon", colconArgs(), fileConfig.outPath + ) val returnCode = colconCommand?.run(context.cancelIndicator) if (returnCode != 0 && !messageReporter.errorsOccurred) { // If errors occurred but none were reported, then the following message is the best we can do. @@ -70,13 +71,13 @@ class CppRos2Generator(generator: CppGenerator) : CppPlatformGenerator(generator private fun colconArgs(): List { return listOf( - "build", - "--packages-select", - fileConfig.name, - packageGenerator.reactorCppName, - "--cmake-args", - "-DLF_REACTOR_CPP_SUFFIX=${packageGenerator.reactorCppSuffix}", - ) + cmakeArgs + "build", + "--packages-select", + fileConfig.name, + packageGenerator.reactorCppName, + "--cmake-args", + "-DLF_REACTOR_CPP_SUFFIX=${packageGenerator.reactorCppSuffix}", + ) + cmakeArgs } inner class CppDockerGenerator(context: LFGeneratorContext?) : DockerGenerator(context) { @@ -90,13 +91,16 @@ class CppRos2Generator(generator: CppGenerator) : CppPlatformGenerator(generator override fun generateRunForInstallingDeps(): String = "" - override fun defaultEntryPoint(): List = listOf(fileConfig.outPath.relativize(fileConfig.binPath).toUnixString() + "/" + fileConfig.name) + override fun defaultEntryPoint(): List = + listOf("$relativeBinDir/${fileConfig.name}") - override fun generateCopyOfExecutable(): String = - """ - ${super.generateCopyOfExecutable()} + override fun generateCopyOfExecutable(): String { + val name = fileConfig.name + return """ + COPY --from=builder /lingua-franca/$name/$relativeBinDir/$name ./$relativeBinDir/$name COPY --from=builder lingua-franca/${fileConfig.name}/install install """.trimIndent() + } override fun defaultBuildCommands(): List { val commands = listOf( diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index 64fdf32ee0..d245285035 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -176,9 +176,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : "cmake", cmakeArgs + additionalCmakeArgs + listOf( "-DCMAKE_INSTALL_PREFIX=${outPath.toUnixString()}", - "-DCMAKE_INSTALL_BINDIR=${ - if (outPath.isAbsolute) outPath.relativize(fileConfig.binPath).toUnixString() else fileConfig.binPath.fileName.toString() - }", + "-DCMAKE_INSTALL_BINDIR=$relativeBinDir", "-S", sourcesRoot ?: fileConfig.srcGenBasePath.toUnixString(), "-B", @@ -194,6 +192,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : return cmd } + inner class StandaloneDockerGenerator(context: LFGeneratorContext?) : DockerGenerator(context) { override fun generateCopyForSources(): String = "COPY src-gen src-gen" @@ -210,15 +209,17 @@ class CppStandaloneGenerator(generator: CppGenerator) : } } - override fun defaultEntryPoint(): List = listOf("./bin/" + context.fileConfig.name) + override fun defaultEntryPoint(): List = listOf("$relativeBinDir/${fileConfig.name}") - override fun generateCopyOfExecutable(): String = - """ - ${super.generateCopyOfExecutable()} + override fun generateCopyOfExecutable(): String { + val name = fileConfig.name + return """ + COPY --from=builder /lingua-franca/$name/$relativeBinDir/$name ./$relativeBinDir/$name COPY --from=builder /usr/local/lib /usr/local/lib COPY --from=builder /usr/lib /usr/lib COPY --from=builder /lingua-franca . """.trimIndent() + } override fun defaultBuildCommands(): List { val mkdirCommand = listOf("mkdir", "-p", "build") diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSFileConfig.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSFileConfig.kt index 2503d94629..e04040f9b3 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSFileConfig.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSFileConfig.kt @@ -53,21 +53,4 @@ class TSFileConfig( super.doClean() FileUtil.deleteDirectory(srcGenPath) } - - override fun getCommand(): LFCommand { - return LFCommand.get( - "node", - listOf(srcPkgPath.relativize(executable).toString()), - true, - srcPkgPath - ) - } - - override fun getExecutableExtension(): String { - return ".js" - } - - override fun getExecutable(): Path { - return srcGenPath.resolve("dist").resolve(name + executableExtension) - } } diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 89ff40e517..fe724cad9c 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -6,8 +6,6 @@ import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Provider; -import java.io.BufferedWriter; -import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; @@ -15,7 +13,6 @@ import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; @@ -53,7 +50,6 @@ import org.lflang.tests.LFTest.Result; import org.lflang.tests.TestRegistry.TestCategory; import org.lflang.tests.Transformers.Transformer; -import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; /** @@ -568,104 +564,17 @@ public static String stackTraceToString(Throwable t) { return sw.toString(); } - /** Bash script that is used to execute docker tests. */ - private static final String DOCKER_RUN_SCRIPT = - """ - #!/bin/bash - - # exit when any command fails - set -e - - docker compose -f "$1" rm -f - docker compose -f "$1" up --build | tee docker_log.txt - docker compose -f "$1" down --rmi local - - errors=`grep -E "exited with code [1-9]" docker_log.txt | cat` - rm docker_log.txt - - if [[ $errors ]]; then - echo "====================================================================" - echo "ERROR: One or multiple containers exited with a non-zero exit code." - echo " See the log above for details. The following containers failed:" - echo $errors - exit 1 - fi - - exit 0 - """; - - /** Path to a bash script containing DOCKER_RUN_SCRIPT. */ - private static Path dockerRunScript = null; - - /** - * Return the path to a bash script containing DOCKER_RUN_SCRIPT. - * - *

If the script does not yet exist, it is created. - */ - private static synchronized Path getDockerRunScript() throws TestError { - if (dockerRunScript != null) { - return dockerRunScript; - } - - try { - var file = File.createTempFile("run_docker_test", "sh"); - file.deleteOnExit(); - file.setExecutable(true); - var path = file.toPath(); - try (BufferedWriter writer = Files.newBufferedWriter(path)) { - writer.write(DOCKER_RUN_SCRIPT); - } - dockerRunScript = path; - } catch (IOException e) { - throw new TestError("IO Error during test preparation.", Result.TEST_EXCEPTION, e); - } - - return dockerRunScript; - } - - /** Throws TestError if docker does not exist. Does nothing otherwise. */ - private void checkDockerExists() throws TestError { - if (LFCommand.get("docker", List.of()) == null) { - throw new TestError("Executable 'docker' not found", Result.NO_EXEC_FAIL); - } - if (LFCommand.get("docker-compose", List.of()) == null) { - throw new TestError("Executable 'docker-compose' not found", Result.NO_EXEC_FAIL); - } - } - - /** - * Return a ProcessBuilder used to test the docker execution. - * - * @param test The test to get the execution command for. - */ - private ProcessBuilder getDockerExecCommand(LFTest test) throws TestError { - checkDockerExists(); - var srcGenPath = test.getFileConfig().getSrcGenPath(); - var dockerComposeFile = FileUtil.globFilesEndsWith(srcGenPath, "docker-compose.yml").get(0); - return new ProcessBuilder(getDockerRunScript().toString(), dockerComposeFile.toString()); - } - /** * Return a preconfigured ProcessBuilder for executing the test program. * * @param test The test to get the execution command for. */ private ProcessBuilder getExecCommand(LFTest test) throws TestError { - - var srcBasePath = test.getFileConfig().srcPkgPath.resolve("src"); - var relativePathName = srcBasePath.relativize(test.getFileConfig().srcPath).toString(); - - // special case to test docker file generation - if (relativePathName.equalsIgnoreCase(TestCategory.DOCKER.getPath()) - || relativePathName.equalsIgnoreCase(TestCategory.DOCKER_FEDERATED.getPath())) { - return getDockerExecCommand(test); - } else { - LFCommand command = test.getFileConfig().getCommand(); - if (command == null) { - throw new TestError("File: " + test.getFileConfig().getExecutable(), Result.NO_EXEC_FAIL); - } - return new ProcessBuilder(command.command()).directory(command.directory()); + LFCommand command = test.getFileConfig().getCommand(); + if (command == null) { + throw new TestError("File: " + test.getFileConfig().getExecutable(), Result.NO_EXEC_FAIL); } + return new ProcessBuilder(command.command()).directory(command.directory()); } /**