Basic implementation of prevalidateConfig working.

This commit is contained in:
Jesse Glick committed 2012-09-14 14:56:10 -04:00
1 parent fe6dbcd779
commit 2658f36994
3 files changed
+119 -2

No files matched your search

+80 -2
View File
@@ -98,6 +98,12 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import static hudson.init.InitMilestone.*;
import hudson.util.VersionNumber;
import java.util.TreeMap;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Manages {@link PluginWrapper}s.
@@ -740,7 +746,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
* If the configuration (typically a job’s {@code config.xml})
* needs some plugins to be installed (or updated), those jobs
* will be triggered.
* Plugins are dynamically loaded if possible (see {@link hudson.model.UpdateSite.Plugin#deploy(boolean)}).
* Plugins are dynamically loaded whenever possible.
* Requires {@link Jenkins#ADMINISTER}.
* @param configXml configuration that might be uploaded
* @return an empty list if all is well, else a list of submitted jobs which must be completed before this configuration can be fully read
@@ -748,11 +754,83 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
* @see ItemGroupMixIn#createProjectFromXML
* @see AbstractItem#updateByXml(javax.xml.transform.Source)
* @see XStream2
* @see hudson.model.UpdateSite.Plugin#deploy(boolean)
* @see PluginWrapper#supportsDynamicLoad
* @see hudson.model.UpdateCenter.DownloadJob.SuccessButRequiresRestart
* @since XXX
*/
public List<Future<UpdateCenter.UpdateCenterJob>> prevalidateConfig(InputStream configXml) throws IOException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
return Collections.emptyList(); // XXX
List<Future<UpdateCenter.UpdateCenterJob>> jobs = new ArrayList<Future<UpdateCenter.UpdateCenterJob>>();
UpdateCenter uc = Jenkins.getInstance().getUpdateCenter();
// XXX call uc.updateAllSites() when available? perhaps not, since we should not block on network here
for (Map.Entry<String,VersionNumber> requestedPlugin : parseRequestedPlugins(configXml).entrySet()) {
PluginWrapper pw = getPlugin(requestedPlugin.getKey());
if (pw == null) { // install new
UpdateSite.Plugin toInstall = uc.getPlugin(requestedPlugin.getKey());
if (toInstall == null) {
LOGGER.log(Level.WARNING, "No such plugin {0} to install", requestedPlugin.getKey());
continue;
}
if (new VersionNumber(toInstall.version).compareTo(requestedPlugin.getValue()) < 0) {
LOGGER.log(Level.WARNING, "{0} can only be satisfied in @{1}", new Object[] {requestedPlugin, toInstall.version});
}
if (toInstall.isForNewerHudson()) {
LOGGER.log(Level.WARNING, "{0}@{1} was built for a newer Jenkins", new Object[] {toInstall.name, toInstall.version});
}
jobs.add(toInstall.deploy(true));
} else if (pw.isOlderThan(requestedPlugin.getValue())) { // upgrade
UpdateSite.Plugin toInstall = uc.getPlugin(requestedPlugin.getKey());
if (toInstall == null) {
LOGGER.log(Level.WARNING, "No such plugin {0} to upgrade", requestedPlugin.getKey());
continue;
}
if (!pw.isOlderThan(new VersionNumber(toInstall.version))) {
LOGGER.log(Level.WARNING, "{0}@{1} is no newer than what we already have", new Object[] {toInstall.name, toInstall.version});
continue;
}
if (new VersionNumber(toInstall.version).compareTo(requestedPlugin.getValue()) < 0) {
LOGGER.log(Level.WARNING, "{0} can only be satisfied in @{1}", new Object[] {requestedPlugin, toInstall.version});
}
if (toInstall.isForNewerHudson()) {
LOGGER.log(Level.WARNING, "{0}@{1} was built for a newer Jenkins", new Object[] {toInstall.name, toInstall.version});
}
if (!toInstall.isCompatibleWithInstalledVersion()) {
LOGGER.log(Level.WARNING, "{0}@{1} is incompatible with the installed @{2}", new Object[] {toInstall.name, toInstall.version, pw.getVersion()});
}
jobs.add(toInstall.deploy(true)); // dynamicLoad=true => sure to throw RestartRequiredException, but at least message is nicer
} // else already good
}
return jobs;
}
static Map<String,VersionNumber> parseRequestedPlugins(InputStream configXml) throws IOException {
final Map<String,VersionNumber> requestedPlugins = new TreeMap<String,VersionNumber>();
try {
SAXParserFactory.newInstance().newSAXParser().parse(configXml, new DefaultHandler() {
@Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
String plugin = attributes.getValue("plugin");
if (plugin == null) {
return;
}
if (!plugin.matches("[^@]+@[^@]+")) {
throw new SAXException("Malformed plugin attribute: " + plugin);
}
int at = plugin.indexOf('@');
String shortName = plugin.substring(0, at);
VersionNumber existing = requestedPlugins.get(shortName);
VersionNumber requested = new VersionNumber(plugin.substring(at + 1));
if (existing == null || existing.compareTo(requested) < 0) {
requestedPlugins.put(shortName, requested);
}
}
});
} catch (IOException x) {
throw x;
} catch (Exception x) {
throw (IOException) new IOException(x.toString()).initCause(x);
}
return requestedPlugins;
}
/**