/** * Like {@link #doInstallNecessaryPlugins(StaplerRequest)} but only checks if everything is * installed or if some plugins need updates or installation. * * <p>This method runs without side-effect. I'm still requiring the ADMINISTER permission since * XML file can contain various external references and we don't configure parsers properly * against that. * * @since 1.483 */ @RequirePOST public JSONArray doPrevalidateConfig(StaplerRequest req) throws IOException { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); JSONArray response = new JSONArray(); for (Map.Entry<String, VersionNumber> p : parseRequestedPlugins(req.getInputStream()).entrySet()) { PluginWrapper pw = getPlugin(p.getKey()); JSONObject j = new JSONObject() .accumulate("name", p.getKey()) .accumulate("version", p.getValue().toString()); if (pw == null) { // install new response.add(j.accumulate("mode", "missing")); } else if (pw.isOlderThan(p.getValue())) { // upgrade response.add(j.accumulate("mode", "old")); } // else already good } return response; }
/** * Prepares plugins for some expected XML configuration. 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 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 * @throws IOException if loading or parsing the configuration failed * @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 1.483 */ public List<Future<UpdateCenter.UpdateCenterJob>> prevalidateConfig(InputStream configXml) throws IOException { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); List<Future<UpdateCenter.UpdateCenterJob>> jobs = new ArrayList<Future<UpdateCenter.UpdateCenterJob>>(); UpdateCenter uc = Jenkins.getInstance().getUpdateCenter(); // TODO 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(WARNING, "No such plugin {0} to install", requestedPlugin.getKey()); continue; } if (new VersionNumber(toInstall.version).compareTo(requestedPlugin.getValue()) < 0) { LOGGER.log( WARNING, "{0} can only be satisfied in @{1}", new Object[] {requestedPlugin, toInstall.version}); } if (toInstall.isForNewerHudson()) { LOGGER.log( 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(WARNING, "No such plugin {0} to upgrade", requestedPlugin.getKey()); continue; } if (!pw.isOlderThan(new VersionNumber(toInstall.version))) { LOGGER.log( 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( WARNING, "{0} can only be satisfied in @{1}", new Object[] {requestedPlugin, toInstall.version}); } if (toInstall.isForNewerHudson()) { LOGGER.log( WARNING, "{0}@{1} was built for a newer Jenkins", new Object[] {toInstall.name, toInstall.version}); } if (!toInstall.isCompatibleWithInstalledVersion()) { LOGGER.log( 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; }