diff --git a/core/src/main/java/hudson/model/FreeStyleProject.java b/core/src/main/java/hudson/model/FreeStyleProject.java index a1407951358e704a879b58298396d799d2b95e0e..c7f510d96576c6ab2515706b69dedb0e6926cbf9 100644 --- a/core/src/main/java/hudson/model/FreeStyleProject.java +++ b/core/src/main/java/hudson/model/FreeStyleProject.java @@ -2,12 +2,35 @@ package hudson.model; import hudson.FilePath; +import java.io.File; +import java.io.IOException; + +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; + +import javax.servlet.ServletException; + /** * Free-style software project. * * @author Kohsuke Kawaguchi */ public class FreeStyleProject extends Project implements TopLevelItem { + /** + * User-specified workspace directory, or null if it's up to Hudson. + * + *

+ * Normally a free-style project uses the workspace location assigned by its parent container, + * but sometimes people have builds that have hard-coded paths (which can be only built in + * certain locations. see http://www.nabble.com/Customize-Workspace-directory-tt17194310.html for + * one such discussion.) + * + *

+ * This is not {@link File} because it may have to hold a path representation on another OS. + * + * @since 1.216 + */ + private String customWorkspace; public FreeStyleProject(Hudson parent, String name) { super(parent, name); @@ -23,13 +46,28 @@ public class FreeStyleProject extends Project i return Hudson.getInstance(); } + public String getCustomWorkspace() { + return customWorkspace; + } + @Override public FilePath getWorkspace() { Node node = getLastBuiltOn(); if(node==null) node = getParent(); + if(customWorkspace!=null) + return node.createPath(customWorkspace); return node.getWorkspaceFor(this); } + protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + if(req.hasParameter("customWorkspace")) + customWorkspace = req.getParameter("customWorkspace.directory"); + else + customWorkspace = null; + + super.submit(req, rsp); + } + public DescriptorImpl getDescriptor() { return DESCRIPTOR; } diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index ddcbb3f6c2c3bc8a436568bbaa7b05425b08a117..ba75639ce13e598b13a51e255ef5b3328d4d9405 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -935,6 +935,10 @@ public final class Hudson extends View implements ItemGroup, Node, return new FilePath(getRootDir()); } + public FilePath createPath(String absolutePath) { + return new FilePath((VirtualChannel)null,absolutePath); + } + public ClockDifference getClockDifference() { return ClockDifference.ZERO; } diff --git a/core/src/main/java/hudson/model/Node.java b/core/src/main/java/hudson/model/Node.java index 752160d02ee98fdb592abf6ed2af92a72e2bdb33..13a18affaf5fcf59dc7e1eabd730a26475fdd006 100644 --- a/core/src/main/java/hudson/model/Node.java +++ b/core/src/main/java/hudson/model/Node.java @@ -106,6 +106,11 @@ public interface Node { */ FilePath getRootPath(); + /** + * Gets the {@link FilePath} on this node. + */ + FilePath createPath(String absolutePath); + /** * Estimates the clock difference with this slave. * diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index 31b3ccc524d69b54aa8304f1ef09ebf91b354a8d..381734800695e29fb9fc24ede219fbc2355ed354 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -311,9 +311,13 @@ public final class Slave implements Node, Serializable { } public FilePath getRootPath() { + return createPath(remoteFS); + } + + public FilePath createPath(String absolutePath) { VirtualChannel ch = getComputer().getChannel(); if(ch==null) return null; // offline - return new FilePath(ch,remoteFS); + return new FilePath(ch,absolutePath); } /** diff --git a/core/src/main/resources/hudson/model/FreeStyleProject/configure-advanced.jelly b/core/src/main/resources/hudson/model/FreeStyleProject/configure-advanced.jelly new file mode 100644 index 0000000000000000000000000000000000000000..2d0c2d3c1cfc9034af8317cc7648e415c4b0465f --- /dev/null +++ b/core/src/main/resources/hudson/model/FreeStyleProject/configure-advanced.jelly @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/war/resources/help/project-config/custom-workspace.html b/war/resources/help/project-config/custom-workspace.html new file mode 100644 index 0000000000000000000000000000000000000000..35263c216c392c26c865503fb8b87b32b4232fb6 --- /dev/null +++ b/war/resources/help/project-config/custom-workspace.html @@ -0,0 +1,23 @@ +

+ For each job on Hudson, Hudson allocates a unique "workspace directory." This is the directory + where the code is checked out and builds happen. Normally you should let Hudson allocate + and clean up workspace directories, but in several situations this is problematic, + and in such case, this option lets you specify the workspace location manually. + +

+ Once such situation is where paths are hard-coded and the code needs to be built on a specific location. + (and you can find one such discussion here.) + While there's no doubt that such a build is not ideal, this option allows you to get going in such a situation. + +

+ Another situation where this is useful is when you are using the free-style project type not to perform + a software build, but execution of a certain batch task, perhaps as a cron replacement. In such case, + you can use this option to map the relevant directory as the workspace, so that people can look at files + through the Hudson web UI, and you can kick relevant commands more easily. + +

+ If you are in a distributed build environment, unless you tie a job to a specific node, Hudson may still + move around jobs to different slaves. Sometimes this is desirable, sometimes this is not. Also, + you can map multiple projects to have the same workspace, but if you do so, make sure concurrent executions + of those jobs won't have nasty interferance with each other. +

\ No newline at end of file