Skip to content

Commit

Permalink
Pluginyml generation (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
Goldmensch committed Jan 19, 2023
2 parents 99f551a + aea1b96 commit bd608f1
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 26 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
commit.types=feat, fix, refactor, perf, style, test, docs, build, ops, chore
commit.scopes=gradle, deps, listener
commit.scopes=gradle, deps, listener, pluginyml
# Allows you to validate commits only after this one, add the commmit hash here.
commit.ignoreCommitsBefore=376515192f5346245d5c7ce0aebf9b706c29b454
micronautVersion=3.7.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2023 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.github.madethoughts.mayflower.plugin;

import jakarta.inject.Singleton;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
This annotation indicates that a class is the plugin's entrypoint, the class must also extend {@link MayflowerPlugin}
<p>
It is also used to generate a "plugin.yml".
*/
@Singleton
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface McPlugin {
/**
@return The plugin's name
*/
String name();

/**
@return The plugin's version
*/
String version();

/**
@return The plugin's api version
*/
ApiVersion apiVersion();

/**
@return The plugin's authors. The field "author" is automatically set if only one author is given.
*/
String[] authors();

/**
@return The plugin's description
*/
String description() default "";

/**
@return The plugin's loading time
*/
Load load() default Load.POSTWORLD;

/**
@return The plugin's website
*/
String website() default "";

/**
@return The plugin's plugin dependencies
*/
String[] depend() default "";

/**
@return The plugin's plugin soft dependencies
*/
String[] softdepend() default "";

/**
@return The plugins prefix
*/
String prefix() default "";

/**
@return The plugins that should be loaded before this plugin.
*/
String[] loadbefore() default "";

/**
Defines the possible plugin load times.
*/
enum Load {
/**
load: STARTUP
*/
STARTUP,
/**
load: POSTWORLD
*/
POSTWORLD
}

/**
This enum defines api versions applicable in {@link McPlugin#apiVersion()}
*/
enum ApiVersion {
/**
api-version: 1.13
*/
V1_13,
/**
api-version: 1.14
*/
V1_14,
/**
api-version: 1.15
*/
V1_15,
/**
api-version: 1.16
*/
V1_16,
/**
api-version: 1.17
*/
V1_17,
/**
api-version: 1.18
*/
V1_18,
/**
api-version: 1.19
*/
V1_19
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright 2023 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.github.madethoughts.mayflower.plugin.yaml;

import io.github.madethoughts.mayflower.plugin.McPlugin;
import io.micronaut.inject.ast.ClassElement;
import io.micronaut.inject.visitor.TypeElementVisitor;
import io.micronaut.inject.visitor.VisitorContext;
import org.yaml.snakeyaml.Yaml;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.stream.Stream;

/**
Generates a plugin.yml from the {@link McPlugin} annotation.
Values specified in the "template-plugin.yml" override generated ones.
*/
public class McPluginVisitor implements TypeElementVisitor<McPlugin, Object> {

private static final String PLUGIN_YAML = "plugin.yml";
private static final String TEMPLATE_PLUGIN_YAML = "override.plugin.yml";
private static final BiPredicate<Path, BasicFileAttributes> TEMPLATE_PLUGIN_YAML_PREDICATE =
(path, basicFileAttributes) -> path.endsWith(Path.of("resources", TEMPLATE_PLUGIN_YAML));
private final Yaml yaml = new Yaml();

@Override
public void visitClass(ClassElement element, VisitorContext context) {
var projectDir = context.getProjectDir().orElseThrow();

// search for existing file
var data = find(projectDir).findFirst()
.map(McPluginVisitor::readString)
.map(s -> new Yaml().<Map<String, Object>>load(s)).orElseGet(HashMap::new);

@SuppressWarnings("DataFlowIssue") // annotation should not be null
var pluginValues = element.getAnnotation(McPlugin.class).getValues().entrySet();
data.computeIfAbsent("main", s -> element.getName());

for (var entry : pluginValues) {
var key = entry.getKey().toString();
var value = entry.getValue();
var mappedKey = switch (key) {
case "apiVersion" -> {
// bring enum entry in right format, the enum is already a string here.
value = value.toString().replace("V", "").replace("_", ".");
yield "api-version";
}
case "authors" -> {
if (value instanceof String[] authors && 1 == authors.length) {
value = authors[0];
yield "author";
}
yield "authors";
}
default -> key;
};

data.putIfAbsent(mappedKey, value);
}

var ouputPath = context.getClassesOutputPath().orElseThrow().resolve(PLUGIN_YAML);
var dump = yaml.dump(data);
writeString(ouputPath, dump);
}

private static Stream<Path> find(Path start) {
try {
// 6 should be enough depth based on the gradle file hierarchy
return Files.find(start, 6, TEMPLATE_PLUGIN_YAML_PREDICATE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private static String readString(Path path) {
try {
return Files.readString(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private static void writeString(Path path, String text) {
try {
Files.writeString(path, text);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,4 @@
* limitations under the License.
*/

package io.github.madethoughts.mayflower.plugin;

import jakarta.inject.Singleton;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
This annotation indicates that a class is the plugin's entrypoint, the class must also extend {@link MayflowerPlugin}
*/
@Singleton
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface PaperPlugin {
}
package io.github.madethoughts.mayflower.plugin.yaml;
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
import io.github.madethoughts.mayflower.lifecycle.event.EnableEvent;
import io.github.madethoughts.mayflower.listener.McListener;
import io.github.madethoughts.mayflower.plugin.MayflowerPlugin;
import io.github.madethoughts.mayflower.plugin.PaperPlugin;
import io.github.madethoughts.mayflower.plugin.McPlugin;
import io.micronaut.runtime.event.annotation.EventListener;
import org.bukkit.event.player.PlayerJoinEvent;

@PaperPlugin
@SuppressWarnings("ALL")
@McPlugin(name = "MayflowerTestPlugin", version = "0.1", apiVersion = McPlugin.ApiVersion.V1_19, authors = "goldmensch")
public class TestPlugin extends MayflowerPlugin {

@EventListener
Expand Down
1 change: 1 addition & 0 deletions test_plugin/src/main/resources/override.plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
description: "The best test plugin eu-west"
4 changes: 0 additions & 4 deletions test_plugin/src/main/resources/plugin.yml

This file was deleted.

0 comments on commit bd608f1

Please sign in to comment.