Skip to content

Commit

Permalink
[JENKINS-27177] Add strategies to disable plugins. Move process to core
Browse files Browse the repository at this point in the history
Move the process to core to be reusable, not only for the cli command.
Add optionalDependants list to PluginWrapper to process them easily.

Replace (depreacate) the disable method without checks by this one with
strategies.

Improve messages and tests
  • Loading branch information
MRamonLeon committed Oct 15, 2018
1 parent 18be196 commit fe8d0d5
Show file tree
Hide file tree
Showing 9 changed files with 679 additions and 175 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ out
.project
build

# VSCode workspace file
*.code-workspace

# vim
*~
*.swp
Expand Down
143 changes: 65 additions & 78 deletions core/src/main/java/hudson/PluginManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,47 +25,29 @@

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.security.ACLContext;
import jenkins.ExtensionRefreshException;
import jenkins.util.SystemProperties;
import hudson.PluginWrapper.Dependency;
import hudson.init.InitMilestone;
import hudson.init.InitStrategy;
import hudson.init.InitializerFinder;
import hudson.model.AbstractItem;
import hudson.model.AbstractModelObject;
import hudson.model.AdministrativeMonitor;
import hudson.model.Api;
import hudson.model.Descriptor;
import hudson.model.Failure;
import hudson.model.ItemGroupMixIn;
import hudson.model.UpdateCenter;
import hudson.model.UpdateSite;
import hudson.model.*;
import hudson.model.UpdateCenter.DownloadJob;
import hudson.model.UpdateCenter.InstallationJob;
import hudson.security.ACL;
import hudson.security.ACLContext;
import hudson.security.Permission;
import hudson.security.PermissionScope;
import hudson.util.CyclicGraphDetector;
import hudson.util.*;
import hudson.util.CyclicGraphDetector.CycleDetectedException;
import hudson.util.PersistedList;
import hudson.util.Service;
import hudson.util.VersionNumber;
import hudson.util.XStream2;
import jenkins.ClassLoaderReflectionToolkit;
import jenkins.InitReactorRunner;
import jenkins.MissingDependencyException;
import jenkins.RestartRequiredException;
import jenkins.YesNoMaybe;
import jenkins.*;
import jenkins.install.InstallState;
import jenkins.install.InstallUtil;
import jenkins.model.Jenkins;
import jenkins.security.CustomClassFilter;
import jenkins.util.SystemProperties;
import jenkins.util.io.OnMaster;
import jenkins.util.xml.RestrictiveEntityResolver;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.acegisecurity.Authentication;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
Expand All @@ -78,84 +60,44 @@
import org.apache.commons.logging.LogFactory;
import org.jenkinsci.Symbol;
import org.jenkinsci.bytecode.Transformer;
import org.jvnet.hudson.reactor.Executable;
import org.jvnet.hudson.reactor.Reactor;
import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.reactor.TaskBuilder;
import org.jvnet.hudson.reactor.TaskGraphBuilder;
import org.jvnet.hudson.reactor.*;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.HttpRedirect;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.*;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerOverridable;
import org.kohsuke.stapler.StaplerProxy;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import java.io.Closeable;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.net.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import static hudson.init.InitMilestone.*;
import hudson.model.DownloadService;
import hudson.util.FormValidation;
import java.io.ByteArrayInputStream;
import java.net.JarURLConnection;
import java.net.URLConnection;
import java.util.ServiceLoader;
import java.util.function.Supplier;
import java.util.jar.JarEntry;

import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import jenkins.security.CustomClassFilter;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import static java.util.logging.Level.*;

/**
* Manages {@link PluginWrapper}s.
Expand Down Expand Up @@ -935,8 +877,15 @@ protected boolean filter(Method e) {
@Restricted(NoExternalUse.class)
public synchronized void resolveDependantPlugins() {
for (PluginWrapper plugin : plugins) {
// Set of optional dependants plugins of plugin
Set<String> optionalDependants = new HashSet<>();
Set<String> dependants = new HashSet<>();
for (PluginWrapper possibleDependant : plugins) {
// No need to check if plugin is dependant of itself
if(possibleDependant.getShortName().equals(plugin.getShortName())) {
continue;
}

// The plugin could have just been deleted. If so, it doesn't
// count as a dependant.
if (possibleDependant.isDeleted()) {
Expand All @@ -946,10 +895,20 @@ public synchronized void resolveDependantPlugins() {
for (Dependency dependency : dependencies) {
if (dependency.shortName.equals(plugin.getShortName())) {
dependants.add(possibleDependant.getShortName());

// If, in addition, the dependency is optional, add to the optionalDependants list
if (dependency.optional) {
optionalDependants.add(possibleDependant.getShortName());
}

// already know possibleDependant depends on plugin, no need to continue with the rest of
// dependencies. We continue with the next possibleDependant
break;
}
}
}
plugin.setDependants(dependants);
plugin.setOptionalDependants(optionalDependants);
}
}

Expand Down Expand Up @@ -1829,6 +1788,34 @@ public MetadataCache createCache() {
return new MetadataCache();
}

/**
* Disable a list of plugins using a strategy for its dependants plugins.
* @param strategy the strategy regarding how the dependant plugins are processed
* @param plugins the list of plugins
* @return the list of results for every plugin and its dependant plugins.
* @throws IOException see {@link PluginWrapper#disable()}
*/
public List<PluginWrapper.PluginDisableResult> disablePlugins(PluginWrapper.PluginDisableStrategy strategy, List<String> plugins) throws IOException {
// Where we store the results of each plugin disablement
List<PluginWrapper.PluginDisableResult> results = new ArrayList<>(plugins.size());

// Disable all plugins passed
for (String pluginName : plugins) {
PluginWrapper plugin = this.getPlugin(pluginName);

if (plugin == null) {
PluginWrapper.PluginDisableResult result = new PluginWrapper.PluginDisableResult(pluginName);
result.setMessage(Messages.PluginWrapper_NoSuchPlugin(pluginName));
result.setStatus(PluginWrapper.PluginDisableStatus.NO_SUCH_PLUGIN);
results.add(result);
} else {
results.add(plugin.disable(strategy));
}
}

return results;
}

@Restricted(NoExternalUse.class) // table.jelly
public static final class MetadataCache {
private final Map<String, Object> data = new HashMap<>();
Expand Down
Loading

0 comments on commit fe8d0d5

Please sign in to comment.