Skip to content

Commit

Permalink
Parse constant resource patterns as globs
Browse files Browse the repository at this point in the history
  • Loading branch information
loicottet committed Sep 5, 2024
1 parent 6a5bc9f commit 17fc7f0
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@
package com.oracle.svm.core.configure;

import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;

import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.MapCursor;
import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition;

import com.oracle.svm.core.TypeResult;
import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.CompressedGlobTrie;

final class LegacyResourceConfigurationParser<C> extends ResourceConfigurationParser<C> {
LegacyResourceConfigurationParser(ConfigurationConditionResolver<C> conditionResolver, ResourcesRegistry<C> registry, boolean strictConfiguration) {
Expand Down Expand Up @@ -64,4 +71,61 @@ private void parseTopLevelObject(EconomicMap<String, Object> obj, Object origin)
parseGlobsObject(globsObject, origin);
}
}

@Override
protected UnresolvedConfigurationCondition parseCondition(EconomicMap<String, Object> condition) {
return parseCondition(condition, false);
}

@SuppressWarnings("unchecked")
private void parseResourcesObject(Object resourcesObject, Object origin) {
if (resourcesObject instanceof EconomicMap) { // New format
EconomicMap<String, Object> resourcesObjectMap = (EconomicMap<String, Object>) resourcesObject;
checkAttributes(resourcesObjectMap, "resource descriptor object", Collections.singleton("includes"), Collections.singleton("excludes"));
Object includesObject = resourcesObjectMap.get("includes");
Object excludesObject = resourcesObjectMap.get("excludes");

List<Object> includes = asList(includesObject, "Attribute 'includes' must be a list of resources");
for (Object object : includes) {
parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin),
(condition, module, glob) -> registry.addGlob(condition, module, glob, origin), "'includes' list");
}

if (excludesObject != null) {
List<Object> excludes = asList(excludesObject, "Attribute 'excludes' must be a list of resources");
for (Object object : excludes) {
parsePatternEntry(object, registry::ignoreResources, null, "'excludes' list");
}
}
} else { // Old format: may be deprecated in future versions
List<Object> resources = asList(resourcesObject, "Attribute 'resources' must be a list of resources");
for (Object object : resources) {
parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin),
(condition, module, glob) -> registry.addGlob(condition, module, glob, origin), "'resources' list");
}
}
}

private void parsePatternEntry(Object data, BiConsumer<C, String> resourceRegistry, GlobPatternConsumer<C> globRegistry, String parentType) {
EconomicMap<String, Object> resource = asMap(data, "Elements of " + parentType + " must be a resource descriptor object");
checkAttributes(resource, "regex resource descriptor object", Collections.singletonList("pattern"), Collections.singletonList(CONDITIONAL_KEY));
TypeResult<C> resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false));
if (!resolvedConfigurationCondition.isPresent()) {
return;
}

Object valueObject = resource.get("pattern");
String value = asString(valueObject, "pattern");

/* Parse fully literal regex as globs */
if (value.startsWith("\\Q") && value.endsWith("\\E") && value.indexOf("\\E") == value.lastIndexOf("\\E")) {
String globValue = value.substring("\\Q".length(), value.length() - "\\E".length());
if (CompressedGlobTrie.validatePattern(globValue).isEmpty()) {
globRegistry.accept(resolvedConfigurationCondition.get(), null, globValue);
return;
}
}

resourceRegistry.accept(resolvedConfigurationCondition.get(), value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

import org.graalvm.collections.EconomicMap;
import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition;

import com.oracle.svm.core.TypeResult;
import com.oracle.svm.core.jdk.localization.LocalizationSupport;
Expand Down Expand Up @@ -64,38 +64,13 @@ protected void parseBundlesObject(Object bundlesObject) {
}
}

@SuppressWarnings("unchecked")
protected void parseResourcesObject(Object resourcesObject, Object origin) {
if (resourcesObject instanceof EconomicMap) { // New format
EconomicMap<String, Object> resourcesObjectMap = (EconomicMap<String, Object>) resourcesObject;
checkAttributes(resourcesObjectMap, "resource descriptor object", Collections.singleton("includes"), Collections.singleton("excludes"));
Object includesObject = resourcesObjectMap.get("includes");
Object excludesObject = resourcesObjectMap.get("excludes");

List<Object> includes = asList(includesObject, "Attribute 'includes' must be a list of resources");
for (Object object : includes) {
parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin), "'includes' list");
}

if (excludesObject != null) {
List<Object> excludes = asList(excludesObject, "Attribute 'excludes' must be a list of resources");
for (Object object : excludes) {
parsePatternEntry(object, registry::ignoreResources, "'excludes' list");
}
}
} else { // Old format: may be deprecated in future versions
List<Object> resources = asList(resourcesObject, "Attribute 'resources' must be a list of resources");
for (Object object : resources) {
parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin), "'resources' list");
}
}
}
protected abstract UnresolvedConfigurationCondition parseCondition(EconomicMap<String, Object> condition);

private void parseBundle(Object bundle) {
EconomicMap<String, Object> resource = asMap(bundle, "Elements of 'bundles' list must be a bundle descriptor object");
checkAttributes(resource, "bundle descriptor object", Collections.singletonList("name"), Arrays.asList("locales", "classNames", "condition"));
String basename = asString(resource.get("name"));
TypeResult<C> resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false));
TypeResult<C> resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource));
if (!resolvedConfigurationCondition.isPresent()) {
return;
}
Expand Down Expand Up @@ -133,34 +108,21 @@ private static Locale parseLocale(Object input) {
return locale;
}

private void parsePatternEntry(Object data, BiConsumer<C, String> resourceRegistry, String parentType) {
EconomicMap<String, Object> resource = asMap(data, "Elements of " + parentType + " must be a resource descriptor object");
checkAttributes(resource, "regex resource descriptor object", Collections.singletonList("pattern"), Collections.singletonList(CONDITIONAL_KEY));
TypeResult<C> resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false));
if (!resolvedConfigurationCondition.isPresent()) {
return;
}

Object valueObject = resource.get("pattern");
String value = asString(valueObject, "pattern");
resourceRegistry.accept(resolvedConfigurationCondition.get(), value);
}

protected void parseGlobsObject(Object globsObject, Object origin) {
List<Object> globs = asList(globsObject, "Attribute 'globs' must be a list of glob patterns");
for (Object object : globs) {
parseGlobEntry(object, (condition, module, glob) -> registry.addGlob(condition, module, glob, origin));
}
}

private interface GlobPatternConsumer<T> {
protected interface GlobPatternConsumer<T> {
void accept(T a, String b, String c);
}

private void parseGlobEntry(Object data, GlobPatternConsumer<C> resourceRegistry) {
EconomicMap<String, Object> globObject = asMap(data, "Elements of 'globs' list must be a glob descriptor objects");
checkAttributes(globObject, "glob resource descriptor object", Collections.singletonList(GLOB_KEY), List.of(CONDITIONAL_KEY, MODULE_KEY));
TypeResult<C> resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(globObject, false));
TypeResult<C> resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(globObject));
if (!resolvedConfigurationCondition.isPresent()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

import java.net.URI;

import org.graalvm.collections.EconomicMap;
import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition;

final class ResourceMetadataParser<C> extends ResourceConfigurationParser<C> {
ResourceMetadataParser(ConfigurationConditionResolver<C> conditionResolver, ResourcesRegistry<C> registry, boolean strictConfiguration) {
super(conditionResolver, registry, strictConfiguration);
Expand All @@ -42,4 +45,9 @@ public void parseAndRegister(Object json, URI origin) {
parseBundlesObject(bundlesJson);
}
}

@Override
protected UnresolvedConfigurationCondition parseCondition(EconomicMap<String, Object> condition) {
return parseCondition(condition, true);
}
}

0 comments on commit 17fc7f0

Please sign in to comment.