Skip to content

Commit f9c11bb

Browse files
committed
Include the reachability-metadata-schema with GraalVM
1 parent 1427c2c commit f9c11bb

File tree

10 files changed

+559
-23
lines changed

10 files changed

+559
-23
lines changed

docs/reference-manual/native-image/FFM-API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,4 +754,4 @@ This is also why the `native-image` tool currently disallows native `MemorySegme
754754
* [Interoperability with Native Code](InteropWithNativeCode.md)
755755
* [Collect Metadata with the Tracing Agent](AutomaticMetadataCollection.md)
756756
* [Reachability Metadata](ReachabilityMetadata.md)
757-
* [reachability-metadata-schema-v1.1.0.json](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reachability-metadata-schema-v1.1.0.json)
757+
* [reachability-metadata-schema-v1.2.0.json](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reachability-metadata-schema-v1.2.0.json)

docs/reference-manual/native-image/ReachabilityMetadata.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ Computing metadata in code can be achieved in two ways:
124124
## Specifying Metadata with JSON
125125
126126
All metadata specified in the _reachability-metadata.json_ file that is located in any of the classpath entries at _META-INF/native-image/\<group.Id>\/\<artifactId>\/_.
127-
The JSON schema for the reachability metadata is defined in [reachability-metadata-schema-v1.1.0.json](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reachability-metadata-schema-v1.1.0.json).
127+
The JSON schema for the reachability metadata is defined in [reachability-metadata-schema-v1.2.0.json](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reachability-metadata-schema-v1.2.0.json).
128128
129129
A sample _reachability-metadata.json_ file can be found [in the sample section](#sample-reachability-metadata).
130130
The _reachability-metadata.json_ configuration contains a single object with one field for each type of metadata. Each field in the top-level object contains an array of *metadata entries*:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../substratevm/schemas/reachability-metadata-schema-v1.2.0.json

sdk/mx.sdk/mx_sdk.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import datetime
5555
import shutil
5656
import tempfile
57+
from typing import Iterable, Tuple
5758
from mx_bisect import define_bisect_default_build_steps
5859
from mx_bisect_strategy import BuildStepsGraalVMStrategy
5960

@@ -262,6 +263,96 @@ def jlink_new_jdk(jdk, dst_jdk_dir, module_dists, ignore_dists,
262263
use_upgrade_module_path=use_upgrade_module_path,
263264
default_to_jvmci=default_to_jvmci)
264265

266+
267+
def create_jsonschema_validator(schema_path):
268+
"""Create and return a jsonschema Validator for the schema at the given file path. Abort on missing jsonschema or invalid schema."""
269+
import json
270+
try:
271+
with open(schema_path, "r", encoding="utf-8") as f:
272+
schema = json.load(f)
273+
except json.JSONDecodeError as e:
274+
mx.abort(f'Failed to parse JSON in schema file "{schema_path}" at line {e.lineno}, column {e.colno}: {e.msg}')
275+
except OSError as e:
276+
mx.abort(f'I/O error when opening schema file "{schema_path}": {e}')
277+
278+
try:
279+
import jsonschema # type: ignore
280+
except ImportError as e:
281+
mx.abort(
282+
'Python module "jsonschema" is required to validate reachability metadata but was not found. '
283+
'Install it with: \n\npython3 -m pip install --user jsonschema \n\n or \n\npip3 install jsonschema). '
284+
f'Original error: {e}')
285+
try:
286+
if hasattr(jsonschema, 'Draft202012Validator'):
287+
return jsonschema.Draft202012Validator(schema) # type: ignore[attr-defined]
288+
else:
289+
return jsonschema.Draft7Validator(schema) # type: ignore
290+
except (jsonschema.exceptions.SchemaError, TypeError) as e:
291+
mx.abort(f'Invalid reachability metadata schema: {e}')
292+
293+
294+
def validate_json_file_with_validator(validator, file_path):
295+
"""Validates a JSON file against the provided Validator. Returns a list of detailed error strings; empty if valid."""
296+
import json
297+
try:
298+
with open(file_path, 'r', encoding='utf-8') as f:
299+
data = json.load(f)
300+
except json.JSONDecodeError as e:
301+
mx.abort(f'Invalid JSON syntax at line {e.lineno}, column {e.colno}: {e.msg}')
302+
except OSError as e:
303+
mx.abort(f'I/O error: {e}')
304+
305+
# Use jsonschema's ValidationError string representation to produce messages in the form:
306+
# Failed validating '<validator>' in schema[...] :
307+
# { ... failing subschema ... }
308+
#
309+
# On instance[...] :
310+
# <offending instance>
311+
errors = []
312+
for err in validator.iter_errors(data):
313+
errors.append(str(err))
314+
return errors
315+
316+
317+
def validate_dir_files_with_file_schema_pairs(dir_with_json: str, json_and_schema_file_pairs: Iterable[Tuple[str, str]]) -> None:
318+
"""
319+
Validate JSON files in a directory against corresponding JSON Schemas.
320+
321+
This scans the given directory for each JSON filename listed in json_and_schema_file_pairs.
322+
For every file that exists, it validates the file against the associated schema located in
323+
the Native Image docs assets directory. Validation uses a pre-built jsonschema.Validator
324+
per schema to ensure consistent behavior and error reporting.
325+
326+
Parameters:
327+
- dir_with_json: Directory path containing JSON files to validate.
328+
- json_and_schema_file_pairs: Iterable of (json_filename, schema_filename) pairs.
329+
330+
Behavior:
331+
- Logs each validation attempt.
332+
- Accumulates all validation errors across files.
333+
- Calls mx.abort with a detailed message if any error is found; otherwise returns None.
334+
"""
335+
assets_dir = join(suite.dir, '..', 'docs', 'reference-manual', 'native-image', 'assets')
336+
337+
# Build validators for all known schema files using CE helper to ensure uniform behavior and error reporting.
338+
validators = {}
339+
for _, schema_file in json_and_schema_file_pairs:
340+
schema_path = join(assets_dir, schema_file)
341+
validators[schema_file] = create_jsonschema_validator(schema_path)
342+
343+
# Validate any present config files
344+
validation_errors = []
345+
for json_filename, schema_file in json_and_schema_file_pairs:
346+
json_path = join(dir_with_json, json_filename)
347+
if exists(json_path):
348+
mx.log(f'Validating {json_path} against {schema_file}...')
349+
errs = validate_json_file_with_validator(validators[schema_file], json_path)
350+
validation_errors.extend(errs)
351+
352+
if validation_errors:
353+
mx.abort('Unable to validate JSON file against the schema:\n\n' + '\n\n'.join(validation_errors))
354+
355+
265356
class GraalVMJDKConfig(mx.JDKConfig):
266357

267358
# Oracle JDK includes the libjvmci compiler, allowing it to function as GraalVM.

substratevm/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ This changelog summarizes major changes to GraalVM Native Image.
88
* (GR-69280) Allow use of the `graal.` prefix for options without issuing a warning.
99
* (GR-2092) Add jitdump support for recording run-time compilation metadata for perf (see PerfProfiling.md). Can be enabled with `-g -H:+RuntimeDebugInfo -H:RuntimeDebugInfoFormat=jitdump`.
1010
* (GR-69572) Deprecates the `native-image-inspect` tool. To extract embedded SBOMs, use `native-image-configure extract-sbom --image-path=<path_to_binary>`.
11+
* (GR-68984) Ship the `reachability-metadata-schema.json` together with GraalVM at `<graalvm-home>/lib/svm/schemas/reachability-metadata-schema.json`.
12+
* (GR-68984) Improve the schema to capture detailed constraints about each element in the `reachability-metadata-schema.json`.
1113

1214
## GraalVM 25
1315
* (GR-52276) (GR-61959) Add support for Arena.ofShared().

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import mx_compiler
4444
import mx_gate
4545
import mx_unittest
46+
import mx_sdk
4647
import mx_sdk_vm
4748
import mx_sdk_vm_impl
4849
import mx_javamodules
@@ -525,13 +526,6 @@ def help_stdout_check(output):
525526

526527
with Task('Validate JSON build info', tasks, tags=[GraalTags.helloworld]) as t:
527528
if t:
528-
import json
529-
try:
530-
from jsonschema import validate as json_validate
531-
from jsonschema.exceptions import ValidationError, SchemaError
532-
except ImportError:
533-
mx.abort('Unable to import jsonschema')
534-
535529
json_and_schema_file_pairs = [
536530
('build-artifacts.json', 'build-artifacts-schema-v0.9.0.json'),
537531
('build-output.json', 'build-output-schema-v0.9.4.json'),
@@ -540,19 +534,7 @@ def help_stdout_check(output):
540534
build_output_file = join(svmbuild_dir(), 'build-output.json')
541535
helloworld(['--output-path', svmbuild_dir()] + svm_experimental_options([f'-H:BuildOutputJSONFile={build_output_file}', '-H:+GenerateBuildArtifactsFile']))
542536

543-
try:
544-
for json_file, schema_file in json_and_schema_file_pairs:
545-
with open(join(svmbuild_dir(), json_file)) as f:
546-
json_contents = json.load(f)
547-
with open(join(suite.dir, '..', 'docs', 'reference-manual', 'native-image', 'assets', schema_file)) as f:
548-
schema_contents = json.load(f)
549-
json_validate(json_contents, schema_contents)
550-
except IOError as e:
551-
mx.abort(f'Unable to load JSON build info: {e}')
552-
except ValidationError as e:
553-
mx.abort(f'Unable to validate JSON build info against the schema: {e}')
554-
except SchemaError as e:
555-
mx.abort(f'JSON schema not valid: {e}')
537+
mx_sdk.validate_dir_files_with_file_schema_pairs(svmbuild_dir(), json_and_schema_file_pairs)
556538

557539
with Task('java agent tests', tasks, tags=[GraalTags.java_agent]) as t:
558540
if t:

substratevm/mx.substratevm/suite.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2475,6 +2475,7 @@
24752475
"clibraries/" : ["extracted-dependency:substratevm:SVM_HOSTED_NATIVE"],
24762476
"builder/clibraries/" : ["extracted-dependency:substratevm:SVM_HOSTED_NATIVE"],
24772477
"builder/lib/" : ["dependency:com.oracle.svm.native.reporterchelper"],
2478+
"schemas/reachability-metadata-schema.json" : ["file:schemas/reachability-metadata-schema-v1.2.0.json"],
24782479
# Note: `ld64.lld` is a symlink to `lld`, but it is dereferenced here.
24792480
"bin/" : ["extracted-dependency:LLVM_LLD_STANDALONE/bin/ld64.lld"],
24802481
},

0 commit comments

Comments
 (0)