Skip to content

Commit

Permalink
Support reading build-time config properties in code generation
Browse files Browse the repository at this point in the history
fixes #19389
  • Loading branch information
michalszynkiewicz committed Oct 18, 2021
1 parent 7da4fc3 commit 382d33b
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -1,37 +1,26 @@
package io.quarkus.deployment;

import java.nio.file.Path;
import java.util.Map;

import io.quarkus.bootstrap.model.AppModel;
import org.eclipse.microprofile.config.Config;

import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.util.BootstrapUtils;

public class CodeGenContext {
private final ApplicationModel model;
private final Path outDir;
private final Path workDir;
private final Path inputDir;
private final boolean redirectIO;
private final Map<String, String> properties;
private final Config config;

public CodeGenContext(ApplicationModel model, Path outDir, Path workDir, Path inputDir, boolean redirectIO,
Map<String, String> properties) {
public CodeGenContext(ApplicationModel model, Path outDir, Path workDir, Path inputDir, boolean redirectIO, Config config) {
this.model = model;
this.outDir = outDir;
this.workDir = workDir;
this.inputDir = inputDir;
this.redirectIO = redirectIO;
this.properties = properties;
}

/**
* @deprecated in favor of {@link #applicationModel()}
* @return
*/
@Deprecated
public AppModel appModel() {
return BootstrapUtils.convert(model);
this.config = config;
}

public ApplicationModel applicationModel() {
Expand All @@ -54,7 +43,7 @@ public boolean shouldRedirectIO() {
return redirectIO;
}

public Map<String, String> properties() {
return properties;
public Config config() {
return config;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,33 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.function.Consumer;

import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.model.PathsCollection;
import io.quarkus.bootstrap.prebuild.CodeGenException;
import io.quarkus.deployment.codegen.CodeGenData;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.ConfigUtils;
import io.smallrye.config.PropertiesConfigSource;
import io.smallrye.config.SmallRyeConfig;

/**
* A set of methods to initialize and execute {@link CodeGenProvider}s.
*/
public class CodeGenerator {

// used by Gradle
// used by Gradle and Maven
public static void initAndRun(ClassLoader classLoader,
PathsCollection sourceParentDirs, Path generatedSourcesDir, Path buildDir,
Consumer<Path> sourceRegistrar,
ApplicationModel appModel, Map<String, String> properties) throws CodeGenException {
Consumer<Path> sourceRegistrar, ApplicationModel appModel, Properties properties,
String launchMode) throws CodeGenException {
List<CodeGenData> generators = init(classLoader, sourceParentDirs, generatedSourcesDir, buildDir, sourceRegistrar);
for (CodeGenData generator : generators) {
generator.setRedirectIO(true);
trigger(classLoader, generator, appModel, properties);
trigger(classLoader, generator, appModel, properties, LaunchMode.valueOf(launchMode));
}
}

Expand Down Expand Up @@ -82,14 +86,21 @@ private static <T> T callWithClassloader(ClassLoader deploymentClassLoader, Code
public static boolean trigger(ClassLoader deploymentClassLoader,
CodeGenData data,
ApplicationModel appModel,
Map<String, String> properties) throws CodeGenException {
Properties properties,
LaunchMode launchMode) throws CodeGenException {
return callWithClassloader(deploymentClassLoader, () -> {
CodeGenProvider provider = data.provider;

final PropertiesConfigSource pcs = new PropertiesConfigSource(properties, "Build system");

final SmallRyeConfig config = ConfigUtils.configBuilder(false, launchMode)
.withProfile(launchMode.getDefaultProfile())
.withSources(pcs)
.build();

CodeGenProvider provider = data.provider;
return Files.isDirectory(data.sourceDir)
&& provider.trigger(
new CodeGenContext(appModel, data.outPath, data.buildDir, data.sourceDir, data.redirectIO,
properties));
new CodeGenContext(appModel, data.outPath, data.buildDir, data.sourceDir, data.redirectIO, config));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
Expand Down Expand Up @@ -59,6 +60,7 @@
import io.quarkus.dev.spi.HotReplacementSetup;
import io.quarkus.runner.bootstrap.AugmentActionImpl;
import io.quarkus.runtime.ApplicationLifecycleManager;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.QuarkusConfigFactory;
import io.quarkus.runtime.logging.LoggingSetupRecorder;

Expand Down Expand Up @@ -186,16 +188,18 @@ public void accept(String args) {
}

private void startCodeGenWatcher(QuarkusClassLoader classLoader, List<CodeGenData> codeGens,
Map<String, String> properties) {
Map<String, String> propertyMap) {

Collection<FSWatchUtil.Watcher> watchers = new ArrayList<>();
Properties properties = new Properties();
properties.putAll(propertyMap);
for (CodeGenData codeGen : codeGens) {
watchers.add(new FSWatchUtil.Watcher(codeGen.sourceDir, codeGen.provider.inputExtension(),
modifiedPaths -> {
try {
CodeGenerator.trigger(classLoader,
codeGen,
curatedApplication.getApplicationModel(), properties);
curatedApplication.getApplicationModel(), properties, LaunchMode.DEVELOPMENT);
} catch (Exception any) {
log.warn("Code generation failed", any);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public class QuarkusPlugin implements Plugin<Project> {
public static final String ADD_EXTENSION_TASK_NAME = "addExtension";
public static final String REMOVE_EXTENSION_TASK_NAME = "removeExtension";
public static final String QUARKUS_GENERATE_CODE_TASK_NAME = "quarkusGenerateCode";
public static final String QUARKUS_GENERATE_CODE_DEV_TASK_NAME = "quarkusGenerateCodeDev";
public static final String QUARKUS_GENERATE_CODE_TESTS_TASK_NAME = "quarkusGenerateCodeTests";
public static final String QUARKUS_BUILD_TASK_NAME = "quarkusBuild";
public static final String QUARKUS_DEV_TASK_NAME = "quarkusDev";
Expand Down Expand Up @@ -106,6 +107,9 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) {
tasks.create(REMOVE_EXTENSION_TASK_NAME, QuarkusRemoveExtension.class);

QuarkusGenerateCode quarkusGenerateCode = tasks.create(QUARKUS_GENERATE_CODE_TASK_NAME, QuarkusGenerateCode.class);
QuarkusGenerateCode quarkusGenerateCodeDev = tasks.create(QUARKUS_GENERATE_CODE_DEV_TASK_NAME,
QuarkusGenerateCode.class);
quarkusGenerateCodeDev.setDevMode(true);
QuarkusGenerateCode quarkusGenerateCodeTests = tasks.create(QUARKUS_GENERATE_CODE_TESTS_TASK_NAME,
QuarkusGenerateCode.class);
quarkusGenerateCodeTests.setTest(true);
Expand Down Expand Up @@ -148,8 +152,8 @@ public void execute(Task test) {
project.afterEvaluate(this::afterEvaluate);
ConfigurationContainer configurations = project.getConfigurations();
JavaCompile compileJavaTask = (JavaCompile) tasks.getByName(JavaPlugin.COMPILE_JAVA_TASK_NAME);

compileJavaTask.dependsOn(quarkusGenerateCode);
compileJavaTask.mustRunAfter(quarkusGenerateCodeDev);
compileJavaTask.mustRunAfter(quarkusGenerateCode);

JavaCompile compileTestJavaTask = (JavaCompile) tasks.getByName(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME);
compileTestJavaTask.dependsOn(quarkusGenerateCodeTests);
Expand All @@ -158,7 +162,12 @@ public void execute(Task test) {
Task resourcesTask = tasks.getByName(JavaPlugin.PROCESS_RESOURCES_TASK_NAME);
Task testClassesTask = tasks.getByName(JavaPlugin.TEST_CLASSES_TASK_NAME);
Task testResourcesTask = tasks.getByName(JavaPlugin.PROCESS_TEST_RESOURCES_TASK_NAME);
quarkusDev.dependsOn(classesTask, resourcesTask, testClassesTask, testResourcesTask, quarkusGenerateCode,

quarkusGenerateCode.dependsOn(resourcesTask);
quarkusGenerateCodeDev.dependsOn(resourcesTask);
quarkusGenerateCodeTests.dependsOn(resourcesTask);

quarkusDev.dependsOn(classesTask, resourcesTask, testClassesTask, testResourcesTask, quarkusGenerateCodeDev,
quarkusGenerateCodeTests);
quarkusRemoteDev.dependsOn(classesTask, resourcesTask);
quarkusTest.dependsOn(classesTask, resourcesTask, testClassesTask, testResourcesTask, quarkusGenerateCode,
Expand All @@ -172,6 +181,7 @@ public void execute(Task test) {
SourceSet testSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME);

quarkusGenerateCode.setSourcesDirectories(getSourcesParents(mainSourceSet));
quarkusGenerateCodeDev.setSourcesDirectories(getSourcesParents(mainSourceSet));
quarkusGenerateCodeTests.setSourcesDirectories(getSourcesParents(testSourceSet));

nativeTestSourceSet.setCompileClasspath(
Expand Down Expand Up @@ -224,7 +234,8 @@ public void execute(Task test) {

project.getPlugins().withId("org.jetbrains.kotlin.jvm", plugin -> {
quarkusDev.shouldPropagateJavaCompilerArgs(false);
tasks.getByName("compileKotlin").dependsOn(quarkusGenerateCode);
tasks.getByName("compileKotlin").mustRunAfter(quarkusGenerateCode);
tasks.getByName("compileKotlin").mustRunAfter(quarkusGenerateCodeDev);
tasks.getByName("compileTestKotlin").dependsOn(quarkusGenerateCodeTests);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class QuarkusGenerateCode extends QuarkusTask {
private Consumer<Path> sourceRegistrar = (p) -> {
};
private boolean test = false;
private boolean devMode = false;

public QuarkusGenerateCode() {
super("Performs Quarkus pre-build preparations, such as sources generation");
Expand Down Expand Up @@ -88,7 +89,8 @@ public File getGeneratedOutputDirectory() {
public void prepareQuarkus() {
getLogger().lifecycle("preparing quarkus application");

final ApplicationModel appModel = extension().getApplicationModel(test ? LaunchMode.TEST : LaunchMode.NORMAL);
LaunchMode launchMode = test ? LaunchMode.TEST : devMode ? LaunchMode.DEVELOPMENT : LaunchMode.NORMAL;
final ApplicationModel appModel = extension().getApplicationModel(launchMode);
final Properties realProperties = getBuildSystemProperties(appModel.getAppArtifact());

Path buildDir = getProject().getBuildDir().toPath();
Expand Down Expand Up @@ -124,7 +126,7 @@ public void prepareQuarkus() {
Optional<Method> initAndRun = Arrays.stream(codeGenerator.getMethods())
.filter(m -> m.getName().equals(INIT_AND_RUN))
.findAny();
if (!initAndRun.isPresent()) {
if (initAndRun.isEmpty()) {
throw new GradleException("Failed to find " + INIT_AND_RUN + " method in " + CodeGenerator.class.getName());
}

Expand All @@ -134,7 +136,8 @@ public void prepareQuarkus() {
buildDir,
sourceRegistrar,
appCreationContext.getApplicationModel(),
realProperties);
realProperties,
launchMode.name());

}
} catch (BootstrapException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
Expand All @@ -149,4 +152,8 @@ public void setSourcesDirectories(Set<Path> sourcesDirectories) {
public void setTest(boolean test) {
this.test = test;
}

public void setDevMode(boolean devMode) {
this.devMode = devMode;
}
}
29 changes: 18 additions & 11 deletions devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public class DevMojo extends AbstractMojo {
"install",
"deploy");
private static final String QUARKUS_GENERATE_CODE_GOAL = "generate-code";
private static final String QUARKUS_GENERATE_CODE_TESTS_GOAL = "generate-code-tests";

private static final String ORG_APACHE_MAVEN_PLUGINS = "org.apache.maven.plugins";
private static final String MAVEN_COMPILER_PLUGIN = "maven-compiler-plugin";
Expand Down Expand Up @@ -399,8 +400,8 @@ public void execute() throws MojoFailureException, MojoExecutionException {
getLog().info("Changes detected to " + changed + ", restarting dev mode");
final DevModeRunner newRunner;
try {
triggerCompile(false);
triggerCompile(true);
triggerCompile(false, true);
triggerCompile(true, true);
newRunner = new DevModeRunner();
} catch (Exception e) {
getLog().info("Could not load changed pom.xml file, changes not applied", e);
Expand Down Expand Up @@ -478,10 +479,14 @@ private void handleAutoCompile() throws MojoExecutionException {
boolean compileNeeded = true;
boolean testCompileNeeded = true;
boolean prepareNeeded = true;
boolean prepareTestsNeeded = true;
for (String goal : session.getGoals()) {
if (goal.endsWith("quarkus:prepare")) {
if (goal.endsWith("quarkus:generate-code")) {
prepareNeeded = false;
}
if (goal.endsWith("quarkus:generate-code-tests")) {
prepareTestsNeeded = false;
}

if (POST_COMPILE_PHASES.contains(goal)) {
compileNeeded = false;
Expand All @@ -498,14 +503,11 @@ private void handleAutoCompile() throws MojoExecutionException {

//if the user did not compile we run it for them
if (compileNeeded) {
if (prepareNeeded) {
triggerPrepare();
}
triggerCompile(false);
triggerCompile(false, prepareNeeded);
}
if (testCompileNeeded) {
try {
triggerCompile(true);
triggerCompile(true, prepareTestsNeeded);
} catch (Throwable t) {
getLog().error("Test compile failed, you will need to fix your tests before you can use continuous testing", t);
}
Expand All @@ -516,19 +518,24 @@ private void initToolchain() throws MojoExecutionException {
executeIfConfigured(ORG_APACHE_MAVEN_PLUGINS, MAVEN_TOOLCHAINS_PLUGIN, "toolchain", Collections.emptyMap());
}

private void triggerPrepare() throws MojoExecutionException {
private void triggerPrepare(boolean test) throws MojoExecutionException {
final PluginDescriptor pluginDescr = getPluginDescriptor();
executeIfConfigured(pluginDescr.getGroupId(), pluginDescr.getArtifactId(), QUARKUS_GENERATE_CODE_GOAL,
executeIfConfigured(pluginDescr.getGroupId(), pluginDescr.getArtifactId(),
test ? QUARKUS_GENERATE_CODE_TESTS_GOAL : QUARKUS_GENERATE_CODE_GOAL,
Collections.singletonMap("mode", LaunchMode.DEVELOPMENT.name()));
}

private PluginDescriptor getPluginDescriptor() {
return (PluginDescriptor) getPluginContext().get("pluginDescriptor");
}

private void triggerCompile(boolean test) throws MojoExecutionException {
private void triggerCompile(boolean test, boolean prepareNeeded) throws MojoExecutionException {
handleResources(test);

if (prepareNeeded) {
triggerPrepare(test);
}

// compile the Kotlin sources if needed
executeIfConfigured(ORG_JETBRAINS_KOTLIN, KOTLIN_MAVEN_PLUGIN, test ? "test-compile" : "compile",
Collections.emptyMap());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Properties;
import java.util.function.Consumer;

import org.apache.maven.plugin.MojoExecutionException;
Expand All @@ -19,7 +19,7 @@
import io.quarkus.bootstrap.model.PathsCollection;
import io.quarkus.runtime.LaunchMode;

@Mojo(name = "generate-code", defaultPhase = LifecyclePhase.GENERATE_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, threadSafe = true)
@Mojo(name = "generate-code", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, threadSafe = true)
public class GenerateCodeMojo extends QuarkusBootstrapMojo {

/**
Expand Down Expand Up @@ -72,14 +72,14 @@ void generateCode(Path sourcesDir,
final Method initAndRun = codeGenerator.getMethod("initAndRun", ClassLoader.class, PathsCollection.class,
Path.class,
Path.class,
Consumer.class, ApplicationModel.class, Map.class);
Consumer.class, ApplicationModel.class, Properties.class, String.class);
initAndRun.invoke(null, deploymentClassLoader,
PathsCollection.of(sourcesDir),
generatedSourcesDir(test),
buildDir().toPath(),
sourceRegistrar,
curatedApplication.getApplicationModel(),
mavenProject().getProperties());
mavenProject().getProperties(), launchMode.name());
} catch (Exception any) {
throw new MojoExecutionException("Quarkus code generation phase has failed", any);
} finally {
Expand Down
Loading

0 comments on commit 382d33b

Please sign in to comment.