提交 7d7e8d98 编写于 作者: V valentina

Merge pull request #1972 from varmenise/JENKINS-32328

 [FIXED JENKINS-32328] process multiple update-centers for ToolInstallers
......@@ -38,8 +38,11 @@ import static hudson.util.TimeUnit2.DAYS;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.model.DownloadSettings;
......@@ -301,6 +304,24 @@ public class DownloadService extends PageDecorator {
return Jenkins.getInstance().getUpdateCenter().getDefaultBaseUrl()+"updates/"+url;
}
/**
* URLs to download from.
*/
public List<String> getUrls() {
List<String> updateSites = new ArrayList<String>();
for (UpdateSite site : Jenkins.getActiveInstance().getUpdateCenter().getSiteList()) {
String siteUrl = site.getUrl();
int baseUrlEnd = siteUrl.indexOf("update-center.json");
if (baseUrlEnd != -1) {
String siteBaseUrl = siteUrl.substring(0, baseUrlEnd);
updateSites.add(siteBaseUrl + "updates/" + url);
} else {
LOGGER.log(Level.WARNING, "Url {0} does not look like an update center:", siteUrl);
}
}
return updateSites;
}
/**
* How often do we retrieve the new image?
*
......@@ -364,15 +385,6 @@ public class DownloadService extends PageDecorator {
}
private FormValidation load(String json, long dataTimestamp) throws IOException {
JSONObject o = JSONObject.fromObject(json);
if (signatureCheck) {
FormValidation e = new JSONSignatureValidator("downloadable '"+id+"'").verifySignature(o);
if (e.kind!= Kind.OK) {
return e;
}
}
TextFile df = getDataFile();
df.write(json);
df.file.setLastModified(dataTimestamp);
......@@ -382,7 +394,72 @@ public class DownloadService extends PageDecorator {
@Restricted(NoExternalUse.class)
public FormValidation updateNow() throws IOException {
return load(loadJSONHTML(new URL(getUrl() + ".html?id=" + URLEncoder.encode(getId(), "UTF-8") + "&version=" + URLEncoder.encode(Jenkins.VERSION, "UTF-8"))), System.currentTimeMillis());
List<JSONObject> jsonList = new ArrayList<>();
for (String site : getUrls()) {
String jsonString;
try {
jsonString = loadJSONHTML(new URL(site + ".html?id=" + URLEncoder.encode(getId(), "UTF-8") + "&version=" + URLEncoder.encode(Jenkins.VERSION, "UTF-8")));
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Could not load json from " + site, e );
continue;
}
JSONObject o = JSONObject.fromObject(jsonString);
if (signatureCheck) {
FormValidation e = new JSONSignatureValidator("downloadable '"+id+"'").verifySignature(o);
if (e.kind!= Kind.OK) {
continue;
}
}
jsonList.add(o);
}
if (jsonList.size() == 0) {
return FormValidation.warning("None of the Update Sites passed the signature check");
}
JSONObject reducedJson = reduce(jsonList);
return load(reducedJson.toString(), System.currentTimeMillis());
}
/**
* Function that takes multiple JSONObjects and returns a single one.
* @param jsonList to be processed
* @return a single JSONObject
*/
public JSONObject reduce(List<JSONObject> jsonList) {
return jsonList.get(0);
}
/**
* check if the list of update center entries has duplicates
* @param genericList list of entries coming from multiple update centers
* @param comparator the unique ID of an entry
* @param <T> the generic class
* @return true if the list has duplicates, false otherwise
*/
public static <T> boolean hasDuplicates (List<T> genericList, String comparator) {
if (genericList.isEmpty()) {
return false;
}
Field field;
try {
field = genericList.get(0).getClass().getDeclaredField(comparator);
} catch (NoSuchFieldException e) {
LOGGER.warning("comparator: " + comparator + "does not exist for " + genericList.get(0).getClass() + ", " + e);
return false;
}
for (int i = 0; i < genericList.size(); i ++ ) {
T data1 = genericList.get(i);
for (int j = i + 1; j < genericList.size(); j ++ ) {
T data2 = genericList.get(j);
try {
if (field.get(data1).equals(field.get(data2))) {
return true;
}
} catch (IllegalAccessException e) {
LOGGER.warning("could not access field: " + comparator + ", " + e);
}
}
}
return false;
}
/**
......
......@@ -10,6 +10,7 @@ import net.sf.json.JSONObject;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.net.URL;
......@@ -126,10 +127,94 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller {
Downloadable.all().add(createDownloadable());
}
protected Downloadable createDownloadable() {
/**
* function that creates a {@link Downloadable}.
* @return a downloadable object
*/
public Downloadable createDownloadable() {
if (this instanceof DownloadFromUrlInstaller.DescriptorImpl) {
final DownloadFromUrlInstaller.DescriptorImpl delegate = (DownloadFromUrlInstaller.DescriptorImpl)this;
return new Downloadable(getId()) {
public JSONObject reduce(List<JSONObject> jsonList) {
if (isDefualtSchema(jsonList)) {
return delegate.reduce(jsonList);
} else {
//if it's not default schema fall back to the super class implementation
return super.reduce(jsonList);
}
}
};
}
return new Downloadable(getId());
}
/**
* this function checks is the update center tool has the default schema
* @param jsonList the list of Update centers json files
* @return true if the schema is the default one (id, name, url), false otherwise
*/
private boolean isDefualtSchema(List<JSONObject> jsonList) {
JSONObject jsonToolInstallerList = jsonList.get(0);
ToolInstallerList toolInstallerList = (ToolInstallerList) JSONObject.toBean(jsonToolInstallerList, ToolInstallerList.class);
if (toolInstallerList != null) {
ToolInstallerEntry[] entryList = toolInstallerList.list;
ToolInstallerEntry sampleEntry = entryList[0];
if (sampleEntry != null) {
if (sampleEntry.id != null && sampleEntry.name != null && sampleEntry.url != null) {
return true;
}
}
}
return false;
}
private JSONObject reduce(List<JSONObject> jsonList) {
List<ToolInstallerEntry> reducedToolEntries = new LinkedList<>();
//collect all tool installers objects from the multiple json objects
for (JSONObject jsonToolList : jsonList) {
ToolInstallerList toolInstallerList = (ToolInstallerList) JSONObject.toBean(jsonToolList, ToolInstallerList.class);
reducedToolEntries.addAll(Arrays.asList(toolInstallerList.list));
}
while (Downloadable.hasDuplicates(reducedToolEntries, "id")) {
List<ToolInstallerEntry> tmpToolInstallerEntries = new LinkedList<>();
//we need to skip the processed entries
boolean processed[] = new boolean[reducedToolEntries.size()];
for (int i = 0; i < reducedToolEntries.size(); i++) {
if (processed[i] == true) {
continue;
}
ToolInstallerEntry data1 = reducedToolEntries.get(i);
boolean hasDuplicate = false;
for (int j = i + 1; j < reducedToolEntries.size(); j ++) {
ToolInstallerEntry data2 = reducedToolEntries.get(j);
//if we found a duplicate we choose the first one
if (data1.id.equals(data2.id)) {
hasDuplicate = true;
processed[j] = true;
tmpToolInstallerEntries.add(data1);
//after the first duplicate has been found we break the loop since the duplicates are
//processed two by two
break;
}
}
//if no duplicate has been found we just insert the entry in the tmp list
if (!hasDuplicate) {
tmpToolInstallerEntries.add(data1);
}
}
reducedToolEntries = tmpToolInstallerEntries;
}
ToolInstallerList toolInstallerList = new ToolInstallerList();
toolInstallerList.list = new ToolInstallerEntry[reducedToolEntries.size()];
reducedToolEntries.toArray(toolInstallerList.list);
JSONObject reducedToolEntriesJsonList = JSONObject.fromObject(toolInstallerList);
//return the list with no duplicates
return reducedToolEntriesJsonList;
}
/**
* This ID needs to be unique, and needs to match the ID token in the JSON update file.
* <p>
......
......@@ -32,6 +32,7 @@ import hudson.ProxyConfiguration;
import hudson.Util;
import hudson.model.DownloadService.Downloadable;
import hudson.model.JDK;
import hudson.model.Job;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.util.ArgumentListBuilder;
......@@ -41,6 +42,7 @@ import hudson.util.Secret;
import jenkins.model.Jenkins;
import jenkins.security.MasterToSlaveCallable;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
......@@ -69,6 +71,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
......@@ -669,8 +672,8 @@ public class JDKInstaller extends ToolInstaller {
}
public static final class JDKFamilyList {
public int version;
public JDKFamily[] data = new JDKFamily[0];
public int version;
public boolean isEmpty() {
for (JDKFamily f : data) {
......@@ -697,6 +700,18 @@ public class JDKInstaller extends ToolInstaller {
}
public static final class JDKRelease {
/**
* the list of {@Link JDKFile}s
*/
public JDKFile[] files;
/**
* the license path
*/
public String licpath;
/**
* the license title
*/
public String lictitle;
/**
* This maps to the former product code, like "jdk-6u13-oth-JPR"
*/
......@@ -705,7 +720,6 @@ public class JDKInstaller extends ToolInstaller {
* This is human readable.
*/
public String title;
public JDKFile[] files;
/**
* We used to use IDs like "jdk-6u13-oth-JPR@CDS-CDS_Developer", but Oracle switched to just "jdk-6u13-oth-JPR".
......@@ -717,9 +731,9 @@ public class JDKInstaller extends ToolInstaller {
}
public static final class JDKFile {
public String filepath;
public String name;
public String title;
public String filepath;
}
@Override
......@@ -802,6 +816,123 @@ public class JDKInstaller extends ToolInstaller {
if(d==null) return new JDKFamilyList();
return (JDKFamilyList)JSONObject.toBean(d,JDKFamilyList.class);
}
/**
* @{inheritDoc}
*/
@Override
public JSONObject reduce (List<JSONObject> jsonObjectList) {
List<JDKFamily> reducedFamilies = new LinkedList<>();
int version = 0;
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerPropertyExclusion(JDKFamilyList.class, "empty");
jsonConfig.setRootClass(JDKFamilyList.class);
//collect all JDKFamily objects from the multiple json objects
for (JSONObject jsonJdkFamilyList : jsonObjectList) {
JDKFamilyList jdkFamilyList = (JDKFamilyList)JSONObject.toBean(jsonJdkFamilyList, jsonConfig);
if (version == 0) {
//we set as version the version of the first update center
version = jdkFamilyList.version;
}
JDKFamily[] jdkFamilies = jdkFamilyList.data;
reducedFamilies.addAll(Arrays.asList(jdkFamilies));
}
//we iterate on the list and reduce it until there are no more duplicates
//this could be made recursive
while (hasDuplicates(reducedFamilies, "name")) {
//create a temporary list to store the tmp result
List<JDKFamily> tmpReducedFamilies = new LinkedList<>();
//we need to skip the processed families
boolean processed [] = new boolean[reducedFamilies.size()];
for (int i = 0; i < reducedFamilies.size(); i ++ ) {
if (processed [i] == true) {
continue;
}
JDKFamily data1 = reducedFamilies.get(i);
boolean hasDuplicate = false;
for (int j = i + 1; j < reducedFamilies.size(); j ++ ) {
JDKFamily data2 = reducedFamilies.get(j);
//if we found a duplicate we need to merge the families
if (data1.name.equals(data2.name)) {
hasDuplicate = true;
processed [j] = true;
JDKFamily reducedData = reduceData(data1.name, new LinkedList<JDKRelease>(Arrays.asList(data1.releases)), new LinkedList<JDKRelease>(Arrays.asList(data2.releases)));
tmpReducedFamilies.add(reducedData);
//after the first duplicate has been found we break the loop since the duplicates are
//processed two by two
break;
}
}
//if no duplicate has been found we just insert the whole family in the tmp list
if (!hasDuplicate) {
tmpReducedFamilies.add(data1);
}
}
reducedFamilies = tmpReducedFamilies;
}
JDKFamilyList jdkFamilyList = new JDKFamilyList();
jdkFamilyList.version = version;
jdkFamilyList.data = new JDKFamily[reducedFamilies.size()];
reducedFamilies.toArray(jdkFamilyList.data);
JSONObject reducedJdkFamilyList = JSONObject.fromObject(jdkFamilyList, jsonConfig);
//return the list with no duplicates
return reducedJdkFamilyList;
}
private JDKFamily reduceData(String name, List<JDKRelease> releases1, List<JDKRelease> releases2) {
LinkedList<JDKRelease> reducedReleases = new LinkedList<>();
for (Iterator<JDKRelease> iterator = releases1.iterator(); iterator.hasNext(); ) {
JDKRelease release1 = iterator.next();
boolean hasDuplicate = false;
for (Iterator<JDKRelease> iterator2 = releases2.iterator(); iterator2.hasNext(); ) {
JDKRelease release2 = iterator2.next();
if (release1.name.equals(release2.name)) {
hasDuplicate = true;
JDKRelease reducedRelease = reduceReleases(release1, new LinkedList<JDKFile>(Arrays.asList(release1.files)), new LinkedList<JDKFile>(Arrays.asList(release2.files)));
iterator2.remove();
reducedReleases.add(reducedRelease);
//we assume that in one release list there are no duplicates so we stop at the first one
break;
}
}
if (!hasDuplicate) {
reducedReleases.add(release1);
}
}
reducedReleases.addAll(releases2);
JDKFamily reducedFamily = new JDKFamily();
reducedFamily.name = name;
reducedFamily.releases = new JDKRelease[reducedReleases.size()];
reducedReleases.toArray(reducedFamily.releases);
return reducedFamily;
}
private JDKRelease reduceReleases(JDKRelease release, List<JDKFile> files1, List<JDKFile> files2) {
LinkedList<JDKFile> reducedFiles = new LinkedList<>();
for (Iterator<JDKFile> iterator1 = files1.iterator(); iterator1.hasNext(); ) {
JDKFile file1 = iterator1.next();
for (Iterator<JDKFile> iterator2 = files2.iterator(); iterator2.hasNext(); ) {
JDKFile file2 = iterator2.next();
if (file1.name.equals(file2.name)) {
iterator2.remove();
//we assume the in one file list there are no duplicates so we break after we find the
//first match
break;
}
}
}
reducedFiles.addAll(files1);
reducedFiles.addAll(files2);
JDKRelease jdkRelease = new JDKRelease();
jdkRelease.files = new JDKFile[reducedFiles.size()];
reducedFiles.toArray(jdkRelease.files);
jdkRelease.name = release.name;
jdkRelease.licpath = release.licpath;
jdkRelease.lictitle = release.lictitle;
jdkRelease.title = release.title;
return jdkRelease;
}
}
private static final Logger LOGGER = Logger.getLogger(JDKInstaller.class.getName());
......
......@@ -36,6 +36,8 @@ import hudson.model.TaskListener;
import java.io.File;
import java.io.IOException;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundConstructor;
/**
......@@ -129,4 +131,47 @@ public abstract class ToolInstaller implements Describable<ToolInstaller>, Exten
public ToolInstallerDescriptor<?> getDescriptor() {
return (ToolInstallerDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass());
}
@Restricted(NoExternalUse.class)
public static final class ToolInstallerList {
/**
* the list of {@link ToolInstallerEntry}
*/
public ToolInstallerEntry [] list;
}
@Restricted(NoExternalUse.class)
public static final class ToolInstallerEntry {
/**
* the id of the of the release entry
*/
public String id;
/**
* the name of the release entry
*/
public String name;
/**
* the url of the release
*/
public String url;
/**
* public default constructor needed by the JSON parser
*/
public ToolInstallerEntry() {
}
/**
* The constructor
* @param id the id of the release
* @param name the name of the release
* @param url the URL of thr release
*/
public ToolInstallerEntry (String id, String name, String url) {
this.id = id;
this.name = name;
this.url = url;
}
}
}
......@@ -3,8 +3,15 @@ package hudson.model;
import hudson.model.DownloadService.Downloadable;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import hudson.tasks.Maven;
import hudson.tools.DownloadFromUrlInstaller;
import hudson.tools.JDKInstaller;
import hudson.tools.ToolInstallation;
import jenkins.model.DownloadSettings;
import net.sf.json.JSONObject;
import org.jvnet.hudson.test.Issue;
......@@ -36,20 +43,12 @@ public class DownloadServiceTest extends HudsonTestCase {
@Issue("JENKINS-5536")
public void testPost() throws Exception {
// initially it should fail because the data doesn't have a signature
assertNull(job.getData());
// we do not save with signature for toolInstallers,
//neither we check it in the getData method.
createWebClient().goTo("/self/testPost");
assertNull(job.getData());
// and now it should work
DownloadService.signatureCheck = false;
try {
createWebClient().goTo("/self/testPost");
JSONObject d = job.getData();
assertEquals(hashCode(),d.getInt("hello"));
} finally {
DownloadService.signatureCheck = true;
}
JSONObject d = job.getData();
assertEquals(hashCode(),d.getInt("hello"));
// TODO: test with a signature
}
......@@ -77,4 +76,89 @@ public class DownloadServiceTest extends HudsonTestCase {
assertEquals(expected, new TreeSet<String>(keySet).toString());
}
public void testReduceFunctionWithMavenJsons() throws Exception {
URL resource1 = DownloadServiceTest.class.getResource("hudson.tasks.Maven.MavenInstaller1.json");
URL resource2 = DownloadServiceTest.class.getResource("hudson.tasks.Maven.MavenInstaller2.json");
URL resource3 = DownloadServiceTest.class.getResource("hudson.tasks.Maven.MavenInstaller3.json");
JSONObject json1 = JSONObject.fromObject(DownloadService.loadJSON(resource1));
JSONObject json2 = JSONObject.fromObject(DownloadService.loadJSON(resource2));
JSONObject json3 = JSONObject.fromObject(DownloadService.loadJSON(resource3));
List<JSONObject> jsonObjectList = new ArrayList<>();
jsonObjectList.add(json1);
jsonObjectList.add(json2);
jsonObjectList.add(json3);
Downloadable downloadable = new Maven.MavenInstaller.DescriptorImpl().createDownloadable();
JSONObject reducedJson = downloadable.reduce(jsonObjectList);
URL expectedResult = DownloadServiceTest.class.getResource("hudson.tasks.Maven.MavenInstallerResult.json");
JSONObject expectedResultJson = JSONObject.fromObject(DownloadService.loadJSON(expectedResult));
assertEquals(reducedJson, expectedResultJson);
}
public void testReduceFunctionWithAntJsons() throws Exception {
URL resource1 = DownloadServiceTest.class.getResource("hudson.tasks.Ant.AntInstaller1.json");
URL resource2 = DownloadServiceTest.class.getResource("hudson.tasks.Ant.AntInstaller2.json");
URL resource3 = DownloadServiceTest.class.getResource("hudson.tasks.Ant.AntInstaller3.json");
JSONObject json1 = JSONObject.fromObject(DownloadService.loadJSON(resource1));
JSONObject json2 = JSONObject.fromObject(DownloadService.loadJSON(resource2));
JSONObject json3 = JSONObject.fromObject(DownloadService.loadJSON(resource3));
List<JSONObject> jsonObjectList = new ArrayList<>();
jsonObjectList.add(json1);
jsonObjectList.add(json2);
jsonObjectList.add(json3);
Downloadable downloadable = new hudson.tasks.Ant.AntInstaller.DescriptorImpl().createDownloadable();
JSONObject reducedJson = downloadable.reduce(jsonObjectList);
URL expectedResult = DownloadServiceTest.class.getResource("hudson.tasks.Ant.AntInstallerResult.json");
JSONObject expectedResultJson = JSONObject.fromObject(DownloadService.loadJSON(expectedResult));
assertEquals(reducedJson, expectedResultJson);
}
public void testReduceFunctionWithJDKJsons() throws Exception {
URL resource1 = DownloadServiceTest.class.getResource("hudson.tools.JDKInstaller1.json");
URL resource2 = DownloadServiceTest.class.getResource("hudson.tools.JDKInstaller2.json");
URL resource3 = DownloadServiceTest.class.getResource("hudson.tools.JDKInstaller3.json");
JSONObject json1 = JSONObject.fromObject(DownloadService.loadJSON(resource1));
JSONObject json2 = JSONObject.fromObject(DownloadService.loadJSON(resource2));
JSONObject json3 = JSONObject.fromObject(DownloadService.loadJSON(resource3));
List<JSONObject> jsonObjectList = new ArrayList<>();
jsonObjectList.add(json1);
jsonObjectList.add(json2);
jsonObjectList.add(json3);
JDKInstaller.JDKList downloadable = new JDKInstaller.JDKList();
JSONObject reducedJson = downloadable.reduce(jsonObjectList);
URL expectedResult = DownloadServiceTest.class.getResource("hudson.tools.JDKInstallerResult.json");
JSONObject expectedResultJson = JSONObject.fromObject(DownloadService.loadJSON(expectedResult));
assertEquals(reducedJson, expectedResultJson);
}
public void testReduceFunctionWithNotDefaultSchemaJsons() throws Exception {
URL resource1 = DownloadServiceTest.class.getResource("hudson.plugins.cmake.CmakeInstaller1.json");
URL resource2 = DownloadServiceTest.class.getResource("hudson.plugins.cmake.CmakeInstaller2.json");
JSONObject json1 = JSONObject.fromObject(DownloadService.loadJSON(resource1));
JSONObject json2 = JSONObject.fromObject(DownloadService.loadJSON(resource2));
List<JSONObject> jsonObjectList = new ArrayList<>();
jsonObjectList.add(json1);
jsonObjectList.add(json2);
Downloadable downloadable = new GenericDownloadFromUrlInstaller.DescriptorImpl().createDownloadable();
JSONObject reducedJson = downloadable.reduce(jsonObjectList);
URL expectedResult = DownloadServiceTest.class.getResource("hudson.plugins.cmake.CmakeInstallerResult.json");
JSONObject expectedResultJson = JSONObject.fromObject(DownloadService.loadJSON(expectedResult));
assertEquals(reducedJson, expectedResultJson);
}
private static class GenericDownloadFromUrlInstaller extends DownloadFromUrlInstaller {
protected GenericDownloadFromUrlInstaller(String id) {
super(id);
}
public static final class DescriptorImpl extends DownloadFromUrlInstaller.DescriptorImpl<Maven.MavenInstaller> {
public String getDisplayName() {
return "";
}
@Override
public boolean isApplicable(Class<? extends ToolInstallation> toolType) {
return true;
}
}
}
}
downloadService.post('hudson.plugins.cmake.CmakeInstaller',{"list": [
{
"id": "3.4.2",
"name": "3.4.2",
"variants": [
{
"arch": "x86",
"os": "win32",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-win32-x86.zip"
},
{
"arch": "x86_64",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-Linux-x86_64.tar.gz"
},
{
"arch": "i386",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-Linux-i386.tar.gz"
},
{
"arch": "x86_64",
"os": "Darwin",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-Darwin-x86_64.tar.gz"
}
]
},
{
"id": "3.4.1",
"name": "3.4.1",
"variants": [
{
"arch": "x86",
"os": "win32",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-win32-x86.zip"
},
{
"arch": "x86_64",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-Linux-x86_64.tar.gz"
},
{
"arch": "i386",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-Linux-i386.tar.gz"
},
{
"arch": "x86_64",
"os": "Darwin",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz"
}
]
}
]})
\ No newline at end of file
downloadService.post('hudson.plugins.cmake.CmakeInstaller',{"list": [
{
"id": "2.6.1",
"name": "2.6.1",
"variants": [
{
"arch": "x86",
"os": "win32",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-win32-x86.zip"
},
{
"arch": "sparc",
"os": "SunOS",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-SunOS-sparc.tar.gz"
},
{
"arch": "i386",
"os": "Linux",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-Linux-i386.tar.gz"
},
{
"arch": "n32",
"os": "IRIX64",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-IRIX64-n32.tar.gz"
},
{
"arch": "64",
"os": "IRIX64",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-IRIX64-64.tar.gz"
},
{
"arch": "9000_785",
"os": "HP-UX",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-HP-UX-9000_785.tar.gz"
},
{
"arch": "universal",
"os": "Darwin",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-Darwin-universal.tar.gz"
},
{
"arch": "powerpc",
"os": "AIX",
"url": "https://cmake.org/files/v2.6/cmake-2.6.1-AIX-powerpc.tar.gz"
}
]
}
]})
\ No newline at end of file
downloadService.post('hudson.plugins.cmake.CmakeInstaller',{"list": [
{
"id": "3.4.2",
"name": "3.4.2",
"variants": [
{
"arch": "x86",
"os": "win32",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-win32-x86.zip"
},
{
"arch": "x86_64",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-Linux-x86_64.tar.gz"
},
{
"arch": "i386",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-Linux-i386.tar.gz"
},
{
"arch": "x86_64",
"os": "Darwin",
"url": "https://cmake.org/files/v3.4/cmake-3.4.2-Darwin-x86_64.tar.gz"
}
]
},
{
"id": "3.4.1",
"name": "3.4.1",
"variants": [
{
"arch": "x86",
"os": "win32",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-win32-x86.zip"
},
{
"arch": "x86_64",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-Linux-x86_64.tar.gz"
},
{
"arch": "i386",
"os": "Linux",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-Linux-i386.tar.gz"
},
{
"arch": "x86_64",
"os": "Darwin",
"url": "https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz"
}
]
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Ant.AntInstaller',{"list": [
{
"id": "1.9.6",
"name": "1.9.6",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.6-bin.zip"
},
{
"id": "1.9.5",
"name": "1.9.5",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.5-bin.zip"
},
{
"id": "1.9.4",
"name": "1.9.4",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.4-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Ant.AntInstaller',{"list": [
{
"id": "1.9.4",
"name": "1.9.4",
"url": "http://archive1.apache.org/dist/ant/binaries/apache-ant-1.9.4-bin.zip"
},
{
"id": "1.9.2",
"name": "1.9.2",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.2-bin.zip"
},
{
"id": "1.9.1",
"name": "1.9.1",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.1-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Ant.AntInstaller',{"list": [
{
"id": "1.9.3",
"name": "1.9.6",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.6-bin.zip"
},
{
"id": "1.9.5",
"name": "1.9.5",
"url": "http://archive2.apache.org/dist/ant/binaries/apache-ant-1.9.5-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Ant.AntInstaller',{"list": [
{
"id": "1.9.6",
"name": "1.9.6",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.6-bin.zip"
},
{
"id": "1.9.5",
"name": "1.9.5",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.5-bin.zip"
},
{
"id": "1.9.4",
"name": "1.9.4",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.4-bin.zip"
},
{
"id": "1.9.2",
"name": "1.9.2",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.2-bin.zip"
},
{
"id": "1.9.1",
"name": "1.9.1",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.1-bin.zip"
},
{
"id": "1.9.3",
"name": "1.9.6",
"url": "http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.6-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Maven.MavenInstaller',{"list": [
{
"id": "3.3.9",
"name": "3.3.9",
"url": "http://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip"
},
{
"id": "3.3.3",
"name": "3.3.3",
"url": "http://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip"
},
{
"id": "3.3.1",
"name": "3.3.1",
"url": "http://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.1/apache-maven-3.3.1-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Maven.MavenInstaller',{"list": [
{
"id": "3.3.1",
"name": "3.3.1",
"url": "http://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.1/apache-maven-3.3.1-bin.zip"
},
{
"id": "3.2.5",
"name": "3.2.5",
"url": "http://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.2.5/apache-maven-3.2.5-bin.zip"
},
{
"id": "3.2.3",
"name": "3.2.3",
"url": "http://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.2.3/apache-maven-3.2.3-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Maven.MavenInstaller',{"list": [
{
"id": "3.3.1",
"name": "3.3.1",
"url": "http://repo2.maven.org/maven2/org/apache/maven/apache-maven/3.3.1/apache-maven-3.3.1-bin.zip"
},
{
"id": "3.0.4",
"name": "3.0.4",
"url": "http://archive.apache.org/dist/maven/binaries/apache-maven-3.0.4-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tasks.Maven.MavenInstaller', {"list": [
{
"id": "3.3.9",
"name": "3.3.9",
"url": "http://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip"
},
{
"id": "3.3.3",
"name": "3.3.3",
"url": "http://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip"
},
{
"id": "3.3.1",
"name": "3.3.1",
"url": "http://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.1/apache-maven-3.3.1-bin.zip"
},
{
"id": "3.2.5",
"name": "3.2.5",
"url": "http://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.2.5/apache-maven-3.2.5-bin.zip"
},
{
"id": "3.2.3",
"name": "3.2.3",
"url": "http://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.2.3/apache-maven-3.2.3-bin.zip"
},
{
"id": "3.0.4",
"name": "3.0.4",
"url": "http://archive.apache.org/dist/maven/binaries/apache-maven-3.0.4-bin.zip"
}
]})
\ No newline at end of file
downloadService.post('hudson.tools.JDKInstaller',{
"data": [
{
"name": "JDK 8",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-i586.tar.gz",
"name": "jdk-8u66-linux-i586.tar.gz",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-macosx-x64.dmg",
"name": "jdk-8u66-macosx-x64.dmg",
"title": "Mac OS X x64"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u66-oth-JPR",
"title": "Java SE Development Kit 8u66"
},
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u65-b17/jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"name": "jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"title": "Linux ARM v6/v7 Hard Float ABI"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u65-b17/jdk-8u65-linux-arm64-vfp-hflt.tar.gz",
"name": "jdk-8u65-linux-arm64-vfp-hflt.tar.gz",
"title": "Linux ARM v8 Hard Float ABI"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u65-oth-JPR",
"title": "Java SE Development Kit 8u65"
}
]
},
{
"name": "JDK 7",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/7u80-b15/jdk-7u80-linux-i586.tar.gz",
"name": "jdk-7u80-linux-i586.tar.gz",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/7u80-b15/jdk-7u80-linux-x64.tar.gz",
"name": "jdk-7u80-linux-x64.tar.gz",
"title": "Linux x64"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-7u80-oth-JPR",
"title": "Java SE Development Kit 7u80"
}
]
}
],
"version": 2
}
\ No newline at end of file
downloadService.post('hudson.tools.JDKInstaller',{
"data": [
{
"name": "JDK 8",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle1.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-i586.tar.gz",
"name": "jdk-8u66-linux-i586.tar.gz",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-x64.tar.gz",
"name": "jdk-8u66-linux-x64.tar.gz",
"title": "Linux x64"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-macosx-x64.dmg",
"name": "jdk-8u66-macosx-x64.dmg",
"title": "Mac OS X x64"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u66-oth-JPR",
"title": "Java SE Development Kit 8u66"
},
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u65-b17/jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"name": "jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"title": "Linux ARM v6/v7 Hard Float ABI"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u65-oth-JPR",
"title": "Java SE Development Kit 8u65"
}
]
}
],
"version": 2
}
\ No newline at end of file
downloadService.post('hudson.tools.JDKInstaller',{
"data": [
{
"name": "JDK 8",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle2.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-i586.tar.gz",
"name": "jdk-8u66-linux-i586.tar.gz",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-solaris-x64.tar.gz",
"name": "jdk-8u66-solaris-x64.tar.gz",
"title": "Solaris x64"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b18/jdk-8u66-windows-i586.exe",
"name": "jdk-8u66-windows-i586.exe",
"title": "Windows x86"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u66-oth-JPR",
"title": "Java SE Development Kit 8u66"
},
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u65-b17/jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"name": "jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"title": "Linux ARM v6/v7 Hard Float ABI"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u65-oth-JPR",
"title": "Java SE Development Kit 8u65"
}
]
},
{
"name": "JDK 6",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle.com/otn/java/jdk/6u45-b06/jdk-6u45-linux-i586.bin",
"name": "jdk-6u45-linux-i586.bin",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn/java/jdk/6u45-b06/jdk-6u45-linux-ia64.bin",
"name": "jdk-6u45-linux-ia64.bin",
"title": "Linux Intel Itanium"
}
],
"licpath": "/technetwork/java/javase/downloads/java-se-archive-license-1382604.html",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-6u45-oth-JPR",
"title": "Java SE Development Kit 6u45"
}
],
}
],
"version": 3
}
\ No newline at end of file
downloadService.post('hudson.tools.JDKInstaller',{
"data": [
{
"name": "JDK 8",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-i586.tar.gz",
"name": "jdk-8u66-linux-i586.tar.gz",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-macosx-x64.dmg",
"name": "jdk-8u66-macosx-x64.dmg",
"title": "Mac OS X x64"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-x64.tar.gz",
"name": "jdk-8u66-linux-x64.tar.gz",
"title": "Linux x64"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-solaris-x64.tar.gz",
"name": "jdk-8u66-solaris-x64.tar.gz",
"title": "Solaris x64"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u66-b18/jdk-8u66-windows-i586.exe",
"name": "jdk-8u66-windows-i586.exe",
"title": "Windows x86"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u66-oth-JPR",
"title": "Java SE Development Kit 8u66"
},
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u65-b17/jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"name": "jdk-8u65-linux-arm32-vfp-hflt.tar.gz",
"title": "Linux ARM v6/v7 Hard Float ABI"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/8u65-b17/jdk-8u65-linux-arm64-vfp-hflt.tar.gz",
"name": "jdk-8u65-linux-arm64-vfp-hflt.tar.gz",
"title": "Linux ARM v8 Hard Float ABI"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-8u65-oth-JPR",
"title": "Java SE Development Kit 8u65"
}
]
},
{
"name": "JDK 7",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/7u80-b15/jdk-7u80-linux-i586.tar.gz",
"name": "jdk-7u80-linux-i586.tar.gz",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn-pub/java/jdk/7u80-b15/jdk-7u80-linux-x64.tar.gz",
"name": "jdk-7u80-linux-x64.tar.gz",
"title": "Linux x64"
}
],
"licpath": "/technetwork/java/javase/terms/license",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-7u80-oth-JPR",
"title": "Java SE Development Kit 7u80"
}
]
},
{
"name": "JDK 6",
"releases": [
{
"files": [
{
"filepath": "http://download.oracle.com/otn/java/jdk/6u45-b06/jdk-6u45-linux-i586.bin",
"name": "jdk-6u45-linux-i586.bin",
"title": "Linux x86"
},
{
"filepath": "http://download.oracle.com/otn/java/jdk/6u45-b06/jdk-6u45-linux-ia64.bin",
"name": "jdk-6u45-linux-ia64.bin",
"title": "Linux Intel Itanium"
}
],
"licpath": "/technetwork/java/javase/downloads/java-se-archive-license-1382604.html",
"lictitle": "Oracle Binary Code License Agreement for Java SE",
"name": "jdk-6u45-oth-JPR",
"title": "Java SE Development Kit 6u45"
}
],
}
],
"version": 2
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册