diff --git a/core/pom.xml b/core/pom.xml index 991cce37117a5f82eb1421c650d9a81f17e36bdf..2caed1b1862e8d9b2a0b8a2ed816e74fd1311fae 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -346,7 +346,7 @@ THE SOFTWARE. org.kohsuke.stapler stapler - 1.93 + 1.95 org.jvnet.localizer diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index ccb5c9a292c6c8e61f75237470212cdc97228228..8ff6a03ced8a45a589f6daa6f7763f6918a0cba9 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -33,13 +33,19 @@ import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.MetaClass; +import org.kohsuke.stapler.WebApp; +import org.kohsuke.stapler.jelly.JellyClassTearOff; import org.springframework.util.StringUtils; import org.jvnet.tiger_types.Types; import org.apache.commons.io.IOUtils; +import org.apache.commons.jelly.Script; +import org.apache.commons.jelly.JellyException; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; +import javax.servlet.ServletException; +import javax.servlet.RequestDispatcher; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -50,6 +56,7 @@ import java.util.List; import java.util.Map; import java.util.HashMap; import java.util.Locale; +import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -59,7 +66,6 @@ import java.lang.reflect.Type; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.beans.Introspector; -import java.net.URL; /** * Metadata about a configurable instance. @@ -355,9 +361,32 @@ public abstract class Descriptor> implements Saveable { * null to indicate that there's no help. */ public String getHelpFile() { - InputStream in = getHelpStream(); + return getHelpFile(null); + } + + /** + * Returns the path to the help screen HTML for the given field. + * + *

+ * The help files are assumed to be at "help/FIELDNAME.html" with possible + * locale variations. + */ + public String getHelpFile(String fieldName) { + if(fieldName==null) fieldName=""; + else fieldName='/'+fieldName; + + String page = "/descriptor/" + clazz.getName() + "/help"+fieldName; + + try { + if(Stapler.getCurrentRequest().getView(clazz,"help"+fieldName+".jelly")!=null) + return page; + } catch (IOException e) { + throw new Error(e); + } + + InputStream in = getHelpStream(fieldName); IOUtils.closeQuietly(in); - if(in!=null) return "/descriptor/"+clazz.getName()+"/help"; + if(in!=null) return page; return null; } @@ -475,8 +504,17 @@ public abstract class Descriptor> implements Saveable { /** * Serves help.html from the resource of {@link #clazz}. */ - public void doHelp(StaplerResponse rsp) throws IOException { - InputStream in = getHelpStream(); + public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { + String path = req.getRestOfPath(); + if(path.contains("..")) throw new ServletException("Illegal path: "+path); + + RequestDispatcher rd = Stapler.getCurrentRequest().getView(clazz, "help"+path+".jelly"); + if(rd!=null) {// Jelly-generated help page + rd.forward(req,rsp); + return; + } + + InputStream in = getHelpStream(path); if(in==null) { rsp.sendError(SC_NOT_FOUND); return; @@ -487,10 +525,10 @@ public abstract class Descriptor> implements Saveable { in.close(); } - private InputStream getHelpStream() { + private InputStream getHelpStream(String suffix) { Locale locale = Stapler.getCurrentRequest().getLocale(); - String base = clazz.getName().replace('.', '/') + "/help"; + String base = clazz.getName().replace('.', '/') + "/help"+suffix; InputStream in; in = clazz.getClassLoader().getResourceAsStream(base + '_' + locale.getLanguage() + '_' + locale.getCountry() + '_' + locale.getVariant() + ".html"); @@ -516,10 +554,7 @@ public abstract class Descriptor> implements Saveable { } public static List toList( T... values ) { - final ArrayList r = new ArrayList(); - for (T v : values) - r.add(v); - return r; + return new ArrayList(Arrays.asList(values)); } public static > @@ -625,4 +660,4 @@ public abstract class Descriptor> implements Saveable { throw new AssertionError(); } } -} +} \ No newline at end of file diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index d735316ade203a749682ae506adad53526e4d9bf..1af08b103172dd8fea8b5c8b6e42cca87c5e5f84 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -27,21 +27,18 @@ import hudson.FilePath; import hudson.Launcher; import hudson.Launcher.RemoteLauncher; import hudson.Util; -import hudson.slaves.ComputerLauncher; -import hudson.slaves.RetentionStrategy; -import hudson.slaves.CommandLauncher; -import hudson.slaves.JNLPLauncher; -import hudson.slaves.SlaveComputer; -import hudson.slaves.DumbSlave; +import hudson.slaves.*; import hudson.model.Descriptor.FormException; import hudson.remoting.Callable; import hudson.remoting.VirtualChannel; import hudson.tasks.DynamicLabeler; import hudson.tasks.LabelFinder; import hudson.util.ClockDifference; +import hudson.util.FormFieldValidator.NonNegativeInteger; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.WebMethod; import org.apache.commons.io.IOUtils; import javax.servlet.ServletException; @@ -391,6 +388,15 @@ public abstract class Slave extends Node implements Serializable { return this; } + public abstract SlaveDescriptor getDescriptor(); + + public static abstract class SlaveDescriptor extends NodeDescriptor { + public void doCheckNumExecutors() throws IOException, ServletException { + new NonNegativeInteger().process(); + } + } + + // // backwrad compatibility // diff --git a/core/src/main/java/hudson/slaves/DumbSlave.java b/core/src/main/java/hudson/slaves/DumbSlave.java index d1d0ad2b6f2e5b0386ab08147fe478c1722b2044..a5927c54f9d24952f8c4c5e7364a4d3897747817 100644 --- a/core/src/main/java/hudson/slaves/DumbSlave.java +++ b/core/src/main/java/hudson/slaves/DumbSlave.java @@ -25,12 +25,8 @@ package hudson.slaves; import hudson.model.Descriptor.FormException; import hudson.model.Slave; -import hudson.util.FormFieldValidator.NonNegativeInteger; import org.kohsuke.stapler.DataBoundConstructor; -import javax.servlet.ServletException; -import java.io.IOException; - /** * Default {@link Slave} implementation for computers that do not belong to a higher level structure, * like grid or cloud. @@ -47,16 +43,12 @@ public final class DumbSlave extends Slave { return DescriptorImpl.INSTANCE; } - public static final class DescriptorImpl extends NodeDescriptor { + public static final class DescriptorImpl extends SlaveDescriptor { public static final DescriptorImpl INSTANCE = new DescriptorImpl(); public String getDisplayName() { return Messages.DumbSlave_displayName(); } - - public void doCheckNumExecutors() throws IOException, ServletException { - new NonNegativeInteger().process(); - } } static { diff --git a/core/src/main/resources/hudson/model/Slave/help/launcher.jelly b/core/src/main/resources/hudson/model/Slave/help/launcher.jelly new file mode 100644 index 0000000000000000000000000000000000000000..01f8c4c467c15312158a1455ebe77029422feb24 --- /dev/null +++ b/core/src/main/resources/hudson/model/Slave/help/launcher.jelly @@ -0,0 +1,40 @@ + + + + +

+ Controls how Hudson starts this slave. + +
+ +
${d.displayName}
+
+ +
+
+
+
+ + \ No newline at end of file diff --git a/core/src/main/resources/hudson/slaves/CommandLauncher/help.jelly b/core/src/main/resources/hudson/slaves/CommandLauncher/help.jelly new file mode 100644 index 0000000000000000000000000000000000000000..8eb19203d6b7ccc9b13ef1aab71f791ada67740f --- /dev/null +++ b/core/src/main/resources/hudson/slaves/CommandLauncher/help.jelly @@ -0,0 +1,29 @@ + + + + Starts a slave by having Hudson execute a command from the master. + Use this when the master is capable of remotely executing a process + on a slave, such as through ssh/rsh. + \ No newline at end of file diff --git a/core/src/main/resources/hudson/slaves/DumbSlave/configure-entries.jelly b/core/src/main/resources/hudson/slaves/DumbSlave/configure-entries.jelly index b89b79821dda405e1fe9846bed6d062b674a4be6..9d5ba795195c94dc3fdaa5db28a973a9de316638 100644 --- a/core/src/main/resources/hudson/slaves/DumbSlave/configure-entries.jelly +++ b/core/src/main/resources/hudson/slaves/DumbSlave/configure-entries.jelly @@ -48,7 +48,7 @@ THE SOFTWARE. + help="${descriptor.getHelpFile('launcher')}"> + + + Starts a slave by launching an agent program through + JNLP. + The launch in this case is initiated by the slave, + although it is possible to start a launch without GUI, for example + as a Windows service. + \ No newline at end of file