From aad6e4c66c3f50a0f6da104fded2913f4a064cf3 Mon Sep 17 00:00:00 2001 From: imod Date: Sun, 19 Feb 2012 18:29:53 +0100 Subject: [PATCH] only deactivate plugins with cycle dependencies instead of failing to launch Jenkins --- core/src/main/java/hudson/PluginManager.java | 42 +++++++++++++++++++ core/src/main/java/hudson/PluginWrapper.java | 14 ++++++- .../java/hudson/util/CyclicGraphDetector.java | 15 ++++++- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index b7a7a7f6c5..375328cd1d 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -28,10 +28,12 @@ import hudson.init.InitMilestone; import hudson.init.InitStrategy; import hudson.init.InitializerFinder; import hudson.model.AbstractModelObject; +import hudson.model.AdministrativeMonitor; import hudson.model.Descriptor; import hudson.model.Failure; import hudson.model.UpdateCenter; import hudson.model.UpdateSite; +import hudson.model.UpdateSite.Data; import hudson.util.CyclicGraphDetector; import hudson.util.CyclicGraphDetector.CycleDetectedException; import hudson.util.FormValidation; @@ -243,6 +245,18 @@ public abstract class PluginManager extends AbstractModelObject { r.add(p); } } + + @Override + protected void reactOnCycle(PluginWrapper q, List cycle) + throws hudson.util.CyclicGraphDetector.CycleDetectedException { + + LOGGER.log(Level.SEVERE, "found cycle in plugin dependencies: (root="+q+", deactivating all involved) "+Util.join(cycle," -> ")); + for (PluginWrapper pluginWrapper : cycle) { + pluginWrapper.setHasCycleDependency(true); + failedPlugins.add(new FailedPlugin(pluginWrapper.getShortName(), new CycleDetectedException(cycle))); + } + } + }; cgd.run(getPlugins()); @@ -810,4 +824,32 @@ public abstract class PluginManager extends AbstractModelObject { /*package*/ static final class PluginInstanceStore { final Map store = new Hashtable(); } + + /** + * {@link AdministrativeMonitor} that checks if there's Jenkins update. + */ + @Extension + public static final class PluginCycleDependenciesMonitor extends AdministrativeMonitor { + + private transient volatile boolean isActive = false; + + private transient volatile List pluginsWithCycle; + + public boolean isActivated() { + if(pluginsWithCycle == null){ + pluginsWithCycle = new ArrayList(); + for (PluginWrapper p : Jenkins.getInstance().getPluginManager().getPlugins()) { + if(p.hasCycleDependency()){ + pluginsWithCycle.add(p.getShortName()); + isActive = true; + } + } + } + return true; + } + + public List getPluginsWithCycle() { + return pluginsWithCycle; + } + } } diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index aa51b0a2b8..c105393695 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -125,6 +125,8 @@ public class PluginWrapper implements Comparable { * The snapshot of disableFile.exists() as of the start up. */ private final boolean active; + + private boolean hasCycleDependency = false; private final List dependencies; private final List optionalDependencies; @@ -276,6 +278,8 @@ public class PluginWrapper implements Comparable { return null; } + + @Override public String toString() { @@ -379,9 +383,17 @@ public class PluginWrapper implements Comparable { * Returns true if this plugin is enabled for this session. */ public boolean isActive() { - return active; + return active && !hasCycleDependency(); + } + + public boolean hasCycleDependency(){ + return hasCycleDependency; } + public void setHasCycleDependency(boolean hasCycle){ + hasCycleDependency = hasCycle; + } + public boolean isBundled() { return isBundled; } diff --git a/core/src/main/java/hudson/util/CyclicGraphDetector.java b/core/src/main/java/hudson/util/CyclicGraphDetector.java index 7999e558ca..74f7fdeb48 100644 --- a/core/src/main/java/hudson/util/CyclicGraphDetector.java +++ b/core/src/main/java/hudson/util/CyclicGraphDetector.java @@ -23,8 +23,9 @@ public abstract class CyclicGraphDetector { private final List topologicalOrder = new ArrayList(); public void run(Iterable allNodes) throws CycleDetectedException { - for (N n : allNodes) + for (N n : allNodes){ visit(n); + } } /** @@ -62,8 +63,18 @@ public abstract class CyclicGraphDetector { private void detectedCycle(N q) throws CycleDetectedException { int i = path.indexOf(q); path.push(q); - throw new CycleDetectedException(path.subList(i, path.size())); + reactOnCycle(q, path.subList(i, path.size())); } + + /** + * React on detected cycles - default implementation throws an exception. + * @param q + * @param cycle + * @throws CycleDetectedException + */ + protected void reactOnCycle(N q, List cycle) throws CycleDetectedException{ + throw new CycleDetectedException(cycle); + } public static final class CycleDetectedException extends Exception { public final List cycle; -- GitLab