use of net.fabricmc.loader.api.VersionParsingException in project quilt-loader by QuiltMC.
the class V1ModMetadataParser method parse.
/**
* Reads a {@code fabric.mod.json} file of schema version {@code 1}.
*
* @param logger the logger to print warnings to
* @param reader the json reader to read the file with
* @return the metadata of this file, null if the file could not be parsed
* @throws IOException if there was any issue reading the file
*/
static FabricLoaderModMetadata parse(JsonReader reader) throws IOException, ParseMetadataException {
List<ParseWarning> warnings = new ArrayList<>();
// All the values the `fabric.mod.json` may contain:
// Required
String id = null;
Version version = null;
// Optional (id provides)
List<String> provides = new ArrayList<>();
// Optional (mod loading)
// Default is always universal
ModEnvironment environment = ModEnvironment.UNIVERSAL;
Map<String, List<EntrypointMetadata>> entrypoints = new HashMap<>();
List<NestedJarEntry> jars = new ArrayList<>();
List<V1ModMetadataFabric.MixinEntry> mixins = new ArrayList<>();
String accessWidener = null;
// Optional (dependency resolution)
List<ModDependency> dependencies = new ArrayList<>();
// Happy little accidents
boolean hasRequires = false;
// Optional (metadata)
String name = null;
String description = null;
List<Person> authors = new ArrayList<>();
List<Person> contributors = new ArrayList<>();
ContactInformation contact = null;
List<String> license = new ArrayList<>();
V1ModMetadataFabric.IconEntry icon = null;
// Optional (language adapter providers)
Map<String, String> languageAdapters = new HashMap<>();
// Optional (custom values)
Map<String, CustomValue> customValues = new HashMap<>();
while (reader.hasNext()) {
final String key = reader.nextName();
// Work our way from required to entirely optional
switch(key) {
case "schemaVersion":
// Duplicate field, make sure it matches our current schema version
if (reader.peek() != JsonToken.NUMBER) {
throw new ParseMetadataException("Duplicate \"schemaVersion\" field is not a number", reader);
}
final int read = reader.nextInt();
if (read != 1) {
throw new ParseMetadataException(String.format("Duplicate \"schemaVersion\" field does not match the predicted schema version of 1. Duplicate field value is %s", read), reader);
}
break;
case "id":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Mod id must be a non-empty string with a length of 3-64 characters.", reader);
}
id = reader.nextString();
break;
case "version":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Version must be a non-empty string", reader);
}
try {
version = VersionParser.parse(reader.nextString(), false);
} catch (VersionParsingException e) {
throw new ParseMetadataException("Failed to parse version", e);
}
break;
case "provides":
readProvides(reader, provides);
break;
case "environment":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Environment must be a string", reader);
}
environment = readEnvironment(reader);
break;
case "entrypoints":
readEntrypoints(warnings, reader, entrypoints);
break;
case "jars":
readNestedJarEntries(warnings, reader, jars);
break;
case "mixins":
readMixinConfigs(warnings, reader, mixins);
break;
case "accessWidener":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Access Widener file must be a string", reader);
}
accessWidener = reader.nextString();
break;
case "depends":
readDependenciesContainer(reader, ModDependency.Kind.DEPENDS, dependencies);
break;
case "recommends":
readDependenciesContainer(reader, ModDependency.Kind.RECOMMENDS, dependencies);
break;
case "suggests":
readDependenciesContainer(reader, ModDependency.Kind.SUGGESTS, dependencies);
break;
case "conflicts":
readDependenciesContainer(reader, ModDependency.Kind.CONFLICTS, dependencies);
break;
case "breaks":
readDependenciesContainer(reader, ModDependency.Kind.BREAKS, dependencies);
break;
case "requires":
hasRequires = true;
reader.skipValue();
break;
case "name":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Mod name must be a string", reader);
}
name = reader.nextString();
break;
case "description":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Mod description must be a string", reader);
}
description = reader.nextString();
break;
case "authors":
readPeople(warnings, reader, authors);
break;
case "contributors":
readPeople(warnings, reader, contributors);
break;
case "contact":
contact = readContactInfo(reader);
break;
case "license":
readLicense(reader, license);
break;
case "icon":
icon = readIcon(reader);
break;
case "languageAdapters":
readLanguageAdapters(reader, languageAdapters);
break;
case "custom":
readCustomValues(reader, customValues);
break;
case "$schema":
reader.skipValue();
break;
default:
if (!FabricModMetadataReader.IGNORED_KEYS.contains(key)) {
warnings.add(new ParseWarning(reader.locationString(), key, "Unsupported root entry"));
}
reader.skipValue();
break;
}
}
// Validate all required fields are resolved
if (id == null) {
throw new ParseMetadataException.MissingField("id");
}
if (version == null) {
throw new ParseMetadataException.MissingField("version");
}
FabricModMetadataReader.logWarningMessages(id, warnings);
return new V1ModMetadataFabric(id, version, provides, environment, entrypoints, jars, mixins, accessWidener, dependencies, hasRequires, name, description, authors, contributors, contact, license, icon, languageAdapters, customValues);
}
use of net.fabricmc.loader.api.VersionParsingException in project BCLib by paulevsGitch.
the class ModUtil method readJSON.
private static ModMetadata readJSON(InputStream is, String sourceFile) throws IOException {
try (com.google.gson.stream.JsonReader reader = new JsonReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
JsonObject data = new JsonParser().parse(reader).getAsJsonObject();
Version ver;
try {
ver = new SemanticVersionImpl(data.get("version").getAsString(), false);
} catch (VersionParsingException e) {
BCLib.LOGGER.error("Unable to parse Version in " + sourceFile);
return null;
}
if (data.get("id") == null) {
BCLib.LOGGER.error("Unable to read ID in " + sourceFile);
return null;
}
if (data.get("name") == null) {
BCLib.LOGGER.error("Unable to read name in " + sourceFile);
return null;
}
return new ModMetadata() {
@Override
public Version getVersion() {
return ver;
}
@Override
public String getType() {
return "fabric";
}
@Override
public String getId() {
return data.get("id").getAsString();
}
@Override
public Collection<String> getProvides() {
return new ArrayList<>();
}
@Override
public ModEnvironment getEnvironment() {
JsonElement env = data.get("environment");
if (env == null) {
BCLib.LOGGER.warning("No environment specified in " + sourceFile);
// return ModEnvironment.UNIVERSAL;
}
final String environment = env == null ? "" : env.getAsString().toLowerCase(Locale.ROOT);
if (environment.isEmpty() || environment.equals("*") || environment.equals("\"*\"") || environment.equals("common")) {
JsonElement entrypoints = data.get("entrypoints");
boolean hasClient = true;
// check if there is an actual client entrypoint
if (entrypoints != null && entrypoints.isJsonObject()) {
JsonElement client = entrypoints.getAsJsonObject().get("client");
if (client != null && client.isJsonArray()) {
hasClient = client.getAsJsonArray().size() > 0;
} else if (client == null || !client.isJsonPrimitive()) {
hasClient = false;
} else if (!client.getAsJsonPrimitive().isString()) {
hasClient = false;
}
}
// if (hasClient == false) return ModEnvironment.SERVER;
return ModEnvironment.UNIVERSAL;
} else if (environment.equals("client")) {
return ModEnvironment.CLIENT;
} else if (environment.equals("server")) {
return ModEnvironment.SERVER;
} else {
BCLib.LOGGER.error("Unable to read environment in " + sourceFile);
return ModEnvironment.UNIVERSAL;
}
}
@Override
public Collection<ModDependency> getDepends() {
return new ArrayList<>();
}
@Override
public Collection<ModDependency> getRecommends() {
return new ArrayList<>();
}
@Override
public Collection<ModDependency> getSuggests() {
return new ArrayList<>();
}
@Override
public Collection<ModDependency> getConflicts() {
return new ArrayList<>();
}
@Override
public Collection<ModDependency> getBreaks() {
return new ArrayList<>();
}
public Collection<ModDependency> getDependencies() {
return new ArrayList<>();
}
@Override
public String getName() {
return data.get("name").getAsString();
}
@Override
public String getDescription() {
return "";
}
@Override
public Collection<Person> getAuthors() {
return new ArrayList<>();
}
@Override
public Collection<Person> getContributors() {
return new ArrayList<>();
}
@Override
public ContactInformation getContact() {
return null;
}
@Override
public Collection<String> getLicense() {
return new ArrayList<>();
}
@Override
public Optional<String> getIconPath(int size) {
return Optional.empty();
}
@Override
public boolean containsCustomValue(String key) {
return false;
}
@Override
public CustomValue getCustomValue(String key) {
return null;
}
@Override
public Map<String, CustomValue> getCustomValues() {
return new HashMap<>();
}
@Override
public boolean containsCustomElement(String key) {
return false;
}
public JsonElement getCustomElement(String key) {
return null;
}
};
}
}
use of net.fabricmc.loader.api.VersionParsingException in project fabric-loader by FabricMC.
the class Log4jLogHandler method needsLookupRemoval.
private static boolean needsLookupRemoval() {
Manifest manifest;
try {
manifest = ManifestUtil.readManifest(LogManager.class);
} catch (IOException | URISyntaxException e) {
Log.warn(LogCategory.GAME_PROVIDER, "Can't read Log4J2 Manifest", e);
return true;
}
if (manifest == null)
return true;
String title = ManifestUtil.getManifestValue(manifest, Name.IMPLEMENTATION_TITLE);
if (title == null || !title.toLowerCase(Locale.ENGLISH).contains("log4j"))
return true;
String version = ManifestUtil.getManifestValue(manifest, Name.IMPLEMENTATION_VERSION);
if (version == null)
return true;
try {
// 2.15+ doesn't lookup by default, but we patch anything up to 2.16 just in case
return Version.parse(version).compareTo(Version.parse("2.16")) < 0;
} catch (VersionParsingException e) {
Log.warn(LogCategory.GAME_PROVIDER, "Can't parse Log4J2 Manifest version %s", version, e);
return true;
}
}
use of net.fabricmc.loader.api.VersionParsingException in project fabric-loader by FabricMC.
the class V1ModMetadataParser method parse.
/**
* Reads a {@code fabric.mod.json} file of schema version {@code 1}.
*
* @param logger the logger to print warnings to
* @param reader the json reader to read the file with
* @return the metadata of this file, null if the file could not be parsed
* @throws IOException if there was any issue reading the file
*/
static LoaderModMetadata parse(JsonReader reader) throws IOException, ParseMetadataException {
List<ParseWarning> warnings = new ArrayList<>();
// All the values the `fabric.mod.json` may contain:
// Required
String id = null;
Version version = null;
// Optional (id provides)
List<String> provides = new ArrayList<>();
// Optional (mod loading)
// Default is always universal
ModEnvironment environment = ModEnvironment.UNIVERSAL;
Map<String, List<EntrypointMetadata>> entrypoints = new HashMap<>();
List<NestedJarEntry> jars = new ArrayList<>();
List<V1ModMetadata.MixinEntry> mixins = new ArrayList<>();
String accessWidener = null;
// Optional (dependency resolution)
List<ModDependency> dependencies = new ArrayList<>();
// Happy little accidents
boolean hasRequires = false;
// Optional (metadata)
String name = null;
String description = null;
List<Person> authors = new ArrayList<>();
List<Person> contributors = new ArrayList<>();
ContactInformation contact = null;
List<String> license = new ArrayList<>();
V1ModMetadata.IconEntry icon = null;
// Optional (language adapter providers)
Map<String, String> languageAdapters = new HashMap<>();
// Optional (custom values)
Map<String, CustomValue> customValues = new HashMap<>();
while (reader.hasNext()) {
final String key = reader.nextName();
// Work our way from required to entirely optional
switch(key) {
case "schemaVersion":
// Duplicate field, make sure it matches our current schema version
if (reader.peek() != JsonToken.NUMBER) {
throw new ParseMetadataException("Duplicate \"schemaVersion\" field is not a number", reader);
}
final int read = reader.nextInt();
if (read != 1) {
throw new ParseMetadataException(String.format("Duplicate \"schemaVersion\" field does not match the predicted schema version of 1. Duplicate field value is %s", read), reader);
}
break;
case "id":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Mod id must be a non-empty string with a length of 3-64 characters.", reader);
}
id = reader.nextString();
break;
case "version":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Version must be a non-empty string", reader);
}
try {
version = VersionParser.parse(reader.nextString(), false);
} catch (VersionParsingException e) {
throw new ParseMetadataException("Failed to parse version", e);
}
break;
case "provides":
readProvides(reader, provides);
break;
case "environment":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Environment must be a string", reader);
}
environment = readEnvironment(reader);
break;
case "entrypoints":
readEntrypoints(warnings, reader, entrypoints);
break;
case "jars":
readNestedJarEntries(warnings, reader, jars);
break;
case "mixins":
readMixinConfigs(warnings, reader, mixins);
break;
case "accessWidener":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Access Widener file must be a string", reader);
}
accessWidener = reader.nextString();
break;
case "depends":
readDependenciesContainer(reader, ModDependency.Kind.DEPENDS, dependencies);
break;
case "recommends":
readDependenciesContainer(reader, ModDependency.Kind.RECOMMENDS, dependencies);
break;
case "suggests":
readDependenciesContainer(reader, ModDependency.Kind.SUGGESTS, dependencies);
break;
case "conflicts":
readDependenciesContainer(reader, ModDependency.Kind.CONFLICTS, dependencies);
break;
case "breaks":
readDependenciesContainer(reader, ModDependency.Kind.BREAKS, dependencies);
break;
case "requires":
hasRequires = true;
reader.skipValue();
break;
case "name":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Mod name must be a string", reader);
}
name = reader.nextString();
break;
case "description":
if (reader.peek() != JsonToken.STRING) {
throw new ParseMetadataException("Mod description must be a string", reader);
}
description = reader.nextString();
break;
case "authors":
readPeople(warnings, reader, authors);
break;
case "contributors":
readPeople(warnings, reader, contributors);
break;
case "contact":
contact = readContactInfo(reader);
break;
case "license":
readLicense(reader, license);
break;
case "icon":
icon = readIcon(reader);
break;
case "languageAdapters":
readLanguageAdapters(reader, languageAdapters);
break;
case "custom":
readCustomValues(reader, customValues);
break;
default:
if (!ModMetadataParser.IGNORED_KEYS.contains(key)) {
warnings.add(new ParseWarning(reader.getLineNumber(), reader.getColumn(), key, "Unsupported root entry"));
}
reader.skipValue();
break;
}
}
// Validate all required fields are resolved
if (id == null) {
throw new ParseMetadataException.MissingField("id");
}
if (version == null) {
throw new ParseMetadataException.MissingField("version");
}
ModMetadataParser.logWarningMessages(id, warnings);
return new V1ModMetadata(id, version, provides, environment, entrypoints, jars, mixins, accessWidener, dependencies, hasRequires, name, description, authors, contributors, contact, license, icon, languageAdapters, customValues);
}
use of net.fabricmc.loader.api.VersionParsingException in project fabric-loader by FabricMC.
the class VersionPredicateParser method parse.
public static VersionPredicate parse(String predicate) throws VersionParsingException {
List<SingleVersionPredicate> predicateList = new ArrayList<>();
for (String s : predicate.split(" ")) {
s = s.trim();
if (s.isEmpty() || s.equals("*")) {
continue;
}
VersionComparisonOperator operator = VersionComparisonOperator.EQUAL;
for (VersionComparisonOperator op : OPERATORS) {
if (s.startsWith(op.getSerialized())) {
operator = op;
s = s.substring(op.getSerialized().length());
break;
}
}
Version version = VersionParser.parse(s, true);
if (version instanceof SemanticVersion) {
SemanticVersion semVer = (SemanticVersion) version;
if (semVer.hasWildcard()) {
// .x version -> replace with conventional version by replacing the operator
if (operator != VersionComparisonOperator.EQUAL) {
throw new VersionParsingException("Invalid predicate: " + predicate + ", version ranges with wildcards (.X) require using the equality operator or no operator at all!");
}
assert !semVer.getPrereleaseKey().isPresent();
int compCount = semVer.getVersionComponentCount();
assert compCount == 2 || compCount == 3;
operator = compCount == 2 ? VersionComparisonOperator.SAME_TO_NEXT_MAJOR : VersionComparisonOperator.SAME_TO_NEXT_MINOR;
int[] newComponents = new int[semVer.getVersionComponentCount() - 1];
for (int i = 0; i < semVer.getVersionComponentCount() - 1; i++) {
newComponents[i] = semVer.getVersionComponent(i);
}
version = new SemanticVersionImpl(newComponents, "", semVer.getBuildKey().orElse(null));
}
} else if (!operator.isMinInclusive() && !operator.isMaxInclusive()) {
// non-semver without inclusive bound
throw new VersionParsingException("Invalid predicate: " + predicate + ", version ranges need to be semantic version compatible to use operators that exclude the bound!");
} else {
// non-semver with inclusive bound
operator = VersionComparisonOperator.EQUAL;
}
predicateList.add(new SingleVersionPredicate(operator, version));
}
if (predicateList.isEmpty()) {
return AnyVersionPredicate.INSTANCE;
} else if (predicateList.size() == 1) {
return predicateList.get(0);
} else {
return new MultiVersionPredicate(predicateList);
}
}
Aggregations