Add option to list disabled plugins
After disabling a plugin, it can now be viewed in the ls command by specifying the --all (-a) argument. This will be more useful once we add an ssh command to re-enabled plugins which are disabled. Change-Id: I4100cd9df4ebfac87b2099ef2c916b99ef55c978 Signed-off-by: Brad Larson <bklarson@gmail.com>
This commit is contained in:
@@ -40,6 +40,9 @@ public class ListPlugins {
|
|||||||
@Option(name = "--format", metaVar = "FMT", usage = "Output display format")
|
@Option(name = "--format", metaVar = "FMT", usage = "Output display format")
|
||||||
private OutputFormat format = OutputFormat.TEXT;
|
private OutputFormat format = OutputFormat.TEXT;
|
||||||
|
|
||||||
|
@Option(name = "--all", aliases = {"-a"}, usage = "List all plugins, including disabled plugins")
|
||||||
|
private boolean all;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected ListPlugins(PluginLoader pluginLoader) {
|
protected ListPlugins(PluginLoader pluginLoader) {
|
||||||
this.pluginLoader = pluginLoader;
|
this.pluginLoader = pluginLoader;
|
||||||
@@ -67,7 +70,7 @@ public class ListPlugins {
|
|||||||
|
|
||||||
Map<String, PluginInfo> output = Maps.newTreeMap();
|
Map<String, PluginInfo> output = Maps.newTreeMap();
|
||||||
|
|
||||||
List<Plugin> plugins = Lists.newArrayList(pluginLoader.getPlugins());
|
List<Plugin> plugins = Lists.newArrayList(pluginLoader.getPlugins(all));
|
||||||
Collections.sort(plugins, new Comparator<Plugin>() {
|
Collections.sort(plugins, new Comparator<Plugin>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(Plugin a, Plugin b) {
|
public int compare(Plugin a, Plugin b) {
|
||||||
@@ -76,20 +79,22 @@ public class ListPlugins {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!format.isJson()) {
|
if (!format.isJson()) {
|
||||||
stdout.format("%-30s %-10s\n", "Name", "Version");
|
stdout.format("%-30s %-10s %-8s\n", "Name", "Version", "Status");
|
||||||
stdout
|
stdout
|
||||||
.print("----------------------------------------------------------------------\n");
|
.print("-------------------------------------------------------------------------------\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Plugin p : plugins) {
|
for (Plugin p : plugins) {
|
||||||
PluginInfo info = new PluginInfo();
|
PluginInfo info = new PluginInfo();
|
||||||
info.version = p.getVersion();
|
info.version = p.getVersion();
|
||||||
|
info.disabled = p.isDisabled() ? true : null;
|
||||||
|
|
||||||
if (format.isJson()) {
|
if (format.isJson()) {
|
||||||
output.put(p.getName(), info);
|
output.put(p.getName(), info);
|
||||||
} else {
|
} else {
|
||||||
stdout.format("%-30s %-10s\n", p.getName(),
|
stdout.format("%-30s %-10s %-8s\n", p.getName(),
|
||||||
Strings.nullToEmpty(info.version));
|
Strings.nullToEmpty(info.version),
|
||||||
|
p.isDisabled() ? "DISABLED" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,5 +108,9 @@ public class ListPlugins {
|
|||||||
|
|
||||||
private static class PluginInfo {
|
private static class PluginInfo {
|
||||||
String version;
|
String version;
|
||||||
|
// disabled is only read via reflection when building the json output. We
|
||||||
|
// do not want to show a compiler error that it isn't used.
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
Boolean disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ public class Plugin {
|
|||||||
private final File dataDir;
|
private final File dataDir;
|
||||||
private final ApiType apiType;
|
private final ApiType apiType;
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
|
private final boolean disabled;
|
||||||
private Class<? extends Module> sysModule;
|
private Class<? extends Module> sysModule;
|
||||||
private Class<? extends Module> sshModule;
|
private Class<? extends Module> sshModule;
|
||||||
private Class<? extends Module> httpModule;
|
private Class<? extends Module> httpModule;
|
||||||
@@ -119,6 +120,7 @@ public class Plugin {
|
|||||||
this.dataDir = dataDir;
|
this.dataDir = dataDir;
|
||||||
this.apiType = apiType;
|
this.apiType = apiType;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
|
this.disabled = srcJar.getName().endsWith(".disabled");
|
||||||
this.sysModule = sysModule;
|
this.sysModule = sysModule;
|
||||||
this.sshModule = sshModule;
|
this.sshModule = sshModule;
|
||||||
this.httpModule = httpModule;
|
this.httpModule = httpModule;
|
||||||
@@ -165,6 +167,10 @@ public class Plugin {
|
|||||||
return snapshot.lastModified() != jar.lastModified();
|
return snapshot.lastModified() != jar.lastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDisabled() {
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
public void start(PluginGuiceEnvironment env) throws Exception {
|
public void start(PluginGuiceEnvironment env) throws Exception {
|
||||||
Injector root = newRootInjector(env);
|
Injector root = newRootInjector(env);
|
||||||
manager = new LifecycleManager();
|
manager = new LifecycleManager();
|
||||||
@@ -294,13 +300,15 @@ public class Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void add(RegistrationHandle handle) {
|
public void add(RegistrationHandle handle) {
|
||||||
if (handle instanceof ReloadableRegistrationHandle) {
|
if (manager != null) {
|
||||||
if (reloadableHandles == null) {
|
if (handle instanceof ReloadableRegistrationHandle) {
|
||||||
reloadableHandles = Lists.newArrayList();
|
if (reloadableHandles == null) {
|
||||||
|
reloadableHandles = Lists.newArrayList();
|
||||||
|
}
|
||||||
|
reloadableHandles.add((ReloadableRegistrationHandle<?>) handle);
|
||||||
}
|
}
|
||||||
reloadableHandles.add((ReloadableRegistrationHandle<?>) handle);
|
manager.add(handle);
|
||||||
}
|
}
|
||||||
manager.add(handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ReloadableRegistrationHandle<?>> getReloadableHandles() {
|
List<ReloadableRegistrationHandle<?>> getReloadableHandles() {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import java.lang.ref.ReferenceQueue;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -67,6 +68,7 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
private final PluginGuiceEnvironment env;
|
private final PluginGuiceEnvironment env;
|
||||||
private final ServerInformationImpl srvInfoImpl;
|
private final ServerInformationImpl srvInfoImpl;
|
||||||
private final ConcurrentMap<String, Plugin> running;
|
private final ConcurrentMap<String, Plugin> running;
|
||||||
|
private final ConcurrentMap<String, Plugin> disabled;
|
||||||
private final Map<String, FileSnapshot> broken;
|
private final Map<String, FileSnapshot> broken;
|
||||||
private final ReferenceQueue<ClassLoader> cleanupQueue;
|
private final ReferenceQueue<ClassLoader> cleanupQueue;
|
||||||
private final ConcurrentMap<CleanupHandle, Boolean> cleanupHandles;
|
private final ConcurrentMap<CleanupHandle, Boolean> cleanupHandles;
|
||||||
@@ -85,6 +87,7 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
env = pe;
|
env = pe;
|
||||||
srvInfoImpl = sii;
|
srvInfoImpl = sii;
|
||||||
running = Maps.newConcurrentMap();
|
running = Maps.newConcurrentMap();
|
||||||
|
disabled = Maps.newConcurrentMap();
|
||||||
broken = Maps.newHashMap();
|
broken = Maps.newHashMap();
|
||||||
cleanupQueue = new ReferenceQueue<ClassLoader>();
|
cleanupQueue = new ReferenceQueue<ClassLoader>();
|
||||||
cleanupHandles = Maps.newConcurrentMap();
|
cleanupHandles = Maps.newConcurrentMap();
|
||||||
@@ -100,8 +103,14 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterable<Plugin> getPlugins() {
|
public Iterable<Plugin> getPlugins(boolean all) {
|
||||||
return running.values();
|
if (!all) {
|
||||||
|
return running.values();
|
||||||
|
} else {
|
||||||
|
ArrayList<Plugin> plugins = new ArrayList<Plugin>(running.values());
|
||||||
|
plugins.addAll(disabled.values());
|
||||||
|
return plugins;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void installPluginFromStream(String name, InputStream in)
|
public void installPluginFromStream(String name, InputStream in)
|
||||||
@@ -178,6 +187,15 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
|
|
||||||
active.stop();
|
active.stop();
|
||||||
running.remove(name);
|
running.remove(name);
|
||||||
|
try {
|
||||||
|
FileSnapshot snapshot = FileSnapshot.save(off);
|
||||||
|
Plugin offPlugin = loadPlugin(name, off, snapshot);
|
||||||
|
disabled.put(name, offPlugin);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// This shouldn't happen, as the plugin was loaded earlier.
|
||||||
|
log.warn(String.format("Cannot load disabled plugin %s", name),
|
||||||
|
e.getCause());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cleanInBackground();
|
cleanInBackground();
|
||||||
}
|
}
|
||||||
@@ -205,6 +223,7 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
p.stop();
|
p.stop();
|
||||||
}
|
}
|
||||||
running.clear();
|
running.clear();
|
||||||
|
disabled.clear();
|
||||||
broken.clear();
|
broken.clear();
|
||||||
if (cleanupHandles.size() > running.size()) {
|
if (cleanupHandles.size() > running.size()) {
|
||||||
System.gc();
|
System.gc();
|
||||||
@@ -250,6 +269,7 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
public synchronized void rescan() {
|
public synchronized void rescan() {
|
||||||
List<File> jars = scanJarsInPluginsDirectory();
|
List<File> jars = scanJarsInPluginsDirectory();
|
||||||
stopRemovedPlugins(jars);
|
stopRemovedPlugins(jars);
|
||||||
|
dropRemovedDisabledPlugins(jars);
|
||||||
|
|
||||||
for (File jar : jars) {
|
for (File jar : jars) {
|
||||||
String name = nameOf(jar);
|
String name = nameOf(jar);
|
||||||
@@ -292,14 +312,20 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
oldPlugin.stop();
|
oldPlugin.stop();
|
||||||
running.remove(name);
|
running.remove(name);
|
||||||
}
|
}
|
||||||
newPlugin.start(env);
|
if (!newPlugin.isDisabled()) {
|
||||||
|
newPlugin.start(env);
|
||||||
|
}
|
||||||
if (reload) {
|
if (reload) {
|
||||||
env.onReloadPlugin(oldPlugin, newPlugin);
|
env.onReloadPlugin(oldPlugin, newPlugin);
|
||||||
oldPlugin.stop();
|
oldPlugin.stop();
|
||||||
} else {
|
} else if (!newPlugin.isDisabled()) {
|
||||||
env.onStartPlugin(newPlugin);
|
env.onStartPlugin(newPlugin);
|
||||||
}
|
}
|
||||||
running.put(name, newPlugin);
|
if (!newPlugin.isDisabled()) {
|
||||||
|
running.put(name, newPlugin);
|
||||||
|
} else {
|
||||||
|
disabled.put(name, newPlugin);
|
||||||
|
}
|
||||||
broken.remove(name);
|
broken.remove(name);
|
||||||
} catch (Throwable err) {
|
} catch (Throwable err) {
|
||||||
broken.put(name, snapshot);
|
broken.put(name, snapshot);
|
||||||
@@ -318,6 +344,16 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dropRemovedDisabledPlugins(List<File> jars) {
|
||||||
|
Set<String> unload = Sets.newHashSet(disabled.keySet());
|
||||||
|
for (File jar : jars) {
|
||||||
|
unload.remove(nameOf(jar));
|
||||||
|
}
|
||||||
|
for (String name : unload) {
|
||||||
|
disabled.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized int processPendingCleanups() {
|
synchronized int processPendingCleanups() {
|
||||||
CleanupHandle h;
|
CleanupHandle h;
|
||||||
while ((h = (CleanupHandle) cleanupQueue.poll()) != null) {
|
while ((h = (CleanupHandle) cleanupQueue.poll()) != null) {
|
||||||
@@ -336,6 +372,9 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
|
|
||||||
private static String nameOf(File jar) {
|
private static String nameOf(File jar) {
|
||||||
String name = jar.getName();
|
String name = jar.getName();
|
||||||
|
if (name.endsWith(".disabled")) {
|
||||||
|
name = name.substring(0, name.lastIndexOf('.'));
|
||||||
|
}
|
||||||
int ext = name.lastIndexOf('.');
|
int ext = name.lastIndexOf('.');
|
||||||
return 0 < ext ? name.substring(0, ext) : name;
|
return 0 < ext ? name.substring(0, ext) : name;
|
||||||
}
|
}
|
||||||
@@ -430,7 +469,9 @@ public class PluginLoader implements LifecycleListener {
|
|||||||
File[] matches = pluginsDir.listFiles(new FileFilter() {
|
File[] matches = pluginsDir.listFiles(new FileFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File pathname) {
|
public boolean accept(File pathname) {
|
||||||
return pathname.getName().endsWith(".jar") && pathname.isFile();
|
String n = pathname.getName();
|
||||||
|
return (n.endsWith(".jar") || n.endsWith(".jar.disabled"))
|
||||||
|
&& pathname.isFile();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (matches == null) {
|
if (matches == null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user