From 533a1524874d16665ac72352adf6fda71b593fc4 Mon Sep 17 00:00:00 2001
From: Carlo de Wolf <cdewolf@redhat.com>
Date: Thu, 6 May 2010 16:03:07 +0200
Subject: [PATCH] HUDSON-6357: allow specification of a relative target directory

---
 src/main/java/hudson/plugins/git/GitPublisher.java |   20 ++---
 src/main/java/hudson/plugins/git/GitSCM.java       |   78 +++++++++++---------
 .../hudson/plugins/git/GitSCM/config.jelly         |    8 ++
 3 files changed, 61 insertions(+), 45 deletions(-)

diff --git a/src/main/java/hudson/plugins/git/GitPublisher.java b/src/main/java/hudson/plugins/git/GitPublisher.java
index 59ff1b8..1f58bca 100644
--- a/src/main/java/hudson/plugins/git/GitPublisher.java
+++ b/src/main/java/hudson/plugins/git/GitPublisher.java
@@ -2,9 +2,9 @@ package hudson.plugins.git;
 
 import hudson.EnvVars;
 import hudson.Extension;
-import hudson.Launcher;
 import hudson.FilePath;
 import hudson.FilePath.FileCallable;
+import hudson.Launcher;
 import hudson.model.AbstractBuild;
 import hudson.model.AbstractProject;
 import hudson.model.BuildListener;
@@ -16,19 +16,16 @@ import hudson.tasks.BuildStepDescriptor;
 import hudson.tasks.BuildStepMonitor;
 import hudson.tasks.Publisher;
 import hudson.util.FormFieldValidator;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Serializable;
-
-import javax.servlet.ServletException;
-
 import net.sf.json.JSONObject;
-
 import org.kohsuke.stapler.StaplerRequest;
 import org.kohsuke.stapler.StaplerResponse;
 import org.spearce.jgit.transport.RemoteConfig;
 
+import javax.servlet.ServletException;
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+
 public class GitPublisher extends Publisher implements Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -69,9 +66,10 @@ public class GitPublisher extends Publisher implements Serializable {
         }
         final EnvVars environment = tempEnvironment;
 
+        final FilePath workingDirectory = gitSCM.workingDirectory(workspacePath);
         boolean canPerform;
         try {
-            canPerform = build.getWorkspace().act(
+            canPerform = workingDirectory.act(
                     new FileCallable<Boolean>() {
 
                         private static final long serialVersionUID = 1L;
@@ -80,7 +78,7 @@ public class GitPublisher extends Publisher implements Serializable {
                                 VirtualChannel channel) throws IOException {
 
                             IGitAPI git = new GitAPI(
-                                    gitExe, workspacePath,
+                                    gitExe, new FilePath(workspace),
                                     listener, environment);
 
                             // We delete the old tag generated by the SCM plugin
diff --git a/src/main/java/hudson/plugins/git/GitSCM.java b/src/main/java/hudson/plugins/git/GitSCM.java
index 2e129c1..80a91f1 100644
--- a/src/main/java/hudson/plugins/git/GitSCM.java
+++ b/src/main/java/hudson/plugins/git/GitSCM.java
@@ -1,24 +1,13 @@
 package hudson.plugins.git;
 
-import hudson.EnvVars;
-import hudson.Extension;
-import hudson.FilePath;
-import hudson.Launcher;
-import hudson.Proc;
+import hudson.*;
 import hudson.FilePath.FileCallable;
 import hudson.matrix.MatrixBuild;
 import hudson.matrix.MatrixRun;
-import hudson.model.AbstractBuild;
-import hudson.model.AbstractProject;
-import hudson.model.Action;
-import hudson.model.BuildListener;
-import hudson.model.Hudson;
-import hudson.model.ParametersAction;
-import hudson.model.Result;
-import hudson.model.Run;
-import hudson.model.TaskListener;
+import hudson.model.*;
 import hudson.plugins.git.browser.GitWeb;
 import hudson.plugins.git.opt.PreBuildMergeOptions;
+import hudson.plugins.git.util.Build;
 import hudson.plugins.git.util.*;
 import hudson.remoting.VirtualChannel;
 import hudson.scm.ChangeLogParser;
@@ -26,20 +15,6 @@ import hudson.scm.SCM;
 import hudson.scm.SCMDescriptor;
 import hudson.util.FormFieldValidator;
 import hudson.util.FormValidation;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.logging.Logger;
-
-import javax.servlet.ServletException;
-
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.StaplerRequest;
 import org.kohsuke.stapler.StaplerResponse;
@@ -48,6 +23,13 @@ import org.spearce.jgit.lib.RepositoryConfig;
 import org.spearce.jgit.transport.RefSpec;
 import org.spearce.jgit.transport.RemoteConfig;
 
+import javax.servlet.ServletException;
+import java.io.*;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
 /**
  * Git SCM.
  *
@@ -97,6 +79,8 @@ public class GitSCM extends SCM implements Serializable {
     public static final String GIT_BRANCH = "GIT_BRANCH";
     public static final String GIT_COMMIT = "GIT_COMMIT";
 
+   private String relativeTargetDir;
+
     public Collection<SubmoduleConfig> getSubmoduleCfg() {
 		return submoduleCfg;
 	}
@@ -113,7 +97,7 @@ public class GitSCM extends SCM implements Serializable {
             boolean doGenerateSubmoduleConfigurations,
             Collection<SubmoduleConfig> submoduleCfg,
             boolean clean,
-            String choosingStrategy, GitWeb browser) {
+            String choosingStrategy, GitWeb browser, String relativeTargetDir) {
 
 		// normalization
 	    this.branches = branches;
@@ -129,6 +113,8 @@ public class GitSCM extends SCM implements Serializable {
 		this.clean = clean;
         this.choosingStrategy = choosingStrategy;
 		this.configVersion = 1L;
+
+      this.relativeTargetDir = relativeTargetDir;
 	}
 
    public Object readResolve()  {
@@ -249,7 +235,10 @@ public class GitSCM extends SCM implements Serializable {
 
         final String singleBranch = getSingleBranch(lastBuild);
 
-		boolean pollChangesResult = workspace.act(new FileCallable<Boolean>() {
+      FilePath workingDirectory = workingDirectory(workspace);
+      if(!workingDirectory.exists())
+         return true;
+		boolean pollChangesResult = workingDirectory.act(new FileCallable<Boolean>() {
 			private static final long serialVersionUID = 1L;
 
 			public Boolean invoke(File localWorkspace, VirtualChannel channel) throws IOException {
@@ -412,6 +401,10 @@ public class GitSCM extends SCM implements Serializable {
 	    listener.getLogger().println("Checkout:" + workspace.getName() + " / " + workspace.getRemote() + " - " + workspace.getChannel());
         listener.getLogger().println("Using strategy: " + choosingStrategy);
 
+      final FilePath workingDirectory = workingDirectory(workspace);
+      if(!workingDirectory.exists())
+         workingDirectory.mkdirs();
+      
 		final String projectName = build.getProject().getName();
 		final int buildNumber = build.getNumber();
 		final String gitExe = getDescriptor().getGitExe();
@@ -443,7 +436,7 @@ public class GitSCM extends SCM implements Serializable {
 
         final Revision parentLastBuiltRev = tempParentLastBuiltRev;
 
-		final Revision revToBuild = workspace.act(new FileCallable<Revision>() {
+		final Revision revToBuild = workingDirectory.act(new FileCallable<Revision>() {
 			private static final long serialVersionUID = 1L;
 			public Revision invoke(File localWorkspace, VirtualChannel channel)
 					throws IOException {
@@ -531,7 +524,7 @@ public class GitSCM extends SCM implements Serializable {
 
 		if (mergeOptions.doMerge()) {
 			if (!revToBuild.containsBranchName(mergeOptions.getRemoteBranchName())) {
-				returnData = workspace.act(new FileCallable<Object[]>() {
+				returnData = workingDirectory.act(new FileCallable<Object[]>() {
 					private static final long serialVersionUID = 1L;
 					public Object[] invoke(File localWorkspace, VirtualChannel channel)
 							throws IOException {
@@ -616,7 +609,7 @@ public class GitSCM extends SCM implements Serializable {
 
 		// No merge
 
-		returnData = workspace.act(new FileCallable<Object[]>() {
+		returnData = workingDirectory.act(new FileCallable<Object[]>() {
 			private static final long serialVersionUID = 1L;
 			public Object[] invoke(File localWorkspace, VirtualChannel channel)
 					throws IOException {
@@ -868,7 +861,8 @@ public class GitSCM extends SCM implements Serializable {
 					submoduleCfg,
 					req.getParameter("git.clean") != null,
                     req.getParameter("git.choosing_strategy"),
-					gitWeb);
+					gitWeb,
+               req.getParameter("git.relativeTargetDir"));
 		}
 
 
@@ -980,4 +974,20 @@ public class GitSCM extends SCM implements Serializable {
 		else
 			return buildData;
     }
+
+   /**
+    * @param workspace
+    * @return
+    */
+   protected FilePath workingDirectory(FilePath workspace)
+   {
+      if(relativeTargetDir == null || relativeTargetDir.length() == 0 || relativeTargetDir.equals("."))
+         return workspace;
+      return workspace.child(relativeTargetDir);
+   }
+
+   public String getRelativeTargetDir()
+   {
+      return relativeTargetDir;
+   }
 }
diff --git a/src/main/resources/hudson/plugins/git/GitSCM/config.jelly b/src/main/resources/hudson/plugins/git/GitSCM/config.jelly
index d1b49e6..c5c9543 100644
--- a/src/main/resources/hudson/plugins/git/GitSCM/config.jelly
+++ b/src/main/resources/hudson/plugins/git/GitSCM/config.jelly
@@ -67,6 +67,14 @@
   
   </f:entry>
 
+   <f:entry title="Checkout place">
+      <table width="100%">
+         <f:entry title="Relative target directory">
+            <f:textbox name="git.relativeTargetDir" value="${scm.relativeTargetDir}"/>
+         </f:entry>
+      </table>
+   </f:entry>
+
   <f:advanced>
          <!-- This needs more thought
   <f:entry title="Autogenerate submodule configurations">
-- 
1.6.3.3

