diff --git a/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/GraalVMReachabilityMetadataRepository.java b/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/GraalVMReachabilityMetadataRepository.java index 692a2a2c8..e844102c1 100644 --- a/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/GraalVMReachabilityMetadataRepository.java +++ b/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/GraalVMReachabilityMetadataRepository.java @@ -55,6 +55,9 @@ * are missing. */ public interface GraalVMReachabilityMetadataRepository { + + String getMetadataSchemaVersion(); + /** * Performs a generic query on the repository, returning a list of * configuration directories. The query may be parameterized with diff --git a/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/internal/FileSystemRepository.java b/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/internal/FileSystemRepository.java index 85e8963af..741fb51b2 100644 --- a/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/internal/FileSystemRepository.java +++ b/common/graalvm-reachability-metadata/src/main/java/org/graalvm/reachability/internal/FileSystemRepository.java @@ -63,13 +63,14 @@ public class FileSystemRepository implements GraalVMReachabilityMetadataReposito private final Logger logger; private final Map artifactIndexes; private final Path rootDirectory; + private final String metadataSchemaVersion; public FileSystemRepository(Path rootDirectory) { this(rootDirectory, new Logger() {}); } public FileSystemRepository(Path rootDirectory, Logger logger) { - SchemaValidationUtils.validateSchemas(rootDirectory); + this.metadataSchemaVersion = SchemaValidationUtils.validateSchemas(rootDirectory); this.moduleIndex = new FileSystemModuleToConfigDirectoryIndex(rootDirectory); this.logger = logger; this.artifactIndexes = new ConcurrentHashMap<>(); @@ -139,6 +140,10 @@ public Path getRootDirectory() { return rootDirectory; } + public String getMetadataSchemaVersion() { + return metadataSchemaVersion; + } + /** * Allows getting insights about how configuration is picked. */ diff --git a/common/utils/src/main/java/org/graalvm/buildtools/utils/SchemaValidationUtils.java b/common/utils/src/main/java/org/graalvm/buildtools/utils/SchemaValidationUtils.java index 691903b40..12ae025d3 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/utils/SchemaValidationUtils.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/utils/SchemaValidationUtils.java @@ -28,6 +28,7 @@ public final class SchemaValidationUtils { new RequiredSchema("library-and-framework-list-schema", 1), new RequiredSchema("metadata-library-index-schema", 2), }; + public static final String REACHABILITY_METADATA_SCHEMA_JSON_NAME = "reachability-metadata-schema.json"; /** * Represents a required schema by base name with an exact required major version. @@ -63,7 +64,7 @@ private static int safeParseInt(String s) { * * @param repoRoot the root path of the exploded repository */ - public static void validateSchemas(Path repoRoot) { + public static String validateSchemas(Path repoRoot) { Path schemasDir = repoRoot.resolve("schemas"); if (!Files.isDirectory(schemasDir)) { @@ -75,13 +76,31 @@ public static void validateSchemas(Path repoRoot) { } int totalFilesFound = 0; + // Will try to extract the version from the descriptor file if present + String repositorySchemaVersion = null; List missing = new ArrayList<>(); List metadataTooOld = new ArrayList<>(); List toolsTooOld = new ArrayList<>(); String prefix = repoRoot.relativize(schemasDir).toString(); - try (DirectoryStream allFiles = Files.newDirectoryStream(schemasDir)) { - for (Path ignored : allFiles) { + for (Path entry : allFiles) { + String fileName = entry.getFileName().toString(); + if (REACHABILITY_METADATA_SCHEMA_JSON_NAME.equals(fileName)) { + // Do not count this descriptor file in the schema files total, + // but try to extract the repository schema version from it. + try { + String content = Files.readString(entry); + // Try common keys that may hold the version string + Pattern vpat = Pattern.compile("\"(?:schemaVersion|version)\"\\s*:\\s*\"(\\d+\\.\\d+\\.\\d+)\""); + Matcher vm = vpat.matcher(content); + if (vm.find()) { + repositorySchemaVersion = vm.group(1); + } + } catch (IOException ignored) { + // Best effort: ignore failures reading or parsing this optional descriptor + } + continue; + } totalFilesFound++; } } catch (IOException ignored) {} @@ -146,5 +165,6 @@ public static void validateSchemas(Path repoRoot) { + ". Please update your Native Build Tools to a newer version."; throw new IllegalStateException(message); } + return repositorySchemaVersion; } } diff --git a/native-maven-plugin/src/functionalTest/groovy/org/graalvm/buildtools/maven/SBOMFunctionalTest.groovy b/native-maven-plugin/src/functionalTest/groovy/org/graalvm/buildtools/maven/SBOMFunctionalTest.groovy index 7985df120..0ec1f90ad 100644 --- a/native-maven-plugin/src/functionalTest/groovy/org/graalvm/buildtools/maven/SBOMFunctionalTest.groovy +++ b/native-maven-plugin/src/functionalTest/groovy/org/graalvm/buildtools/maven/SBOMFunctionalTest.groovy @@ -95,8 +95,8 @@ class SBOMFunctionalTest extends AbstractGraalVMMavenFunctionalTest { } private static boolean supportsBaseSBOM() { - boolean isOracleGraalVM = NativeCompileNoForkMojo.isOracleGraalVM(null) - int version = NativeImageUtils.getMajorJDKVersion(NativeCompileNoForkMojo.getVersionInformation(null)) + boolean isOracleGraalVM = NativeCompileNoForkMojo.isOracleGraalVM(null, metadataRepository) + int version = NativeImageUtils.getMajorJDKVersion(NativeCompileNoForkMojo.getVersionInformation(null, metadataRepository)) return SBOMGenerator.isBaseSBOMSupported(isOracleGraalVM, version) } diff --git a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java index d11247151..18d4cb26e 100644 --- a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java +++ b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java @@ -56,6 +56,7 @@ import org.graalvm.buildtools.utils.NativeImageConfigurationUtils; import org.graalvm.buildtools.utils.NativeImageUtils; import org.graalvm.buildtools.utils.SharedConstants; +import org.graalvm.reachability.GraalVMReachabilityMetadataRepository; import javax.inject.Inject; import java.io.BufferedReader; @@ -502,7 +503,7 @@ protected String getClasspath() throws MojoExecutionException { } protected void buildImage() throws MojoExecutionException { - checkRequiredVersionIfNeeded(); + checkRequiredVersionIfNeeded(metadataRepository); Path nativeImageExecutable = NativeImageConfigurationUtils.getNativeImageSupportingToolchain(logger, toolchainManager, session, enforceToolchain); try { @@ -535,24 +536,26 @@ protected void buildImage() throws MojoExecutionException { } } - protected void checkRequiredVersionIfNeeded() throws MojoExecutionException { + protected void checkRequiredVersionIfNeeded(GraalVMReachabilityMetadataRepository metadataRepository) throws MojoExecutionException { if (requiredVersion == null) { return; } - NativeImageUtils.checkVersion(requiredVersion, getVersionInformation(logger)); + NativeImageUtils.checkVersion(requiredVersion, getVersionInformation(logger, metadataRepository)); } - protected static boolean isOracleGraalVM(Logger logger) throws MojoExecutionException { - return getVersionInformation(logger).contains(ORACLE_GRAALVM_IDENTIFIER); + protected static boolean isOracleGraalVM(Logger logger, GraalVMReachabilityMetadataRepository metadataRepository) throws MojoExecutionException { + return getVersionInformation(logger, metadataRepository).contains(ORACLE_GRAALVM_IDENTIFIER); } /** * Returns the output of calling "native-image --version". - * @param logger a logger, that may be null, to print warnings or useful information. + * + * @param logger a logger, that may be null, to print warnings or useful information. + * @param metadataRepository path to the metadata repo for reachability-metadata schema crosschecking. * @return the output as a string joined by "\n". * @throws MojoExecutionException when any errors occurred. */ - protected static String getVersionInformation(Logger logger) throws MojoExecutionException { + protected static String getVersionInformation(Logger logger, GraalVMReachabilityMetadataRepository metadataRepository) throws MojoExecutionException { if (nativeImageVersionInformation != null) { return nativeImageVersionInformation; } @@ -571,6 +574,9 @@ protected static String getVersionInformation(Logger logger) throws MojoExecutio new InputStreamReader(inputStream, StandardCharsets.UTF_8)) .lines() .collect(Collectors.joining("\n")); + + if (metadataRepository.getMetadataSchemaVersion() == null ) + return nativeImageVersionInformation; } catch (IOException | InterruptedException e) { throw new MojoExecutionException("Checking GraalVM version with " + nativeImageExecutable + " failed", e); diff --git a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeCompileNoForkMojo.java b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeCompileNoForkMojo.java index a9baff345..60b39eb23 100644 --- a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeCompileNoForkMojo.java +++ b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeCompileNoForkMojo.java @@ -156,7 +156,7 @@ private void generateBaseSBOMIfNeeded() throws MojoExecutionException { } var sbomGenerator = new SBOMGenerator(mavenProject, mavenSession, pluginManager, repositorySystem, mainClass); - var config = new SBOMGenerator.Config(isOracleGraalVM(logger), getBuildArgs(), NativeImageUtils.getMajorJDKVersion(getVersionInformation(logger))); + var config = new SBOMGenerator.Config(isOracleGraalVM(logger, metadataRepository), getBuildArgs(), NativeImageUtils.getMajorJDKVersion(getVersionInformation(logger, metadataRepository))); try { sbomGenerator.generateIfSupportedAndEnabled(config); } catch (Throwable e) {