mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-03 00:15:35 +00:00
Merge submodule contents for common/addons/manifest-addon-loader/master
This commit is contained in:
commit
0de7a437bb
21
common/addons/manifest-addon-loader/LICENSE
Normal file
21
common/addons/manifest-addon-loader/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2021 Polyhedral Development
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
12
common/addons/manifest-addon-loader/build.gradle.kts
Normal file
12
common/addons/manifest-addon-loader/build.gradle.kts
Normal file
@ -0,0 +1,12 @@
|
||||
dependencies {
|
||||
"shadedApi"("commons-io:commons-io:2.6")
|
||||
"shadedImplementation"("com.dfsek.tectonic:yaml:2.1.2")
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
manifest {
|
||||
attributes("Bootstrap-Addon-Entry-Point" to "com.dfsek.terra.addons.manifest.impl.ManifestAddonLoader")
|
||||
}
|
||||
}
|
||||
|
||||
project.extra.set("bootstrap", true)
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.api;
|
||||
|
||||
|
||||
public interface AddonInitializer {
|
||||
void initialize();
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.solostudios.strata.version.Version;
|
||||
import ca.solostudios.strata.version.VersionRange;
|
||||
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.addons.manifest.impl.config.AddonManifest;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.inject.Injector;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class ManifestAddon implements BaseAddon {
|
||||
private final AddonManifest manifest;
|
||||
|
||||
private final List<AddonInitializer> initializers;
|
||||
|
||||
@Inject
|
||||
private Platform platform;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ManifestAddon.class);
|
||||
|
||||
public ManifestAddon(AddonManifest manifest, List<AddonInitializer> initializers) {
|
||||
this.manifest = manifest;
|
||||
this.initializers = initializers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return manifest.getID();
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
Injector<BaseAddon> addonInjector = Injector.get(this);
|
||||
addonInjector.addExplicitTarget(BaseAddon.class);
|
||||
|
||||
Injector<Platform> platformInjector = Injector.get(platform);
|
||||
platformInjector.addExplicitTarget(Platform.class);
|
||||
|
||||
LOGGER.info("Initializing addon " + getID());
|
||||
|
||||
initializers.forEach(initializer -> {
|
||||
LOGGER.debug("Invoking entry point {}", initializer.getClass());
|
||||
addonInjector.inject(initializer);
|
||||
platformInjector.inject(initializer);
|
||||
initializer.initialize();
|
||||
});
|
||||
}
|
||||
|
||||
public AddonManifest getManifest() {
|
||||
return manifest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, VersionRange> getDependencies() {
|
||||
return manifest.getDependencies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
return manifest.getVersion();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
|
||||
public class ManifestAddonClassLoader extends URLClassLoader {
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
public ManifestAddonClassLoader(URL[] urls, ClassLoader parent) {
|
||||
super(urls, parent);
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl;
|
||||
|
||||
import ca.solostudios.strata.Versions;
|
||||
import ca.solostudios.strata.version.Version;
|
||||
import ca.solostudios.strata.version.VersionRange;
|
||||
import com.dfsek.tectonic.exception.LoadException;
|
||||
import com.dfsek.tectonic.loading.ConfigLoader;
|
||||
import com.dfsek.tectonic.yaml.YamlConfiguration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.addons.manifest.impl.config.AddonManifest;
|
||||
import com.dfsek.terra.addons.manifest.impl.config.WebsiteConfig;
|
||||
import com.dfsek.terra.addons.manifest.impl.config.loaders.VersionLoader;
|
||||
import com.dfsek.terra.addons.manifest.impl.config.loaders.VersionRangeLoader;
|
||||
import com.dfsek.terra.addons.manifest.impl.exception.AddonException;
|
||||
import com.dfsek.terra.addons.manifest.impl.exception.ManifestException;
|
||||
import com.dfsek.terra.addons.manifest.impl.exception.ManifestNotPresentException;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.bootstrap.BootstrapBaseAddon;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ManifestAddonLoader.class);
|
||||
|
||||
private static final Version VERSION = Versions.getVersion(1, 0, 0);
|
||||
|
||||
@Override
|
||||
public Iterable<ManifestAddon> loadAddons(Path addonsFolder, ClassLoader parent) {
|
||||
LOGGER.info("Loading addons...");
|
||||
|
||||
ConfigLoader manifestLoader = new ConfigLoader();
|
||||
manifestLoader.registerLoader(Version.class, new VersionLoader())
|
||||
.registerLoader(VersionRange.class, new VersionRangeLoader())
|
||||
.registerLoader(WebsiteConfig.class, WebsiteConfig::new);
|
||||
|
||||
try {
|
||||
return Files.walk(addonsFolder, 1)
|
||||
.filter(path -> path.toFile().isFile() && path.toString().endsWith(".jar"))
|
||||
.map(path -> {
|
||||
try {
|
||||
LOGGER.debug("Loading addon from JAR {}", path);
|
||||
JarFile jar = new JarFile(path.toFile());
|
||||
|
||||
JarEntry manifestEntry = jar.getJarEntry("terra.addon.yml");
|
||||
if(manifestEntry == null) {
|
||||
throw new ManifestNotPresentException("Addon " + path + " does not contain addon manifest.");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
AddonManifest manifest = manifestLoader.load(new AddonManifest(),
|
||||
new YamlConfiguration(jar.getInputStream(manifestEntry),
|
||||
"terra.addon.yml"));
|
||||
|
||||
LOGGER.info("Loading addon {}", manifest.getID());
|
||||
|
||||
ManifestAddonClassLoader loader = new ManifestAddonClassLoader(new URL[]{ path.toUri().toURL() },
|
||||
getClass().getClassLoader());
|
||||
|
||||
return new ManifestAddon(manifest, manifest.getEntryPoints().stream().map(entryPoint -> {
|
||||
try {
|
||||
Object in = loader.loadClass(entryPoint).getConstructor().newInstance();
|
||||
if(!(in instanceof AddonInitializer)) {
|
||||
throw new AddonException(in.getClass() + " does not extend " + AddonInitializer.class);
|
||||
}
|
||||
return (AddonInitializer) in;
|
||||
} catch(InvocationTargetException e) {
|
||||
throw new AddonException("Exception occurred while instantiating addon: ", e);
|
||||
} catch(NoSuchMethodException | IllegalAccessException | InstantiationException e) {
|
||||
throw new AddonException("No valid default constructor found in entry point " + entryPoint);
|
||||
} catch(ClassNotFoundException e) {
|
||||
throw new AddonException("Entry point " + entryPoint + " not found in JAR.");
|
||||
}
|
||||
}).collect(Collectors.toList()));
|
||||
|
||||
} catch(LoadException e) {
|
||||
throw new ManifestException("Failed to load addon manifest", e);
|
||||
}
|
||||
} catch(IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
} catch(IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return "MANIFEST";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl.config;
|
||||
|
||||
import ca.solostudios.strata.version.Version;
|
||||
import ca.solostudios.strata.version.VersionRange;
|
||||
import com.dfsek.tectonic.annotations.Default;
|
||||
import com.dfsek.tectonic.annotations.Value;
|
||||
import com.dfsek.tectonic.config.ConfigTemplate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.api.util.StringIdentifiable;
|
||||
|
||||
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
public class AddonManifest implements ConfigTemplate, StringIdentifiable {
|
||||
@Value("schema-version")
|
||||
private int schemaVersion;
|
||||
|
||||
@Value("id")
|
||||
private String id;
|
||||
|
||||
@Value("version")
|
||||
private Version version;
|
||||
|
||||
@Value("license")
|
||||
private String license;
|
||||
|
||||
@Value("contributors")
|
||||
@Default
|
||||
private List<String> contributors = Collections.emptyList();
|
||||
|
||||
@Value("entrypoints")
|
||||
private List<String> entryPoints;
|
||||
|
||||
@Value("depends")
|
||||
@Default
|
||||
private Map<String, VersionRange> dependencies = Collections.emptyMap();
|
||||
|
||||
@Value("website")
|
||||
private WebsiteConfig website;
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getSchemaVersion() {
|
||||
return schemaVersion;
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public List<String> getContributors() {
|
||||
return contributors;
|
||||
}
|
||||
|
||||
public List<String> getEntryPoints() {
|
||||
return entryPoints;
|
||||
}
|
||||
|
||||
public String getLicense() {
|
||||
return license;
|
||||
}
|
||||
|
||||
public WebsiteConfig getWebsite() {
|
||||
return website;
|
||||
}
|
||||
|
||||
public Map<String, VersionRange> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl.config;
|
||||
|
||||
import com.dfsek.tectonic.annotations.Value;
|
||||
import com.dfsek.tectonic.loading.object.ObjectTemplate;
|
||||
|
||||
|
||||
public class WebsiteConfig implements ObjectTemplate<WebsiteConfig> {
|
||||
@Value("issues")
|
||||
private String issues;
|
||||
|
||||
@Value("source")
|
||||
private String source;
|
||||
|
||||
@Value("docs")
|
||||
private String docs;
|
||||
|
||||
public String getDocs() {
|
||||
return docs;
|
||||
}
|
||||
|
||||
public String getIssues() {
|
||||
return issues;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebsiteConfig get() {
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl.config.loaders;
|
||||
|
||||
import ca.solostudios.strata.Versions;
|
||||
import ca.solostudios.strata.parser.tokenizer.ParseException;
|
||||
import ca.solostudios.strata.version.Version;
|
||||
import com.dfsek.tectonic.exception.LoadException;
|
||||
import com.dfsek.tectonic.loading.ConfigLoader;
|
||||
import com.dfsek.tectonic.loading.TypeLoader;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
|
||||
|
||||
public class VersionLoader implements TypeLoader<Version> {
|
||||
@Override
|
||||
public Version load(AnnotatedType t, Object c, ConfigLoader loader) throws LoadException {
|
||||
try {
|
||||
return Versions.parseVersion((String) c);
|
||||
} catch(ParseException e) {
|
||||
throw new LoadException("Failed to parse version", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl.config.loaders;
|
||||
|
||||
import ca.solostudios.strata.Versions;
|
||||
import ca.solostudios.strata.parser.tokenizer.ParseException;
|
||||
import ca.solostudios.strata.version.VersionRange;
|
||||
import com.dfsek.tectonic.exception.LoadException;
|
||||
import com.dfsek.tectonic.loading.ConfigLoader;
|
||||
import com.dfsek.tectonic.loading.TypeLoader;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
|
||||
|
||||
public class VersionRangeLoader implements TypeLoader<VersionRange> {
|
||||
@Override
|
||||
public VersionRange load(AnnotatedType t, Object c, ConfigLoader loader) throws LoadException {
|
||||
try {
|
||||
return Versions.parseVersionRange((String) c);
|
||||
} catch(ParseException e) {
|
||||
throw new LoadException("Failed to parse version range", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
|
||||
public class AddonException extends RuntimeException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -4201912399458420090L;
|
||||
|
||||
public AddonException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AddonException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
|
||||
public class ManifestException extends AddonException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -2458077663176544645L;
|
||||
|
||||
public ManifestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ManifestException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.manifest.impl.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
|
||||
public class ManifestNotPresentException extends ManifestException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -2116663180747013810L;
|
||||
|
||||
public ManifestNotPresentException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ManifestNotPresentException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user