提交 2658f369 编写于 作者: J Jesse Glick

Basic implementation of prevalidateConfig working.

上级 fe6dbcd7
......@@ -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;
}
/**
......
/*
* The MIT License
*
* Copyright 2012 Jesse Glick.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson;
import org.apache.tools.ant.filters.StringInputStream;
import org.junit.Test;
import static org.junit.Assert.*;
public class PluginManagerTest {
@Test public void parseRequestedPlugins() throws Exception {
assertEquals("{other=2.0, stuff=1.2}", PluginManager.parseRequestedPlugins(new StringInputStream("<root><stuff plugin='stuff@1.0'><more plugin='other@2.0'><things plugin='stuff@1.2'/></more></stuff></root>")).toString());
}
}
......@@ -231,6 +231,8 @@ public class PluginManagerTest extends HudsonTestCase {
UpdateCenter.InstallationJob ijob = (UpdateCenter.InstallationJob) job;
assertEquals("tasks", ijob.plugin.name);
assertNotNull(jenkins.getPluginManager().getPlugin("tasks"));
// XXX restart scheduled (SuccessButRequiresRestart) after upgrade or Support-Dynamic-Loading: false
// XXX dependencies installed or upgraded too
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册