13
0
geforkt von Mirrors/Paper

#474: Add ability to set other plugin names as provided API so others can still depend on it

By: Phoenix616 <mail@moep.tv>
Dieser Commit ist enthalten in:
Bukkit/Spigot 2020-03-15 18:59:32 +11:00
Ursprung b35aa20f22
Commit aec6ad036b
3 geänderte Dateien mit 112 neuen und 8 gelöschten Zeilen

Datei anzeigen

@ -45,6 +45,10 @@ public class PluginsCommand extends BukkitCommand {
pluginList.append(plugin.isEnabled() ? ChatColor.GREEN : ChatColor.RED);
pluginList.append(plugin.getDescription().getName());
if (plugin.getDescription().getProvides().size() > 0) {
pluginList.append(" (").append(String.join(", ", plugin.getDescription().getProvides())).append(")");
}
}
return "(" + plugins.length + "): " + pluginList.toString();

Datei anzeigen

@ -64,6 +64,10 @@ import org.yaml.snakeyaml.nodes.Tag;
* <td>{@link #getName()}</td>
* <td>The unique name of plugin</td>
* </tr><tr>
* <td><code>provides</code></td>
* <td>{@link #getProvides()}</td>
* <td>The plugin APIs which this plugin provides</td>
* </tr><tr>
* <td><code>version</code></td>
* <td>{@link #getVersion()}</td>
* <td>A plugin revision identifier</td>
@ -130,6 +134,7 @@ import org.yaml.snakeyaml.nodes.Tag;
* <p>
* A plugin.yml example:<blockquote><pre>
*name: Inferno
*provides: [Hell]
*version: 1.4.1
*description: This plugin is so 31337. You can set yourself on fire.
*# We could place every author in the authors list, but chose not to for illustrative purposes
@ -218,6 +223,7 @@ public final class PluginDescriptionFile {
};
String rawName = null;
private String name = null;
private List<String> provides = ImmutableList.of();
private String main = null;
private String classLoaderOf = null;
private List<String> depend = ImmutableList.of();
@ -299,6 +305,37 @@ public final class PluginDescriptionFile {
return name;
}
/**
* Gives the list of other plugin APIs which this plugin provides.
* These are usable for other plugins to depend on.
* <ul>
* <li>Must consist of all alphanumeric characters, underscores, hyphon,
* and period (a-z,A-Z,0-9, _.-). Any other character will cause the
* plugin.yml to fail loading.
* <li>A different plugin providing the same one or using it as their name
* will not result in the plugin to fail loading.
* <li>Case sensitive.
* <li>An entry of this list can be referenced in {@link #getDepend()},
* {@link #getSoftDepend()}, and {@link #getLoadBefore()}.
* <li><code>provides</code> must be in <a
* href="http://en.wikipedia.org/wiki/YAML#Lists">YAML list
* format</a>.
* </ul>
* <p>
* In the plugin.yml, this entry is named <code>provides</code>.
* <p>
* Example:
* <blockquote><pre>provides:
*- OtherPluginName
*- OldPluginName</pre></blockquote>
*
* @return immutable list of the plugin APIs which this plugin provides
*/
@NotNull
public List<String> getProvides() {
return provides;
}
/**
* Gives the version of the plugin.
* <ul>
@ -459,7 +496,7 @@ public final class PluginDescriptionFile {
* plugin in the <a
* href=https://en.wikipedia.org/wiki/Circular_dependency>network</a>,
* all plugins in that network will fail.
* <li><code>depend</code> must be in must be in <a
* <li><code>depend</code> must be in <a
* href="http://en.wikipedia.org/wiki/YAML#Lists">YAML list
* format</a>.
* </ul>
@ -923,6 +960,8 @@ public final class PluginDescriptionFile {
throw new InvalidDescriptionException(ex, "name is of wrong type");
}
provides = makePluginNameList(map, "provides");
try {
version = map.get("version").toString();
} catch (NullPointerException ex) {
@ -1080,6 +1119,9 @@ public final class PluginDescriptionFile {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", name);
if (provides != null) {
map.put("provides", provides);
}
map.put("main", main);
map.put("version", version);
map.put("order", order.toString());

Datei anzeigen

@ -123,6 +123,7 @@ public final class SimplePluginManager implements PluginManager {
Map<String, File> plugins = new HashMap<String, File>();
Set<String> loadedPlugins = new HashSet<String>();
Map<String, String> pluginsProvided = new HashMap<>();
Map<String, Collection<String>> dependencies = new HashMap<String, Collection<String>>();
Map<String, Collection<String>> softDependencies = new HashMap<String, Collection<String>>();
@ -165,6 +166,38 @@ public final class SimplePluginManager implements PluginManager {
));
}
String removedProvided = pluginsProvided.remove(description.getName());
if (removedProvided != null) {
server.getLogger().warning(String.format(
"Ambiguous plugin name `%s'. It is also provided by `%s'",
description.getName(),
removedProvided
));
}
for (String provided : description.getProvides()) {
File pluginFile = plugins.get(provided);
if (pluginFile != null) {
server.getLogger().warning(String.format(
"`%s provides `%s' while this is also the name of `%s' in `%s'",
file.getPath(),
provided,
pluginFile.getPath(),
directory.getPath()
));
} else {
String replacedPlugin = pluginsProvided.put(provided, description.getName());
if (replacedPlugin != null) {
server.getLogger().warning(String.format(
"`%s' is provided by both `%s' and `%s'",
provided,
description.getName(),
replacedPlugin
));
}
}
}
Collection<String> softDependencySet = description.getSoftDepend();
if (softDependencySet != null && !softDependencySet.isEmpty()) {
if (softDependencies.containsKey(description.getName())) {
@ -224,7 +257,7 @@ public final class SimplePluginManager implements PluginManager {
dependencyIterator.remove();
// We have a dependency not found
} else if (!plugins.containsKey(dependency)) {
} else if (!plugins.containsKey(dependency) && !pluginsProvided.containsKey(dependency)) {
missingDependency = false;
pluginIterator.remove();
softDependencies.remove(plugin);
@ -249,7 +282,7 @@ public final class SimplePluginManager implements PluginManager {
String softDependency = softDependencyIterator.next();
// Soft depend is no longer around
if (!plugins.containsKey(softDependency)) {
if (!plugins.containsKey(softDependency) && !pluginsProvided.containsKey(softDependency)) {
softDependencyIterator.remove();
}
}
@ -265,8 +298,14 @@ public final class SimplePluginManager implements PluginManager {
missingDependency = false;
try {
result.add(loadPlugin(file));
loadedPlugins.add(plugin);
Plugin loadedPlugin = loadPlugin(file);
if (loadedPlugin != null) {
result.add(loadedPlugin);
loadedPlugins.add(loadedPlugin.getName());
loadedPlugins.addAll(loadedPlugin.getDescription().getProvides());
} else {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'");
}
continue;
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex);
@ -290,8 +329,14 @@ public final class SimplePluginManager implements PluginManager {
pluginIterator.remove();
try {
result.add(loadPlugin(file));
loadedPlugins.add(plugin);
Plugin loadedPlugin = loadPlugin(file);
if (loadedPlugin != null) {
result.add(loadedPlugin);
loadedPlugins.add(loadedPlugin.getName());
loadedPlugins.addAll(loadedPlugin.getDescription().getProvides());
} else {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'");
}
break;
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex);
@ -352,6 +397,9 @@ public final class SimplePluginManager implements PluginManager {
if (result != null) {
plugins.add(result);
lookupNames.put(result.getDescription().getName(), result);
for (String provided : result.getDescription().getProvides()) {
lookupNames.putIfAbsent(provided, result);
}
}
return result;
@ -796,7 +844,17 @@ public final class SimplePluginManager implements PluginManager {
Preconditions.checkArgument(plugin != null, "plugin");
Preconditions.checkArgument(depend != null, "depend");
return dependencyGraph.nodes().contains(plugin.getName()) && Graphs.reachableNodes(dependencyGraph, plugin.getName()).contains(depend.getName());
if (dependencyGraph.nodes().contains(plugin.getName())) {
if (Graphs.reachableNodes(dependencyGraph, plugin.getName()).contains(depend.getName())) {
return true;
}
for (String provided : depend.getProvides()) {
if (Graphs.reachableNodes(dependencyGraph, plugin.getName()).contains(provided)) {
return true;
}
}
}
return false;
}
@Override