-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce a new extension for generating Dockerfiles #42316
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<parent> | ||
<artifactId>quarkus-dockerfiles-parent</artifactId> | ||
<groupId>io.quarkus</groupId> | ||
<version>999-SNAPSHOT</version> | ||
<relativePath>../pom.xml</relativePath> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>quarkus-dockerfiles-cli</artifactId> | ||
<name>Quarkus - Dockerfiles - CLI</name> | ||
<description>CLI plugin that provides commands for Dockerfile genration</description> | ||
|
||
<properties> | ||
<quarkus.package.jar.type>uber-jar</quarkus.package.jar.type> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-picocli</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-arc</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-devtools-common</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-bootstrap-maven-resolver</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-dockerfiles-spi</artifactId> | ||
</dependency> | ||
|
||
<!-- This dependency is here to make sure the build order is correct--> | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-picocli-deployment</artifactId> | ||
<type>pom</type> | ||
<scope>test</scope> | ||
<version>${project.version}</version> | ||
<exclusions> | ||
<exclusion> | ||
<groupId>*</groupId> | ||
<artifactId>*</artifactId> | ||
</exclusion> | ||
</exclusions> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.assertj</groupId> | ||
<artifactId>assertj-core</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<resources> | ||
<resource> | ||
<directory>src/main/resources</directory> | ||
<filtering>true</filtering> | ||
</resource> | ||
</resources> | ||
<plugins> | ||
<plugin> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-maven-plugin</artifactId> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my case it was a problem to have CLI be a quarkus app. Check you can build from scratch. |
||
<executions> | ||
<execution> | ||
<goals> | ||
<goal>build</goal> | ||
<goal>generate-code</goal> | ||
<goal>generate-code-tests</goal> | ||
</goals> | ||
<configuration> | ||
<skipOriginalJarRename>true</skipOriginalJarRename> | ||
<environmentVariables> | ||
<MAVEN_REPO_LOCAL>${settings.localRepository}</MAVEN_REPO_LOCAL> | ||
<GRADLE_OPTS>${env.MAVEN_OPTS}</GRADLE_OPTS> | ||
</environmentVariables> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<configuration> | ||
<compilerArgs> | ||
<arg>-parameters</arg> | ||
</compilerArgs> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,154 @@ | ||||||
package io.quarkus.dockerfiles.cli; | ||||||
|
||||||
import java.io.IOException; | ||||||
import java.io.InputStream; | ||||||
import java.nio.file.Files; | ||||||
import java.nio.file.Path; | ||||||
import java.nio.file.Paths; | ||||||
import java.util.ArrayList; | ||||||
import java.util.List; | ||||||
import java.util.Optional; | ||||||
import java.util.concurrent.Callable; | ||||||
import java.util.function.Consumer; | ||||||
|
||||||
import io.quarkus.bootstrap.BootstrapException; | ||||||
import io.quarkus.bootstrap.app.AugmentAction; | ||||||
import io.quarkus.bootstrap.app.CuratedApplication; | ||||||
import io.quarkus.bootstrap.app.QuarkusBootstrap; | ||||||
import io.quarkus.devtools.project.BuildTool; | ||||||
import io.quarkus.devtools.project.QuarkusProjectHelper; | ||||||
import io.quarkus.dockerfiles.spi.GeneratedDockerfile; | ||||||
import io.quarkus.maven.dependency.ArtifactDependency; | ||||||
import io.quarkus.picocli.runtime.annotations.TopCommand; | ||||||
import picocli.CommandLine.Command; | ||||||
import picocli.CommandLine.ExitCode; | ||||||
import picocli.CommandLine.Option; | ||||||
import picocli.CommandLine.Parameters; | ||||||
|
||||||
@TopCommand | ||||||
@Command(name = "dockerfiles", sortOptions = false, mixinStandardHelpOptions = false, header = "Generate Dockerfiles.", headerHeading = "%n", commandListHeading = "%nCommands:%n", synopsisHeading = "%nUsage: ", optionListHeading = "%nOptions:%n") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
public class Dockerfiles implements Callable<Integer> { | ||||||
|
||||||
private static final ArtifactDependency QUARKUS_DOCKERFILES = new ArtifactDependency("io.quarkus", "quarkus-dockerfiles", | ||||||
null, "jar", Dockerfiles.getVersion()); | ||||||
private static final ArtifactDependency QUARKUS_DOCKERFILES_SPI = new ArtifactDependency("io.quarkus", | ||||||
"quarkus-dockerfiles-spi", null, "jar", Dockerfiles.getVersion()); | ||||||
|
||||||
@Option(names = { "--jvm" }, paramLabel = "", order = 5, description = "Flag to enable JVM Dockerfile generation") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it generate all the variants or a single one (in this case, which one?) |
||||||
boolean generateJvmDockerfile; | ||||||
|
||||||
@Option(names = { "--native" }, paramLabel = "", order = 5, description = "Flag to enable Native Dockerfile generation") | ||||||
boolean generateNativeDockerfile; | ||||||
|
||||||
@Parameters(arity = "0..1", paramLabel = "GENERATION_PATH", description = " The path to generate Dockerfiles") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
Optional<String> generationPath; | ||||||
|
||||||
public Integer call() { | ||||||
Path projectRoot = getWorkingDirectory(); | ||||||
BuildTool buildTool = QuarkusProjectHelper.detectExistingBuildTool(projectRoot); | ||||||
if (buildTool == null) { | ||||||
System.out.println("Unable to determine the build tool used for the project at " + projectRoot); | ||||||
return ExitCode.USAGE; | ||||||
} | ||||||
Path targetDirecotry = projectRoot.resolve(buildTool.getBuildDirectory()); | ||||||
QuarkusBootstrap quarkusBootstrap = QuarkusBootstrap.builder() | ||||||
.setMode(QuarkusBootstrap.Mode.PROD) | ||||||
.setApplicationRoot(getWorkingDirectory()) | ||||||
.setProjectRoot(getWorkingDirectory()) | ||||||
.setTargetDirectory(targetDirecotry) | ||||||
.setLocalProjectDiscovery(true) | ||||||
.setIsolateDeployment(false) | ||||||
.setForcedDependencies(List.of(QUARKUS_DOCKERFILES, QUARKUS_DOCKERFILES_SPI)) | ||||||
.setBaseClassLoader(ClassLoader.getSystemClassLoader()) | ||||||
.build(); | ||||||
|
||||||
List<String> resultBuildItemFQCNs = new ArrayList<>(); | ||||||
|
||||||
boolean hasJvmSuffix = generationPath.map(p -> p.endsWith(".jvm")).orElse(false); | ||||||
boolean hasNativeSuffix = generationPath.map(p -> p.endsWith(".native")).orElse(false); | ||||||
boolean isDirectory = generationPath.map(p -> Paths.get(p).toFile().isDirectory()) | ||||||
.orElse(Paths.get("").toFile().isDirectory()); | ||||||
|
||||||
// Checking | ||||||
if (generateJvmDockerfile && hasNativeSuffix) { | ||||||
System.out.println("Cannot generate JVM Dockerfile when the path has a .native suffix"); | ||||||
return ExitCode.USAGE; | ||||||
} | ||||||
if (generateNativeDockerfile && hasJvmSuffix) { | ||||||
System.out.println("Cannot generate Native Dockerfile when the path has a .jvm suffix"); | ||||||
return ExitCode.USAGE; | ||||||
} else if (generateJvmDockerfile && generateNativeDockerfile && !isDirectory) { | ||||||
|
||||||
} | ||||||
|
||||||
if (generateJvmDockerfile || hasJvmSuffix) { | ||||||
resultBuildItemFQCNs.add(GeneratedDockerfile.Jvm.class.getName()); | ||||||
} | ||||||
|
||||||
if (generateNativeDockerfile || hasNativeSuffix) { | ||||||
resultBuildItemFQCNs.add(GeneratedDockerfile.Native.class.getName()); | ||||||
} | ||||||
|
||||||
if (resultBuildItemFQCNs.isEmpty()) { | ||||||
generateJvmDockerfile = true; | ||||||
resultBuildItemFQCNs.add(GeneratedDockerfile.Jvm.class.getName()); | ||||||
} | ||||||
|
||||||
Path jvmDockerfile = (isDirectory | ||||||
? generationPath.map(p -> Paths.get(p)) | ||||||
: generationPath.map(Paths::get)) | ||||||
.orElse(Paths.get("Dockerfile.jvm")); | ||||||
|
||||||
Path nativeDockerfile = (isDirectory | ||||||
? generationPath.map(p -> Paths.get(p)) | ||||||
: generationPath.map(Paths::get)) | ||||||
.orElse(Paths.get("Dockerfile.native")); | ||||||
|
||||||
try (CuratedApplication curatedApplication = quarkusBootstrap.bootstrap()) { | ||||||
AugmentAction action = curatedApplication.createAugmentor(); | ||||||
|
||||||
action.performCustomBuild(GenerateDockerfilesHandler.class.getName(), new Consumer<List<GeneratedDockerfile>>() { | ||||||
@Override | ||||||
public void accept(List<GeneratedDockerfile> dockerfiles) { | ||||||
for (GeneratedDockerfile dockerfile : dockerfiles) { | ||||||
if (dockerfile instanceof GeneratedDockerfile.Jvm) { | ||||||
writeStringSafe(jvmDockerfile, dockerfile.getContent()); | ||||||
System.out.println("Generated JVM Dockerfile: " + jvmDockerfile); | ||||||
} else if (dockerfile instanceof GeneratedDockerfile.Native) { | ||||||
writeStringSafe(nativeDockerfile, dockerfile.getContent()); | ||||||
System.out.println("Generated Native Dockerfile: " + nativeDockerfile); | ||||||
} | ||||||
} | ||||||
} | ||||||
}, resultBuildItemFQCNs.toArray(new String[resultBuildItemFQCNs.size()])); | ||||||
|
||||||
} catch (BootstrapException e) { | ||||||
throw new RuntimeException(e); | ||||||
} | ||||||
return ExitCode.OK; | ||||||
} | ||||||
|
||||||
private void writeStringSafe(Path p, String content) { | ||||||
try { | ||||||
Files.writeString(p, content); | ||||||
} catch (IOException e) { | ||||||
throw new RuntimeException(e); | ||||||
} | ||||||
} | ||||||
|
||||||
private Path getWorkingDirectory() { | ||||||
return Paths.get(System.getProperty("user.dir")); | ||||||
} | ||||||
|
||||||
private static String getVersion() { | ||||||
return read(Dockerfiles.class.getClassLoader().getResourceAsStream("version")); | ||||||
} | ||||||
|
||||||
private static String read(InputStream is) { | ||||||
try { | ||||||
return new String(is.readAllBytes()); | ||||||
} catch (IOException e) { | ||||||
throw new RuntimeException(e); | ||||||
} | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this part of this PR?