Skip to content

Commit

Permalink
Embed quarkus version in native executable as a global string symbol
Browse files Browse the repository at this point in the history
Enables getting the quarkus version without running the native
executable:

```
❯ strings target/quarkus-999-SNAPSHOT-runner | grep -F '__quarkus_analytics__quarkus.version'
quarkus.version=999-SNAPSHOT
```

Closes quarkusio#43020
  • Loading branch information
zakkak committed Sep 10, 2024
1 parent b5a181e commit 65c7e68
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ public final class ReflectiveFieldBuildItem extends MultiBuildItem {
final String reason;

public ReflectiveFieldBuildItem(String reason, FieldInfo field) {
this.reason = reason;
this.name = field.name();
this.declaringClass = field.declaringClass().name().toString();
this(reason, field.declaringClass().name().toString(), field.name());
}

public ReflectiveFieldBuildItem(FieldInfo field) {
Expand All @@ -27,9 +25,13 @@ public ReflectiveFieldBuildItem(Field field) {
}

public ReflectiveFieldBuildItem(String reason, Field field) {
this(reason, field.getDeclaringClass().getName(), field.getName());
}

public ReflectiveFieldBuildItem(String reason, String declaringClass, String fieldName) {
this.reason = reason;
this.name = field.getName();
this.declaringClass = field.getDeclaringClass().getName();
this.name = fieldName;
this.declaringClass = declaringClass;
}

public String getDeclaringClass() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import io.quarkus.deployment.builditem.StaticBytecodeRecorderBuildItem;
import io.quarkus.deployment.builditem.SystemPropertyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveFieldBuildItem;
import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator;
import io.quarkus.deployment.naming.NamingConfig;
import io.quarkus.deployment.pkg.PackageConfig;
Expand Down Expand Up @@ -96,6 +97,9 @@ public class MainClassBuildStep {
static final String STARTUP_CONTEXT = "STARTUP_CONTEXT";
static final String LOG = "LOG";
static final String JAVA_LIBRARY_PATH = "java.library.path";
// This is declared as a constant so that it can be grepped for in the native-image binary using `strings`, e.g.:
// strings ./target/quarkus-runner | grep "__quarkus_analytics__quarkus.version="
public static final String QUARKUS_ANALYTICS_QUARKUS_VERSION = "__QUARKUS_ANALYTICS_QUARKUS_VERSION";

public static final String GENERATE_APP_CDS_SYSTEM_PROPERTY = "quarkus.appcds.generate";

Expand Down Expand Up @@ -155,6 +159,9 @@ void build(List<StaticBytecodeRecorderBuildItem> staticInitTasks,
FieldCreator scField = file.getFieldCreator(STARTUP_CONTEXT_FIELD);
scField.setModifiers(Modifier.PUBLIC | Modifier.STATIC);

FieldCreator quarkusVersionField = file.getFieldCreator(QUARKUS_ANALYTICS_QUARKUS_VERSION, String.class)
.setModifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL);

MethodCreator ctor = file.getMethodCreator("<init>", void.class);
ctor.invokeSpecialMethod(ofMethod(Application.class, "<init>", void.class, boolean.class),
ctor.getThis(), ctor.load(launchMode.isAuxiliaryApplication()));
Expand Down Expand Up @@ -192,6 +199,10 @@ void build(List<StaticBytecodeRecorderBuildItem> staticInitTasks,
mv.writeStaticField(logField.getFieldDescriptor(), mv.invokeStaticMethod(
ofMethod(Logger.class, "getLogger", Logger.class, String.class), mv.load("io.quarkus.application")));

// Init the __QUARKUS_ANALYTICS_QUARKUS_VERSION field
mv.writeStaticField(quarkusVersionField.getFieldDescriptor(),
mv.load("__quarkus_analytics__quarkus.version=" + Version.getVersion()));

ResultHandle startupContext = mv.newInstance(ofConstructor(StartupContext.class));
mv.writeStaticField(scField.getFieldDescriptor(), startupContext);
TryBlock tryBlock = mv.tryBlock();
Expand Down Expand Up @@ -703,4 +714,10 @@ private static Result invalid() {
}
}

@BuildStep
ReflectiveFieldBuildItem setupVersionField() {
return new ReflectiveFieldBuildItem(
"Ensure it's included in the executable to be able to grep the quarkus version",
Application.APP_CLASS_NAME, QUARKUS_ANALYTICS_QUARKUS_VERSION);
}
}

0 comments on commit 65c7e68

Please sign in to comment.