Skip to content

Commit

Permalink
Dump all Quarkus app dependencies along with their checksums as part …
Browse files Browse the repository at this point in the history
…of track-config-changes goal
  • Loading branch information
aloubyansky committed Dec 6, 2023
1 parent a2731f4 commit 4f55cee
Showing 1 changed file with 83 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package io.quarkus.maven;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.zip.Adler32;
import java.util.zip.Checksum;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
Expand All @@ -18,6 +26,7 @@
import io.quarkus.bootstrap.app.CuratedApplication;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.maven.dependency.DependencyFlags;
import io.quarkus.runtime.LaunchMode;

/**
Expand Down Expand Up @@ -58,6 +67,18 @@ public class TrackConfigChangesMojo extends QuarkusBootstrapMojo {
@Parameter(defaultValue = "false", property = "quarkus.track-config-changes.dump-current-when-recorded-unavailable")
boolean dumpCurrentWhenRecordedUnavailable;

/**
* Whether to dump Quarkus application dependencies along with their checksums
*/
@Parameter(defaultValue = "true", property = "quarkus.track-config-changes.dump-dependencies")
boolean dumpDependencies;

/**
* Dependency dump file
*/
@Parameter(property = "quarkus.track-config-changes.dependenciesFile", defaultValue = "quarkus-app-deps.txt")
String dependenciesFile;

@Override
protected boolean beforeExecute() throws MojoExecutionException, MojoFailureException {
if (skip) {
Expand Down Expand Up @@ -103,33 +124,53 @@ protected void doExecute() throws MojoExecutionException, MojoFailureException {
}

final Properties compareProps = new Properties();
if (Files.exists(compareFile)) {
boolean prevConfigExists = Files.exists(compareFile);
if (prevConfigExists) {
try (BufferedReader reader = Files.newBufferedReader(compareFile)) {
compareProps.load(reader);
} catch (IOException e) {
throw new RuntimeException("Failed to read " + compareFile, e);
}
} else if (!dumpCurrentWhenRecordedUnavailable) {
} else if (!dumpCurrentWhenRecordedUnavailable && !dumpDependencies) {
getLog().info(compareFile + " not found");
return;
}

CuratedApplication curatedApplication = null;
QuarkusClassLoader deploymentClassLoader = null;
final ClassLoader originalCl = Thread.currentThread().getContextClassLoader();
Properties actualProps;
final boolean clearPackageTypeSystemProperty = setPackageTypeSystemPropertyIfNativeProfileEnabled();
try {
curatedApplication = bootstrapApplication(launchMode);
deploymentClassLoader = curatedApplication.createDeploymentClassLoader();
Thread.currentThread().setContextClassLoader(deploymentClassLoader);

final Class<?> codeGenerator = deploymentClassLoader.loadClass("io.quarkus.deployment.CodeGenerator");
final Method dumpConfig = codeGenerator.getMethod("dumpCurrentConfigValues", ApplicationModel.class, String.class,
Properties.class, QuarkusClassLoader.class, Properties.class, Path.class);
dumpConfig.invoke(null, curatedApplication.getApplicationModel(),
launchMode.name(), getBuildSystemProperties(true),
deploymentClassLoader, compareProps, targetFile);
if (prevConfigExists || dumpCurrentWhenRecordedUnavailable) {
deploymentClassLoader = curatedApplication.createDeploymentClassLoader();
Thread.currentThread().setContextClassLoader(deploymentClassLoader);

final Class<?> codeGenerator = deploymentClassLoader.loadClass("io.quarkus.deployment.CodeGenerator");
final Method dumpConfig = codeGenerator.getMethod("dumpCurrentConfigValues", ApplicationModel.class,
String.class,
Properties.class, QuarkusClassLoader.class, Properties.class, Path.class);
dumpConfig.invoke(null, curatedApplication.getApplicationModel(),
launchMode.name(), getBuildSystemProperties(true),
deploymentClassLoader, compareProps, targetFile);
}

if (dumpDependencies) {
var dependenciesFile = new File(outputDirectory, this.dependenciesFile);
dependenciesFile.getParentFile().mkdirs();
final List<String> deps = new ArrayList<>();
for (var d : curatedApplication.getApplicationModel().getDependencies(DependencyFlags.DEPLOYMENT_CP)) {
var adler32 = new Adler32();
updateChecksum(adler32, d.getResolvedPaths());
deps.add(d.toGACTVString() + " " + adler32.getValue());
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(dependenciesFile))) {
for (var s : deps) {
writer.write(s);
writer.newLine();
}
}
}
} catch (Exception any) {
throw new MojoExecutionException("Failed to bootstrap Quarkus application", any);
} finally {
Expand All @@ -142,4 +183,34 @@ protected void doExecute() throws MojoExecutionException, MojoFailureException {
}
}
}

private static void updateChecksum(Checksum checksum, Iterable<Path> pc) throws IOException {
for (var path : sort(pc)) {
if (Files.isDirectory(path)) {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
updateChecksum(checksum, stream);
}
} else {
checksum.update(Files.readAllBytes(path));
}
}
}

private static Iterable<Path> sort(Iterable<Path> original) {
var i = original.iterator();
if (!i.hasNext()) {
return List.of();
}
var o = i.next();
if (!i.hasNext()) {
return List.of(o);
}
final List<Path> sorted = new ArrayList<>();
sorted.add(o);
while (i.hasNext()) {
sorted.add(i.next());
}
Collections.sort(sorted);
return sorted;
}
}

0 comments on commit 4f55cee

Please sign in to comment.