提交 ae32c905 编写于 作者: H huybrechts

[FIXED HUDSON-786] tool locations can be overridden per slave. Currently...

[FIXED HUDSON-786] tool locations can be overridden per slave. Currently implemented for JDK, Ant, Groovy.
Plugins that want to benefit from this should implement ToolDescriptor.
See hudson.model.Ant for an example of how to do this in a backward compatible way.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@15737 71c3de6d-444a-0410-be80-ed276b4c234a
上级 ea3cdd2a
......@@ -37,11 +37,11 @@ import hudson.model.ModelObject;
import hudson.model.Node;
import hudson.model.PageDecorator;
import hudson.model.ParameterDefinition;
import hudson.model.ParameterDefinition.ParameterDescriptor;
import hudson.model.Project;
import hudson.model.Run;
import hudson.model.TopLevelItem;
import hudson.model.View;
import hudson.model.ParameterDefinition.ParameterDescriptor;
import hudson.search.SearchableModelObject;
import hudson.security.AccessControlled;
import hudson.security.AuthorizationStrategy;
......@@ -49,23 +49,23 @@ import hudson.security.Permission;
import hudson.security.SecurityRealm;
import hudson.slaves.Cloud;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.NodeProperty;
import hudson.slaves.NodePropertyDescriptor;
import hudson.slaves.RetentionStrategy;
import hudson.tasks.BuildStep;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrappers;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.util.Area;
import hudson.util.DescriptorList;
import hudson.util.Iterators;
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.jelly.JellyTagException;
import org.apache.commons.jelly.Script;
import org.apache.commons.jelly.XMLOutput;
import org.apache.commons.jelly.Tag;
import org.apache.commons.jelly.TagSupport;
import org.apache.commons.jelly.XMLOutput;
import org.apache.commons.jexl.parser.ASTSizeFunction;
import org.apache.commons.jexl.util.Introspector;
import org.jvnet.animal_sniffer.IgnoreJRERequirement;
......@@ -92,6 +92,7 @@ import java.lang.management.ThreadMXBean;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
......@@ -621,6 +622,17 @@ public class Functions {
return ParameterDefinition.all();
}
public static List<NodePropertyDescriptor> getNodePropertyDescriptors(Class<? extends Node> clazz) {
List<NodePropertyDescriptor> result = new ArrayList<NodePropertyDescriptor>();
Collection<NodePropertyDescriptor> list = (Collection) Hudson.getInstance().getDescriptorList(NodeProperty.class);
for (NodePropertyDescriptor npd : list) {
if (npd.isApplicable(clazz)) {
result.add(npd);
}
}
return result;
}
/**
* Computes the path to the icon of the given action
* from the context path.
......
......@@ -431,8 +431,13 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
env.put("CLASSPATH","");
JDK jdk = project.getJDK();
if(jdk !=null)
if(jdk != null) {
Computer computer = Computer.currentComputer();
if (computer != null) { // just in case were not in a build
jdk = jdk.forNode(computer.getNode());
}
jdk.buildEnvVars(env);
}
project.getScm().buildEnvVars(this,env);
if(buildEnvironments!=null)
......
......@@ -123,8 +123,19 @@ public abstract class Build <P extends Project<P,B>,B extends Build<P,B>>
try {
List<BuildWrapper> wrappers = new ArrayList<BuildWrapper>(project.getBuildWrappers().values());
Node node = Computer.currentComputer().getNode();
NodeProperty.setup(node, buildEnvironments, Build.this, launcher, listener);
for (NodeProperty nodeProperty: Hudson.getInstance().getGlobalNodeProperties()) {
Environment environment = nodeProperty.setUp(Build.this, launcher, listener);
if (environment != null) {
buildEnvironments.add(environment);
}
}
for (NodeProperty nodeProperty: Computer.currentComputer().getNode().getNodeProperties()) {
Environment environment = nodeProperty.setUp(Build.this, launcher, listener);
if (environment != null) {
buildEnvironments.add(environment);
}
}
ParametersAction parameters = getAction(ParametersAction.class);
if (parameters != null)
......
......@@ -33,7 +33,7 @@ import hudson.EnvVars;
* @since 1.286
* @param <T>
*/
public interface EnvironmentSpecific<T> {
public interface EnvironmentSpecific<T extends EnvironmentSpecific<?>> {
/**
* Returns a specialized copy of T for functioning in the given environment.
*/
......
......@@ -403,10 +403,15 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
private transient final List<Action> actions = new CopyOnWriteArrayList<Action>();
/**
* List of global/master node properties
* List of master node properties
*/
private DescribableList<NodeProperty<?>,NodePropertyDescriptor> nodeProperties = new DescribableList<NodeProperty<?>,NodePropertyDescriptor>(this);
/**
* List of global properties
*/
private DescribableList<NodeProperty<?>,NodePropertyDescriptor> globalNodeProperties = new DescribableList<NodeProperty<?>,NodePropertyDescriptor>(this);
/**
* {@link AdministrativeMonitor}s installed on this system.
*
......@@ -1238,6 +1243,10 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
return nodeProperties;
}
public DescribableList<NodeProperty<?>, NodePropertyDescriptor> getGlobalNodeProperties() {
return globalNodeProperties;
}
/**
* Resets all labels and remove invalid ones.
*/
......@@ -2051,7 +2060,10 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
clouds.rebuildHetero(req,json, Cloud.all(), "cloud");
nodeProperties.rebuild(req, json.getJSONObject("nodeProperties"), NodeProperty.for_(this));
JSONObject np = json.getJSONObject("globalNodeProperties");
if (np != null) {
globalNodeProperties.rebuild(req, np, NodeProperty.for_(this));
}
save();
if(result)
......
......@@ -26,37 +26,40 @@ package hudson.model;
import hudson.util.StreamTaskListener;
import hudson.util.NullStream;
import hudson.Launcher;
import hudson.Extension;
import hudson.slaves.NodeSpecific;
import hudson.tools.ToolInstallation;
import hudson.tools.ToolDescriptor;
import hudson.tools.ToolLocationNodeProperty;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.List;
/**
* Information about JDK installation.
*
* @author Kohsuke Kawaguchi
*/
public final class JDK {
private final String name;
private final String javaHome;
public final class JDK extends ToolInstallation implements NodeSpecific<JDK> {
@Deprecated // kept for backward compatibility - use getHome() instead
private String javaHome;
public JDK(String name, String javaHome) {
this.name = name;
this.javaHome = javaHome;
super(name, javaHome);
}
/**
* install directory.
*/
public String getJavaHome() {
return javaHome;
return getHome();
}
/**
* Human readable display name.
*/
public String getName() {
return name;
public String getHome() {
if (javaHome != null) return javaHome;
return super.getHome();
}
/**
......@@ -92,11 +95,20 @@ public final class JDK {
// see EnvVars javadoc for why this adss PATH.
env.put("PATH+JDK",getBinDir().getPath());
env.put("JAVA_HOME",javaHome);
env.put("JAVA_HOME",getJavaHome());
if(!env.containsKey("HUDSON_HOME"))
env.put("HUDSON_HOME", Hudson.getInstance().getRootDir().getPath() );
}
public JDK forNode(Node node) {
String newHome = ToolLocationNodeProperty.getToolHome(node, this);
if (newHome != null) {
return new JDK(getName(), newHome);
} else {
return this;
}
}
/**
* Checks if "java" is in PATH on the given node.
*
......@@ -115,4 +127,24 @@ public final class JDK {
return false;
}
}
@Extension
public static class DescriptorImpl extends ToolDescriptor<JDK> {
public String getDisplayName() {
return "Java Development Kit";
}
public JDK[] getInstallations() {
return Hudson.getInstance().getJDKs().toArray(new JDK[0]);
}
// this isn't really synchronized well since the list is Hudson.jdks :(
public synchronized void setInstallations(JDK... jdks) {
List<JDK> list = Hudson.getInstance().getJDKs();
list.clear();
for (JDK jdk: jdks) list.add(jdk);
}
}
}
......@@ -27,6 +27,7 @@ import hudson.ExtensionPoint;
import hudson.FilePath;
import hudson.FileSystemProvisioner;
import hudson.Launcher;
import hudson.tools.ToolLocationNodeProperty;
import hudson.node_monitors.NodeMonitor;
import hudson.remoting.VirtualChannel;
import hudson.security.ACL;
......@@ -56,6 +57,7 @@ import org.kohsuke.stapler.Stapler;
* @see NodeDescriptor
*/
public abstract class Node extends AbstractModelObject implements Describable<Node>, ExtensionPoint, AccessControlled {
public String getDisplayName() {
return getNodeName(); // default implementation
}
......@@ -195,13 +197,6 @@ public abstract class Node extends AbstractModelObject implements Describable<No
public List<NodePropertyDescriptor> getNodePropertyDescriptors() {
return NodeProperty.for_(this);
}
/**
* @deprecated
* Check with Tom to see if we really need this method.
*/
public <N extends NodeProperty<?>> N getNodeProperty(Class<N> clazz) {
return getNodeProperties().get(clazz);
}
public ACL getACL() {
return Hudson.getInstance().getAuthorizationStrategy().getACL(this);
......
......@@ -488,17 +488,4 @@ public abstract class Slave extends Node implements Serializable {
private static final long serialVersionUID = 1L;
}
// static {
// ConvertUtils.register(new Converter(){
// public Object convert(Class type, Object value) {
// if (value != null) {
// System.out.println("CVT: " + type + " from (" + value.getClass() + ") " + value);
// } else {
// System.out.println("CVT: " + type + " from " + value);
// }
// return null; //To change body of implemented methods use File | Settings | File Templates.
// }
// }, ComputerLauncher.class);
// }
}
......@@ -71,7 +71,8 @@ public class EnvironmentVariablesNodeProperty extends NodeProperty<Node> {
@Extension
public static class DescriptorImpl extends NodePropertyDescriptor {
@Override
@Override
public String getDisplayName() {
return Messages.EnvironmentVariablesNodeProperty_displayName();
}
......
......@@ -93,25 +93,6 @@ public abstract class NodeProperty<N extends Node> implements Describable<NodePr
public Environment setUp( AbstractBuild build, Launcher launcher, BuildListener listener ) throws IOException, InterruptedException {
return new Environment() {};
}
public static void setup(Node node, List<Environment> buildEnvironments, AbstractBuild build, Launcher launcher, BuildListener listener)
throws IOException, InterruptedException {
if (node != Hudson.getInstance()) {
for (NodeProperty nodeProperty: Hudson.getInstance().getNodeProperties()) {
Environment environment = nodeProperty.setUp(build, launcher, listener);
if (environment != null) {
buildEnvironments.add(environment);
}
}
}
for (NodeProperty nodeProperty: node.getNodeProperties()) {
Environment environment = nodeProperty.setUp(build, launcher, listener);
if (environment != null) {
buildEnvironments.add(environment);
}
}
}
/**
* Lists up all the registered {@link NodeDescriptor}s in the system.
......
......@@ -44,7 +44,7 @@ import org.jvnet.tiger_types.Types;
public abstract class NodePropertyDescriptor extends Descriptor<NodeProperty<?>> {
/**
* Returns true if this {@link NodeProperty} type is applicable to the
* given job type.
* given node type.
*
* <p>
* The default implementation of this method checks if the given node type is assignable to 'N' of
......
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
*
* 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.slaves;
import hudson.model.Node;
/**
* @author huybrechts
*/
public interface NodeSpecific<T extends NodeSpecific<?>> {
T forNode(Node node);
}
......@@ -25,17 +25,24 @@ package hudson.tasks;
import hudson.CopyOnWrite;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Util;
import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Computer;
import hudson.model.Descriptor;
import hudson.model.EnvironmentSpecific;
import hudson.model.Hudson;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.remoting.Callable;
import hudson.slaves.NodeSpecific;
import hudson.tools.ToolDescriptor;
import hudson.tools.ToolInstallation;
import hudson.tools.ToolLocationNodeProperty;
import hudson.util.ArgumentListBuilder;
import hudson.util.FormFieldValidator;
import hudson.util.VariableResolver;
......@@ -47,7 +54,6 @@ import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.Properties;
......@@ -135,13 +141,16 @@ public class Ant extends Builder {
env.overrideAll(build.getEnvVars());
AntInstallation ai = getAnt();
if (ai != null) {
ai = ai.forNode(Computer.currentComputer().getNode());
}
if(ai==null) {
args.add(launcher.isUnix() ? "ant" : "ant.bat");
} else {
ai = ai.forEnvironment(env);
String exe = ai.getExecutable(launcher);
if (exe==null) {
listener.fatalError(Messages.Ant_ExecutableNotFound(ai.name));
listener.fatalError(Messages.Ant_ExecutableNotFound(ai.getName()));
return false;
}
args.add(exe);
......@@ -316,13 +325,13 @@ public class Ant extends Builder {
}
}
public static final class AntInstallation implements Serializable, EnvironmentSpecific<AntInstallation> {
private final String name;
public static final class AntInstallation extends ToolInstallation implements
EnvironmentSpecific<AntInstallation>, NodeSpecific<AntInstallation> {
private final String antHome;
@DataBoundConstructor
public AntInstallation(String name, String home) {
this.name = name;
super(name, launderHome(home));
if(home.endsWith("/") || home.endsWith("\\"))
// see https://issues.apache.org/bugzilla/show_bug.cgi?id=26947
// Ant doesn't like the trailing slash, especially on Windows
......@@ -330,18 +339,26 @@ public class Ant extends Builder {
this.antHome = home;
}
private static String launderHome(String home) {
if(home.endsWith("/") || home.endsWith("\\")) {
// see https://issues.apache.org/bugzilla/show_bug.cgi?id=26947
// Ant doesn't like the trailing slash, especially on Windows
return home.substring(0,home.length()-1);
} else {
return home;
}
}
/**
* install directory.
*/
public String getAntHome() {
return antHome;
return getHome();
}
/**
* Human readable display name.
*/
public String getName() {
return name;
public String getHome() {
if (antHome != null) return antHome;
return super.getHome();
}
/**
......@@ -381,7 +398,36 @@ public class Ant extends Builder {
private static final long serialVersionUID = 1L;
public AntInstallation forEnvironment(EnvVars environment) {
return new AntInstallation(name, environment.expand(antHome));
return new AntInstallation(getName(), environment.expand(antHome));
}
public AntInstallation forNode(Node node) {
String newHome = ToolLocationNodeProperty.getToolHome(node, this);
if (newHome != null) {
return new AntInstallation(getName(), newHome);
} else {
return this;
}
}
@Extension
public static class DescriptorImpl extends ToolDescriptor<AntInstallation> {
@Override
public String getDisplayName() {
return "Ant";
}
@Override
public AntInstallation[] getInstallations() {
return Hudson.getInstance().getDescriptorByType(Ant.DescriptorImpl.class).getInstallations();
}
@Override
public void setInstallations(AntInstallation... installations) {
Hudson.getInstance().getDescriptorByType(Ant.DescriptorImpl.class).setInstallations(installations);
}
}
}
}
......@@ -23,44 +23,48 @@
*/
package hudson.tasks;
import hudson.CopyOnWrite;
import hudson.FilePath.FileCallable;
import hudson.Functions;
import hudson.Extension;
import hudson.Launcher;
import hudson.Launcher.LocalLauncher;
import hudson.Util;
import hudson.Functions;
import hudson.EnvVars;
import hudson.Extension;
import hudson.Util;
import hudson.CopyOnWrite;
import hudson.Launcher.LocalLauncher;
import hudson.FilePath.FileCallable;
import hudson.maven.MavenEmbedder;
import hudson.maven.MavenUtil;
import hudson.maven.RedeployPublisher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Computer;
import hudson.model.Descriptor;
import hudson.model.EnvironmentSpecific;
import hudson.model.Node;
import hudson.model.Hudson;
import hudson.remoting.Callable;
import hudson.remoting.VirtualChannel;
import hudson.slaves.NodeSpecific;
import hudson.tools.ToolDescriptor;
import hudson.tools.ToolInstallation;
import hudson.tools.ToolLocationNodeProperty;
import hudson.util.ArgumentListBuilder;
import hudson.util.FormFieldValidator;
import hudson.util.NullStream;
import hudson.util.StreamTaskListener;
import hudson.util.VariableResolver;
import net.sf.json.JSONObject;
import org.apache.maven.embedder.MavenEmbedderException;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.DataBoundConstructor;
import org.apache.maven.embedder.MavenEmbedderException;
import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Properties;
import net.sf.json.JSONObject;
import java.util.StringTokenizer;
/**
* Build by using Maven.
......@@ -204,15 +208,18 @@ public class Maven extends Builder {
.replaceAll("[\t\r\n]+"," ");
ArgumentListBuilder args = new ArgumentListBuilder();
MavenInstallation ai = getMaven();
if(ai==null) {
MavenInstallation mi = getMaven();
if (mi != null) {
mi = mi.forNode(Computer.currentComputer().getNode());
}
if(mi==null) {
String execName = proj.getWorkspace().act(new DecideDefaultMavenCommand(normalizedTarget));
args.add(execName);
} else {
ai = ai.forEnvironment(env);
String exec = ai.getExecutable(launcher);
mi = mi.forEnvironment(env);
String exec = mi.getExecutable(launcher);
if(exec==null) {
listener.fatalError(Messages.Maven_NoExecutable(ai.getMavenHome()));
listener.fatalError(Messages.Maven_NoExecutable(mi.getMavenHome()));
return false;
}
args.add(exec);
......@@ -223,7 +230,7 @@ public class Maven extends Builder {
args.addKeyValuePairsFromPropertyString("-D",properties,vr);
args.addTokenized(normalizedTarget);
if(ai!=null) {
if(mi!=null) {
// if somebody has use M2_HOME they will get a classloading error
// when M2_HOME points to a different version of Maven2 from
// MAVEN_HOME (as Maven 2 gives M2_HOME priority.)
......@@ -231,8 +238,8 @@ public class Maven extends Builder {
// The other solution would be to set M2_HOME if we are calling Maven2
// and MAVEN_HOME for Maven1 (only of use for strange people that
// are calling Maven2 from Maven1)
env.put("M2_HOME",ai.getMavenHome());
env.put("MAVEN_HOME",ai.getMavenHome());
env.put("M2_HOME",mi.getMavenHome());
env.put("MAVEN_HOME",mi.getMavenHome());
}
// just as a precaution
// see http://maven.apache.org/continuum/faqs.html#how-does-continuum-detect-a-successful-build
......@@ -345,32 +352,30 @@ public class Maven extends Builder {
}
}
public static final class MavenInstallation implements Serializable, EnvironmentSpecific<MavenInstallation> {
private final String name;
private final String mavenHome;
public static final class MavenInstallation extends ToolInstallation implements EnvironmentSpecific<MavenInstallation>, NodeSpecific<MavenInstallation> {
@Deprecated // kept for backward compatiblity - use getHome()
private String mavenHome;
@DataBoundConstructor
public MavenInstallation(String name, String home) {
this.name = name;
this.mavenHome = home;
super(name, home);
}
/**
* install directory.
*/
public String getMavenHome() {
return mavenHome;
return getHome();
}
public File getHomeDir() {
return new File(mavenHome);
return new File(getHome());
}
/**
* Human readable display name.
*/
public String getName() {
return name;
public String getHome() {
if (mavenHome != null) return mavenHome;
return super.getHome();
}
/**
......@@ -412,15 +417,44 @@ public class Maven extends Builder {
}
}
public MavenEmbedder createEmbedder(BuildListener listener, String profiles, Properties systemProperties) throws MavenEmbedderException, IOException {
public MavenEmbedder createEmbedder(BuildListener listener, String profiles, Properties systemProperties)
throws MavenEmbedderException, IOException {
return MavenUtil.createEmbedder(listener,getHomeDir(),profiles,systemProperties);
}
private static final long serialVersionUID = 1L;
public MavenInstallation forEnvironment(EnvVars environment) {
return new MavenInstallation(name, environment.expand(mavenHome));
return new MavenInstallation(getName(), environment.expand(getHome()));
}
public MavenInstallation forNode(Node node) {
String newHome = ToolLocationNodeProperty.getToolHome(Computer.currentComputer().getNode(), this);
if (newHome != null) {
return new MavenInstallation(getName(), newHome);
} else {
return this;
}
}
@Extension
public static class DescriptorImpl extends ToolDescriptor<MavenInstallation> {
@Override
public String getDisplayName() {
return "Maven";
}
@Override
public MavenInstallation[] getInstallations() {
return Hudson.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).getInstallations();
}
@Override
public void setInstallations(MavenInstallation... installations) {
Hudson.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(installations);
}
}
}
/**
......
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
*
* 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.tools;
import hudson.model.Descriptor;
import hudson.model.Describable;
import hudson.tasks.BuildStep;
/**
* @author huybrechts
*/
public abstract class ToolDescriptor<T extends ToolInstallation> extends Descriptor<ToolInstallation> {
T[] installations;
public T[] getInstallations() {
return installations;
}
public void setInstallations(T[] installations) {
this.installations = installations;
}
public abstract String getDisplayName();
}
/*
* The MIT License
*
* Copyright (c) 2004-${date.year}, Sun Microsystems, Inc., Tom Huybrechts
*
* 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.tools;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.DescriptorExtensionList;
import hudson.tasks.BuildWrapper;
import java.io.Serializable;
/**
* @author huybrechts
*/
public abstract class ToolInstallation implements Serializable, Describable<ToolInstallation> {
private final String name;
private final String home;
public ToolInstallation(String name, String home) {
this.name = name;
this.home = home;
}
public String getHome() {
return home;
}
public String getName() {
return name;
}
public ToolDescriptor getDescriptor() {
return (ToolDescriptor) Hudson.getInstance().getDescriptor(getClass());
}
public static DescriptorExtensionList<ToolInstallation,ToolDescriptor<ToolInstallation>> all() {
// use getDescriptorList and not getExtensionList to pick up legacy instances
return Hudson.getInstance().getDescriptorList(ToolInstallation.class);
}
}
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
*
* 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.tools;
import hudson.model.Node;
import hudson.model.Hudson;
import hudson.model.Descriptor;
import hudson.slaves.NodeProperty;
import hudson.slaves.NodePropertyDescriptor;
import hudson.tasks.Ant;
import hudson.DescriptorExtensionList;
import hudson.Extension;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.kohsuke.stapler.DataBoundConstructor;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
public class ToolLocationNodeProperty extends NodeProperty<Node> {
private final List<ToolLocation> locations;
@DataBoundConstructor
public ToolLocationNodeProperty(List<ToolLocation> locations) {
this.locations = locations;
}
public ToolLocationNodeProperty(ToolLocation... locations) {
this(Arrays.asList(locations));
}
public List<ToolLocation> getLocations() {
if (locations == null) return Collections.emptyList();
return Collections.unmodifiableList(locations);
}
public String getHome(ToolInstallation installation) {
for (ToolLocation location : locations) {
if (location.getName().equals(installation.getName()) && location.getType() == installation.getDescriptor()) {
return location.getHome();
}
}
return null;
}
public static String getToolHome(Node node, ToolInstallation installation) {
ToolLocationNodeProperty property = node.getNodeProperties().get(ToolLocationNodeProperty.class);
if (property != null) {
return property.getHome(installation);
}
return null;
}
@Extension
public static class DescriptorImpl extends NodePropertyDescriptor {
public String getDisplayName() {
return "Tool Locations";
}
public synchronized DescriptorExtensionList<ToolInstallation,ToolDescriptor<ToolInstallation>> getToolDescriptors() {
return ToolInstallation.all();
}
public String getKey(ToolInstallation installation) {
return installation.getDescriptor().getClass().getName() + "@" + installation.getName();
}
@Override
public boolean isApplicable(Class<? extends Node> nodeType) {
return nodeType != Hudson.class;
}
}
public static final class ToolLocation {
private final String type;
private final String name;
private final String home;
private transient ToolDescriptor descriptor;
public ToolLocation(ToolDescriptor type, String name, String home) {
this.descriptor = type;
this.type = type.getClass().getName();
this.name = name;
this.home = home;
}
@DataBoundConstructor
public ToolLocation(String key, String home) {
this.type = key.substring(0, key.indexOf('@'));
this.name = key.substring(key.indexOf('@') + 1);
this.home = home;
}
public String getName() {
return name;
}
public String getHome() {
return home;
}
public ToolDescriptor getType() {
if (descriptor == null) descriptor = (ToolDescriptor) Descriptor.find(type);
return descriptor;
}
public String getKey() {
return type.getClass().getName() + "@" + name;
}
}
}
......@@ -90,13 +90,10 @@ THE SOFTWARE.
title="${%statsBlurb}"
help="/help/system-config/usage-statistics.html" />
<j:set var="propertyDescriptors" value="${it.nodePropertyDescriptors}" />
<j:if test="${!empty(propertyDescriptors)}">
<f:descriptorList title="${%Global properties}"
name="nodeProperties"
descriptors="${propertyDescriptors}"
instances="${it.nodeProperties}" />
</j:if>
<f:descriptorList title="${%Global properties}"
name="globalNodeProperties"
descriptors="${h.getNodePropertyDescriptors(it.class)}"
instances="${it.globalNodeProperties}" />
<f:section title="${%JDKs}">
<f:entry title="${%JDK installations}"
......
......@@ -84,7 +84,7 @@ THE SOFTWARE.
</j:forEach>
</f:dropdownList>
</j:if>
<f:descriptorList title="${%Node Properties}" descriptors="${it.nodePropertyDescriptors}" field="nodeProperties" />
<f:descriptorList title="${%Node Properties}" descriptors="${h.getNodePropertyDescriptors(descriptor.clazz)}" field="nodeProperties" />
</j:jelly>
\ No newline at end of file
<!--
~ The MIT License
~
~ Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
~
~ 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.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="List of tool locations" help="/help/tools/tool-location-node-property.html">
<f:repeatable var="location" name="locations" items="${instance.locations}">
<table width="100%">
<f:entry title="Name">
<select class="setting-input" name="locations.key">
<j:forEach var="toolDescriptor" items="${descriptor.toolDescriptors}">
<j:forEach var="toolInstallation" items="${toolDescriptor.installations}">
<f:option selected="${descriptor.getKey(toolInstallation)==location.key}" value="${descriptor.getKey(toolInstallation)}">(${toolDescriptor.displayName}) ${toolInstallation.name}</f:option>
</j:forEach>
</j:forEach>
</select>
</f:entry>
<f:entry title="Home">
<input class="setting-input" name="locations.home" type="text"
value="${location.home}" />
</f:entry>
<f:entry title="">
<div align="right">
<f:repeatableDeleteButton />
</div>
</f:entry>
</table>
</f:repeatable>
</f:entry>
</j:jelly>
\ No newline at end of file
......@@ -43,6 +43,7 @@ import hudson.model.Run;
import hudson.model.Saveable;
import hudson.model.TaskListener;
import hudson.model.UpdateCenter;
import hudson.model.AbstractProject;
import hudson.model.Node.Mode;
import hudson.slaves.CommandLauncher;
import hudson.slaves.DumbSlave;
......@@ -50,6 +51,7 @@ import hudson.slaves.RetentionStrategy;
import hudson.tasks.BuildStep;
import hudson.tasks.Mailer;
import hudson.tasks.Maven;
import hudson.tasks.Ant;
import hudson.tasks.Publisher;
import hudson.tasks.Maven.MavenInstallation;
import hudson.util.ProcessTreeKiller;
......@@ -159,7 +161,7 @@ public abstract class HudsonTestCase extends TestCase {
* <p>
* Unlike Java debugger, which you as a human interfaces directly and interactively,
* this JavaScript debugger is to be interfaced by your program (or through the
* expression evaluation capability of your Java debugger.)
* expression evaluation capability of your Java debugger.)
*/
protected JavaScriptDebugger jsDebugger = new JavaScriptDebugger();
......@@ -173,6 +175,7 @@ public abstract class HudsonTestCase extends TestCase {
protected void setUp() throws Exception {
env.pin();
recipe();
AbstractProject.WORKSPACE.toString();
hudson = newHudson();
hudson.setNoUsageStatistics(true); // collecting usage stats from tests are pointless.
hudson.servletContext.setAttribute("app",hudson);
......@@ -320,6 +323,26 @@ public abstract class HudsonTestCase extends TestCase {
return mavenInstallation;
}
/**
* Extracts Ant and configures it.
*/
protected Ant.AntInstallation configureDefaultAnt() throws Exception {
FilePath ant = hudson.getRootPath().createTempFile("ant", "zip");
OutputStream os = ant.write();
try {
IOUtils.copy(HudsonTestCase.class.getClassLoader().getResourceAsStream("apache-ant-1.7.1-bin.zip"), os);
} finally {
os.close();
}
File antHome = createTmpDir();
ant.unzip(new FilePath(antHome));
Ant.AntInstallation antInstallation = new Ant.AntInstallation("default",
new File(antHome,"apache-ant-1.7.1").getAbsolutePath());
hudson.getDescriptorByType(Ant.DescriptorImpl.class).setInstallations(antInstallation);
return antInstallation;
}
//
// Convenience methods
//
......
......@@ -67,7 +67,14 @@ final class WarExploder {
private static File explode() throws Exception {
// are we in the hudson main workspace? If so, pick up hudson/main/war/resources
// this saves the effort of packaging a war file and makes the debug cycle faster
File d = new File(".").getAbsoluteFile();
// just in case we were started from hudson instead of from hudson/main/...
if (new File(d, "main/war/target/hudson").exists()) {
return new File(d, "main/war/target/hudson");
}
for( ; d!=null; d=d.getParentFile()) {
if(!d.getName().equals("main")) continue;
if(new File(d,".hudson").exists())
......
此差异由.gitattributes 抑制。
......@@ -49,9 +49,11 @@ public class EnvironmentVariableNodePropertyTest extends HudsonTestCase {
* Master properties are available
*/
public void testMasterPropertyOnMaster() throws Exception {
setVariables(Hudson.getInstance(), new Entry("KEY", "masterValue"));
hudson.getGlobalNodeProperties().replaceBy(
Collections.singleton(new EnvironmentVariablesNodeProperty(
new Entry("KEY", "masterValue"))));
Map<String, String> envVars = executeBuild(Hudson.getInstance());
Map<String, String> envVars = executeBuild(hudson);
Assert.assertEquals("masterValue", envVars.get("KEY"));
}
......@@ -60,7 +62,9 @@ public class EnvironmentVariableNodePropertyTest extends HudsonTestCase {
* Both slave and master properties are available, but slave properties have priority
*/
public void testSlaveAndMasterPropertyOnSlave() throws Exception {
setVariables(Hudson.getInstance(), new Entry("KEY", "masterValue"));
hudson.getGlobalNodeProperties().replaceBy(
Collections.singleton(new EnvironmentVariablesNodeProperty(
new Entry("KEY", "masterValue"))));
setVariables(slave, new Entry("KEY", "slaveValue"));
Map<String, String> envVars = executeBuild(slave);
......@@ -79,7 +83,7 @@ public class EnvironmentVariableNodePropertyTest extends HudsonTestCase {
new StringParameterDefinition("KEY", "parameterValue"));
project.addProperty(pdp);
setVariables(Hudson.getInstance(), new Entry("KEY", "masterValue"));
setVariables(hudson, new Entry("KEY", "masterValue"));
setVariables(slave, new Entry("KEY", "slaveValue"));
Map<String, String> envVars = executeBuild(slave);
......@@ -88,23 +92,27 @@ public class EnvironmentVariableNodePropertyTest extends HudsonTestCase {
}
public void testVariableResolving() throws Exception {
setVariables(Hudson.getInstance(), new Entry("KEY1", "value"), new Entry("KEY2", "$KEY1"));
Map<String,String> envVars = executeBuild(Hudson.getInstance());
hudson.getGlobalNodeProperties().replaceBy(
Collections.singleton(new EnvironmentVariablesNodeProperty(
new Entry("KEY1", "value"), new Entry("KEY2", "$KEY1"))));
Map<String,String> envVars = executeBuild(hudson);
Assert.assertEquals("value", envVars.get("KEY1"));
Assert.assertEquals("value", envVars.get("KEY2"));
}
public void testFormRoundTripForMaster() throws Exception {
setVariables(hudson, new Entry("KEY", "value"));
hudson.getGlobalNodeProperties().replaceBy(
Collections.singleton(new EnvironmentVariablesNodeProperty(
new Entry("KEY", "value"))));
WebClient webClient = new WebClient();
HtmlPage page = webClient.getPage(hudson, "configure");
HtmlForm form = page.getFormByName("config");
submit(form);
Assert.assertEquals(1, hudson.getNodeProperties().toList().size());
Assert.assertEquals(1, hudson.getGlobalNodeProperties().toList().size());
EnvironmentVariablesNodeProperty prop = hudson.getNodeProperty(EnvironmentVariablesNodeProperty.class);
EnvironmentVariablesNodeProperty prop = hudson.getGlobalNodeProperties().get(EnvironmentVariablesNodeProperty.class);
Assert.assertEquals(1, prop.getEnvVars().size());
Assert.assertEquals("value", prop.getEnvVars().get("KEY"));
}
......@@ -119,7 +127,7 @@ public class EnvironmentVariableNodePropertyTest extends HudsonTestCase {
Assert.assertEquals(1, slave.getNodeProperties().toList().size());
EnvironmentVariablesNodeProperty prop = slave.getNodeProperty(EnvironmentVariablesNodeProperty.class);
EnvironmentVariablesNodeProperty prop = slave.getNodeProperties().get(EnvironmentVariablesNodeProperty.class);
Assert.assertEquals(1, prop.getEnvVars().size());
Assert.assertEquals("value", prop.getEnvVars().get("KEY"));
}
......
......@@ -96,6 +96,7 @@ public class MavenTest extends HudsonTestCase {
project.setJDK(varJDK);
Build<?,?> build = project.scheduleBuild2(0).get();
Assert.assertEquals(Result.SUCCESS, build.getResult());
}
......
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
*
* 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.tools;
import hudson.model.*;
import hudson.slaves.EnvironmentVariablesNodeProperty.Entry;
import hudson.slaves.DumbSlave;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.slaves.NodeProperty;
import hudson.tasks.Maven;
import hudson.tasks.BatchFile;
import hudson.tasks.Ant;
import hudson.tasks.Ant.AntInstallation;
import hudson.tasks.Maven.MavenInstallation;
import hudson.tasks.Maven.MavenInstallation.DescriptorImpl;
import hudson.maven.MavenBuilder;
import hudson.EnvVars;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Arrays;
import java.util.HashMap;
import junit.framework.Assert;
import org.jvnet.hudson.test.CaptureEnvironmentBuilder;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.SingleFileSCM;
import org.jvnet.hudson.test.HudsonTestCase.WebClient;
import org.codehaus.groovy.tools.shell.Command;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
/**
* This class tests that environment variables from node properties are applied,
* and that the priority is maintained: parameters > slave node properties >
* master node properties
*/
public class ToolLocationNodePropertyTest extends HudsonTestCase {
private DumbSlave slave;
private FreeStyleProject project;
public void testFormRoundTrip() throws Exception {
MavenInstallation.DescriptorImpl mavenDescriptor = hudson.getDescriptorByType(MavenInstallation.DescriptorImpl.class);
mavenDescriptor.setInstallations(new MavenInstallation("maven", "XXX"));
AntInstallation.DescriptorImpl antDescriptor = hudson.getDescriptorByType(AntInstallation.DescriptorImpl.class);
antDescriptor.setInstallations(new AntInstallation("ant", "XXX"));
JDK.DescriptorImpl jdkDescriptor = hudson.getDescriptorByType(JDK.DescriptorImpl.class);
jdkDescriptor.setInstallations(new JDK("jdk", "XXX"));
ToolLocationNodeProperty property = new ToolLocationNodeProperty(
new ToolLocationNodeProperty.ToolLocation(jdkDescriptor, "jdk", "foobar"),
new ToolLocationNodeProperty.ToolLocation(mavenDescriptor, "maven", "barzot"),
new ToolLocationNodeProperty.ToolLocation(antDescriptor, "ant", "zotfoo"));
slave.getNodeProperties().add(property);
WebClient webClient = new WebClient();
HtmlPage page = webClient.getPage(slave, "configure");
HtmlForm form = page.getFormByName("config");
submit(form);
Assert.assertEquals(1, slave.getNodeProperties().toList().size());
ToolLocationNodeProperty prop = slave.getNodeProperties().get(ToolLocationNodeProperty.class);
Assert.assertEquals(3, prop.getLocations().size());
ToolLocationNodeProperty.ToolLocation location = prop.getLocations().get(0);
Assert.assertEquals(jdkDescriptor, location.getType());
Assert.assertEquals("jdk", location.getName());
Assert.assertEquals("foobar", location.getHome());
location = prop.getLocations().get(1);
Assert.assertEquals(mavenDescriptor, location.getType());
Assert.assertEquals("maven", location.getName());
Assert.assertEquals("barzot", location.getHome());
location = prop.getLocations().get(2);
Assert.assertEquals(antDescriptor, location.getType());
Assert.assertEquals("ant", location.getName());
Assert.assertEquals("zotfoo", location.getHome());
}
public void testMaven() throws Exception {
MavenInstallation maven = configureDefaultMaven();
String mavenPath = maven.getHome();
Hudson.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(new MavenInstallation("maven", "THIS IS WRONG"));
project.getBuildersList().add(new Maven("--version", "maven"));
project.getBuildersList().add(new BatchFile("set"));
Build build = project.scheduleBuild2(0).get();
assertBuildStatus(Result.FAILURE, build);
ToolLocationNodeProperty property = new ToolLocationNodeProperty(
new ToolLocationNodeProperty.ToolLocation(hudson.getDescriptorByType(MavenInstallation.DescriptorImpl.class), "maven", mavenPath));
slave.getNodeProperties().add(property);
build = project.scheduleBuild2(0).get();
assertBuildStatus(Result.SUCCESS, build);
}
public void testAnt() throws Exception {
Ant.AntInstallation ant = configureDefaultAnt();
String antPath = ant.getHome();
Hudson.getInstance().getDescriptorByType(Ant.DescriptorImpl.class).setInstallations(new AntInstallation("ant", "THIS IS WRONG"));
project.setScm(new SingleFileSCM("build.xml", "<project name='foo'/>"));
project.getBuildersList().add(new Ant("-version", "ant", null,null,null));
project.getBuildersList().add(new BatchFile("set"));
Build build = project.scheduleBuild2(0).get();
assertBuildStatus(Result.FAILURE, build);
ToolLocationNodeProperty property = new ToolLocationNodeProperty(
new ToolLocationNodeProperty.ToolLocation(hudson.getDescriptorByType(AntInstallation.DescriptorImpl.class), "ant", antPath));
slave.getNodeProperties().add(property);
build = project.scheduleBuild2(0).get();
System.out.println(build.getLog());
assertBuildStatus(Result.SUCCESS, build);
}
// //////////////////////// setup //////////////////////////////////////////
public void setUp() throws Exception {
super.setUp();
EnvVars env = new EnvVars();
env.put("PATH", "empty");
env.put("M2_HOME", "empty");
slave = createSlave(new Label("slave"), env);
project = createFreeStyleProject();
project.setAssignedLabel(slave.getSelfLabel());
}
}
\ No newline at end of file
package hudson.tools;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.recipes.LocalData;
import hudson.tasks.Maven;
import hudson.tasks.Ant;
import hudson.model.JDK;
import hudson.model.Hudson;
import static junit.framework.Assert.*;
import java.util.Arrays;
/**
* @author huybrechts
*/
public class ToolLocationTest extends HudsonTestCase {
/**
* Test xml compatibility since 'extends ToolInstallation'
*/
@LocalData
public void testToolCompatibility() {
Maven.MavenInstallation[] maven = Hudson.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).getInstallations();
assertEquals(maven.length, 1);
assertEquals(maven[0].getHome(), "bar");
assertEquals(maven[0].getMavenHome(), "bar");
assertEquals(maven[0].getName(), "Maven 1");
Ant.AntInstallation[] ant = Hudson.getInstance().getDescriptorByType(Ant.DescriptorImpl.class).getInstallations();
assertEquals(ant.length, 1);
assertEquals(ant[0].getHome(), "foo");
assertEquals(ant[0].getAntHome(), "foo");
assertEquals(ant[0].getName(), "Ant 1");
JDK[] jdk = Hudson.getInstance().getDescriptorByType(JDK.DescriptorImpl.class).getInstallations();
assertEquals(Arrays.asList(jdk), Hudson.getInstance().getJDKs());
assertEquals(2, jdk.length); // HudsonTestCase adds a 'default' JDK
assertEquals("default", jdk[1].getName()); // make sure it's really that we're seeing
assertEquals("FOOBAR", jdk[0].getHome());
assertEquals("FOOBAR", jdk[0].getJavaHome());
assertEquals("1.6", jdk[0].getName());
}
}
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
<numExecutors>2</numExecutors>
<mode>NORMAL</mode>
<authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
<securityRealm class="hudson.security.SecurityRealm$None"/>
<jdks>
<jdk>
<name>1.6</name>
<javaHome>FOOBAR</javaHome>
</jdk>
</jdks>
<clouds/>
<slaves>
<slave>
<name>slave</name>
<description></description>
<remoteFS>c:\temp\hudson</remoteFS>
<numExecutors>1</numExecutors>
<mode>NORMAL</mode>
<retentionStrategy class="hudson.slaves.RetentionStrategy$Always"/>
<launcher class="hudson.slaves.JNLPLauncher"/>
<label></label>
<nodeProperties>
<hudson.tools.ToolLocationNodeProperty>
<locations>
<hudson.tools.ToolLocationNodeProperty_-ToolLocation>
<type>hudson.tasks.Ant$DescriptorImpl</type>
<name>Ant 1</name>
<home>D:\dev\apache-ant-1.7.1</home>
</hudson.tools.ToolLocationNodeProperty_-ToolLocation>
<hudson.tools.ToolLocationNodeProperty_-ToolLocation>
<type>hudson.tasks.Maven$DescriptorImpl</type>
<name>Maven 1</name>
<home>D:\dev\apache-maven-2.0.9</home>
</hudson.tools.ToolLocationNodeProperty_-ToolLocation>
<hudson.tools.ToolLocationNodeProperty_-ToolLocation>
<type>hudson.model.JDK$DescriptorImpl</type>
<name>1.6</name>
<home>C:\Program Files\Java\jdk1.6.0_11</home>
</hudson.tools.ToolLocationNodeProperty_-ToolLocation>
</locations>
</hudson.tools.ToolLocationNodeProperty>
</nodeProperties>
</slave>
</slaves>
<quietPeriod>5</quietPeriod>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>Alle</name>
</hudson.model.AllView>
</views>
<primaryView>Alle</primaryView>
<slaveAgentPort>0</slaveAgentPort>
<label></label>
<nodeProperties/>
<disabledAdministrativeMonitors/>
</hudson>
\ No newline at end of file
<?xml version='1.0' encoding='UTF-8'?>
<hudson.tasks.Ant_-DescriptorImpl>
<installations>
<hudson.tasks.Ant_-AntInstallation>
<name>Ant 1</name>
<antHome>foo</antHome>
</hudson.tasks.Ant_-AntInstallation>
</installations>
</hudson.tasks.Ant_-DescriptorImpl>
\ No newline at end of file
<?xml version='1.0' encoding='UTF-8'?>
<hudson.tasks.Maven_-DescriptorImpl>
<installations>
<hudson.tasks.Maven_-MavenInstallation>
<name>Maven 1</name>
<mavenHome>bar</mavenHome>
</hudson.tasks.Maven_-MavenInstallation>
</installations>
</hudson.tasks.Maven_-DescriptorImpl>
\ No newline at end of file
<div>
You can specify the location of certain tools on this node, overriding the global configuration.
</div>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册