Skip to content

Commit

Permalink
Merge branch 'master' into transient-fed
Browse files Browse the repository at this point in the history
  • Loading branch information
ChadliaJerad committed Jun 21, 2024
2 parents 855fffa + 3a6cc1b commit e0b595e
Show file tree
Hide file tree
Showing 38 changed files with 789 additions and 344 deletions.
1 change: 1 addition & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies {
implementation "com.fasterxml.jackson.core:jackson-core:$fasterxmlVersion"
implementation "com.fasterxml.jackson.core:jackson-annotations:$fasterxmlVersion"
implementation "com.fasterxml.jackson.core:jackson-databind:$fasterxmlVersion"
implementation "org.apache.commons:commons-text:$commonsTextVersion"

implementation ("de.cau.cs.kieler.klighd:de.cau.cs.kieler.klighd.lsp:$klighdVersion") {
exclude group: 'org.eclipse.platform', module: 'org.eclipse.swt.*'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ protected boolean supportsEnclaves() {
return true;
}

@Override
protected boolean supportsDockerOption() {
return true;
}

@Test
@Override
public void runBasicTests() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
import org.lflang.generator.TargetTypes;
import org.lflang.generator.TimerInstance;
import org.lflang.generator.TriggerInstance;
import org.lflang.generator.docker.DockerGenerator;
import org.lflang.lf.AttrParm;
import org.lflang.lf.Attribute;
import org.lflang.lf.Connection;
Expand Down Expand Up @@ -1744,4 +1745,9 @@ public TargetTypes getTargetTypes() {
throw new UnsupportedOperationException(
"This method is not applicable for this generator since Uclid5 is not an LF target.");
}

@Override
protected DockerGenerator getDockerGenerator(LFGeneratorContext context) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,7 @@ private void buildUsingDocker(LFGeneratorContext context, List<SubContext> subCo
try {
var dockerGen = new FedDockerComposeGenerator(context, rtiConfig.getHost());
dockerGen.writeDockerComposeFile(createDockerFiles(context, subContexts));
if (dockerGen.build()) {
dockerGen.createLauncher();
} else {
context.getErrorReporter().nowhere().error("Docker build failed.");
}
dockerGen.buildIfRequested();
} catch (IOException e) {
context
.getErrorReporter()
Expand Down Expand Up @@ -279,6 +275,7 @@ private List<DockerData> createDockerFiles(
var dockerData = dockerGenerator.generateDockerData();
try {
dockerData.writeDockerFile();
dockerData.copyScripts(context);
} catch (IOException e) {
throw new RuntimeIOException(e);
}
Expand Down Expand Up @@ -366,9 +363,7 @@ time allowed for the test expires (currently two hours).
new TargetConfig(
subFileConfig.resource, GeneratorArguments.none(), subContextMessageReporter);

if (targetConfig.get(DockerProperty.INSTANCE).enabled()
&& targetConfig.target.buildsUsingDocker()
|| fed.isRemote) {
if (targetConfig.get(DockerProperty.INSTANCE).enabled() || fed.isRemote) {
NoCompileProperty.INSTANCE.override(subConfig, true);
}
// Disabled Docker for the federate and put federation in charge.
Expand Down
26 changes: 26 additions & 0 deletions core/src/main/java/org/lflang/generator/GeneratorBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
import org.lflang.analyses.uclid.UclidGenerator;
import org.lflang.ast.ASTUtils;
import org.lflang.ast.AstTransformation;
import org.lflang.generator.docker.DockerComposeGenerator;
import org.lflang.generator.docker.DockerGenerator;
import org.lflang.graph.InstantiationGraph;
import org.lflang.lf.Attribute;
import org.lflang.lf.Connection;
Expand Down Expand Up @@ -627,6 +629,30 @@ protected void cleanIfNeeded(LFGeneratorContext context) {
}
}

/** Return a {@code DockerGenerator} instance suitable for the target. */
protected abstract DockerGenerator getDockerGenerator(LFGeneratorContext context);

/** Create Dockerfiles and docker-compose.yml, build, and create a launcher. */
protected boolean buildUsingDocker() {
// Create docker file.
var dockerCompose = new DockerComposeGenerator(context);
var dockerData = getDockerGenerator(context).generateDockerData();
try {
dockerData.writeDockerFile();
dockerData.copyScripts(context);
dockerCompose.writeDockerComposeFile(List.of(dockerData));
} catch (IOException e) {
context
.getErrorReporter()
.nowhere()
.error(
"Error while writing Docker files: "
+ (e.getMessage() == null ? "No cause given" : e.getMessage()));
return false;
}
return dockerCompose.buildIfRequested();
}

/**
* Check if @property is used. If so, instantiate a UclidGenerator. The verification model needs
* to be generated before the target code since code generation changes LF program (desugar
Expand Down
23 changes: 1 addition & 22 deletions core/src/main/java/org/lflang/generator/c/CGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
import org.lflang.generator.TimerInstance;
import org.lflang.generator.TriggerInstance;
import org.lflang.generator.docker.CDockerGenerator;
import org.lflang.generator.docker.DockerComposeGenerator;
import org.lflang.generator.docker.DockerGenerator;
import org.lflang.generator.python.PythonGenerator;
import org.lflang.lf.Action;
Expand Down Expand Up @@ -577,27 +576,6 @@ public void doGenerate(Resource resource, LFGeneratorContext context) {
GeneratorUtils.refreshProject(resource, context.getMode());
}

/** Create Dockerfiles and docker-compose.yml, build, and create a launcher. */
private boolean buildUsingDocker() {
// Create docker file.
var dockerCompose = new DockerComposeGenerator(context);
var dockerData = getDockerGenerator(context).generateDockerData();
try {
dockerData.writeDockerFile();
dockerCompose.writeDockerComposeFile(List.of(dockerData));
} catch (IOException e) {
throw new RuntimeException("Error while writing Docker files", e);
}
var success = dockerCompose.build();
if (!success) {
messageReporter.nowhere().error("Docker-compose build failed.");
}
if (success && mainDef != null) {
dockerCompose.createLauncher();
}
return success;
}

private void generateCodeFor(String lfModuleName) throws IOException {
code.pr(generateDirectives());
code.pr(new CMainFunctionGenerator(targetConfig).generateCode());
Expand Down Expand Up @@ -1966,6 +1944,7 @@ public TargetTypes getTargetTypes() {
* @param context
* @return
*/
@Override
protected DockerGenerator getDockerGenerator(LFGeneratorContext context) {
return new CDockerGenerator(context);
}
Expand Down
104 changes: 37 additions & 67 deletions core/src/main/java/org/lflang/generator/docker/CDockerGenerator.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package org.lflang.generator.docker;

import org.eclipse.xtext.xbase.lib.IterableExtensions;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import org.lflang.generator.LFGeneratorContext;
import org.lflang.generator.c.CCompiler;
import org.lflang.generator.c.CFileConfig;
import org.lflang.target.Target;
import org.lflang.target.property.BuildCommandsProperty;
import org.lflang.util.StringUtil;

/**
* Generate the docker file related code for the C and CCpp target.
*
* @author Hou Seng Wong
* @author Marten Lohstroh
*/
public class CDockerGenerator extends DockerGenerator {

Expand All @@ -30,79 +32,47 @@ public String defaultImage() {
return DEFAULT_BASE_IMAGE;
}

/** Generate the contents of the docker file. */
@Override
protected String generateDockerFileContent() {
var lfModuleName = context.getFileConfig().name;
var config = context.getTargetConfig();
var compileCommand =
IterableExtensions.isNullOrEmpty(config.get(BuildCommandsProperty.INSTANCE))
? generateCompileCommand()
: StringUtil.joinObjects(config.get(BuildCommandsProperty.INSTANCE), " ");
var baseImage = baseImage();
return String.join(
"\n",
"# For instructions, see: https://www.lf-lang.org/docs/handbook/containerized-execution",
"FROM " + baseImage + " AS builder",
"WORKDIR /lingua-franca/" + lfModuleName,
generateRunForBuildDependencies(),
"COPY . src-gen",
compileCommand,
"",
"FROM " + baseImage,
"WORKDIR /lingua-franca",
"RUN mkdir bin",
"COPY --from=builder /lingua-franca/"
+ lfModuleName
+ "/bin/"
+ lfModuleName
+ " ./bin/"
+ lfModuleName,
"",
"# Use ENTRYPOINT not CMD so that command-line arguments go through",
"ENTRYPOINT [\"./bin/" + lfModuleName + "\"]",
"");
public List<String> defaultEntryPoint() {
return List.of("./bin/" + context.getFileConfig().name);
}

@Override
protected String generateRunForBuildDependencies() {
protected String generateRunForInstallingDeps() {
var config = context.getTargetConfig();
var compiler = config.target == Target.CCPP ? "g++" : "gcc";
if (baseImage().equals(defaultImage())) {
return """
# Install build dependencies
RUN set -ex && apk add --no-cache %s musl-dev cmake make
# Optional user specified run command
%s
"""
.formatted(compiler, userRunCommand());
if (builderBase().equals(defaultImage())) {
return "RUN set -ex && apk add --no-cache %s musl-dev cmake make".formatted(compiler);
} else {
return """
# Optional user specified run command
%s
# Check for build dependencies
RUN which make && which cmake && which %s
"""
.formatted(userRunCommand(), compiler);
return "# (Skipping installation of build dependencies; custom base image.)";
}
}

/** Return the default compile command for the C docker container. */
protected String generateCompileCommand() {
var ccompile =
new CCompiler(
context.getTargetConfig(),
context.getFileConfig(),
context.getErrorReporter(),
context.getTargetConfig().target == Target.C);
return String.join(
"\n",
"RUN set -ex && \\",
"mkdir bin && \\",
String.format(
"%s -DCMAKE_INSTALL_BINDIR=./bin -S src-gen -B bin && \\",
ccompile.compileCmakeCommand()),
"cd bin && \\",
"make all");
@Override
protected List<String> defaultBuildCommands() {
try {
var ccompile =
new CCompiler(
context.getTargetConfig(),
new CFileConfig(
context.getFileConfig().resource,
Path.of("/lingua-franca", context.getFileConfig().name),
false),
context.getErrorReporter(),
context.getTargetConfig().target == Target.CCPP);
return List.of(
"mkdir -p bin",
String.format(
"%s -DCMAKE_INSTALL_BINDIR=./bin -S src-gen -B bin", ccompile.compileCmakeCommand()),
"cd bin",
"make all",
"cd ..");
} catch (IOException e) {
context
.getErrorReporter()
.nowhere()
.error("Unable to create file configuration for Docker container");
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.Objects;
import java.util.stream.Collectors;
import org.lflang.generator.LFGeneratorContext;
import org.lflang.target.property.DockerProperty;
import org.lflang.util.FileUtil;
import org.lflang.util.LFCommand;

Expand Down Expand Up @@ -46,7 +47,6 @@ protected String generateDockerNetwork(String networkName) {
*/
protected String generateDockerServices(List<DockerData> services) {
return """
version: "3.9"
services:
%s
"""
Expand Down Expand Up @@ -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));
Expand All @@ -153,4 +156,19 @@ public void createLauncher() {
messageReporter.nowhere().warning("Unable to make launcher script executable.");
}
}

/**
* Build, unless building was disabled.
*
* @return {@code false} if building failed, {@code true} otherwise
*/
public boolean buildIfRequested() {
if (!context.getTargetConfig().get(DockerProperty.INSTANCE).noBuild()) {
if (build()) {
createLauncher();
} else context.getErrorReporter().nowhere().error("Docker build failed.");
return false;
}
return true;
}
}
25 changes: 25 additions & 0 deletions core/src/main/java/org/lflang/generator/docker/DockerData.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import org.lflang.FileConfig;
import org.lflang.generator.LFGeneratorContext;
import org.lflang.target.property.DockerProperty;
import org.lflang.util.FileUtil;

/**
Expand Down Expand Up @@ -44,4 +47,26 @@ public void writeDockerFile() throws IOException {
FileUtil.writeToFile(dockerFileContent, dockerFilePath);
context.getErrorReporter().nowhere().info("Dockerfile written to " + dockerFilePath);
}

/** Copy the pre-build, post-build, and pre-run scripts, if specified */
public void copyScripts(LFGeneratorContext context) throws IOException {
var prop = context.getTargetConfig().get(DockerProperty.INSTANCE);
copyScripts(
context.getFileConfig(),
List.of(prop.preBuildScript(), prop.postBuildScript(), prop.preRunScript()));
}

/** Copy the given list of scripts */
private void copyScripts(FileConfig fileConfig, List<String> scripts) throws IOException {
for (var script : scripts) {
if (!script.isEmpty()) {
var found = FileUtil.findInPackage(Path.of(script), fileConfig);
if (found != null) {
var destination = dockerFilePath.getParent().resolve(found.getFileName());
FileUtil.copyFile(found, destination);
this.context.getErrorReporter().nowhere().info("Script written to " + destination);
}
}
}
}
}
Loading

0 comments on commit e0b595e

Please sign in to comment.