package hudson;

import hudson.util.DualOutputStream;
import hudson.util.EncodingStream;

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * Entry point to Hudson from command line.
 *
 * <p>
 * This tool runs another process and sends its result to Hudson.
 *
 * @author Kohsuke Kawaguchi
 */
public class Main {
    public static void main(String[] args) {
        try {
            System.exit(run(args));
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

    public static int run(String[] args) throws Exception {
        String home = getHudsonHome();
        if(home==null) {
            System.err.println("HUDSON_HOME is not set.");
            return -1;
        }

        return remotePost(args);
    }

    private static String getHudsonHome() {
        return EnvVars.masterEnvVars.get("HUDSON_HOME");
    }

    /**
     * Run command and place the result to a remote Hudson installation
     */
    public static int remotePost(String[] args) throws Exception {
        String projectName = args[0];

        String home = getHudsonHome();
        if(!home.endsWith("/"))     home = home + '/';  // make sure it ends with '/'

        {// check if the home is set correctly
            HttpURLConnection con = (HttpURLConnection)new URL(home).openConnection();
            con.connect();
            if(con.getResponseCode()!=200
            || con.getHeaderField("X-Hudson")==null) {
                System.err.println(home+" is not Hudson ("+con.getResponseMessage()+")");
                return -1;
            }
        }

        String projectNameEnc = URLEncoder.encode(projectName,"UTF-8").replaceAll("\\+","%20");

        {// check if the job name is correct
            HttpURLConnection con = (HttpURLConnection)new URL(home+"job/"+projectNameEnc+"/acceptBuildResult").openConnection();
            con.connect();
            if(con.getResponseCode()!=200) {
                System.err.println(projectName+" is not a valid job name on "+home+" ("+con.getResponseMessage()+")");
                return -1;
            }
        }

        // start a remote connection
        HttpURLConnection con = (HttpURLConnection) new URL(home+"job/"+projectNameEnc+"/postBuildResult").openConnection();
        con.setDoOutput(true);
        con.connect();
        OutputStream os = con.getOutputStream();
        Writer w = new OutputStreamWriter(os,"UTF-8");
        w.write("<?xml version='1.0' encoding='UTF-8'?>");
        w.write("<run><log encoding='hexBinary'>");
        w.flush();

        // run the command
        long start = System.currentTimeMillis();

        List<String> cmd = new ArrayList<String>();
        for( int i=1; i<args.length; i++ )
            cmd.add(args[i]);
        Proc proc = new Proc.LocalProc(cmd.toArray(new String[0]),(String[])null,System.in,
            new DualOutputStream(System.out,new EncodingStream(os)));

        int ret = proc.join();

        w.write("</log><result>"+ret+"</result><duration>"+(System.currentTimeMillis()-start)+"</duration></run>");
        w.close();

        if(con.getResponseCode()!=200) {
            Util.copyStream(con.getErrorStream(),System.err);
        }

        return ret;
    }
}

@@ -90,32 +90,89 @@
 %0Aimport java.io.
+File;%0Aimport java.io.FileInputStream;%0Aimport java.io.File
 OutputStream;%0Aim
@@ -219,32 +219,68 @@
 java.io.Writer;%0A
+import java.net.HttpRetryException;%0A
 import java.net.
@@ -2400,208 +2400,139 @@
  // 
-start a remote connection%0A        HttpURLConnection con = (HttpURLConnection) new URL(home+%22job/%22+projectNameEnc+%22/postBuildResult%22).openConnection();%0A        con.setDoOutput(true);%0A        con.connec
+write the output to a temporary file first.%0A        File tmpFile = File.createTempFile(%22hudson%22,%22log%22);%0A        tmpFile.deleteOnExi
 t();
@@ -2540,16 +2540,20 @@
         
+File
 OutputSt
@@ -2562,23 +2562,24 @@
 am os = 
-con.get
+new File
 OutputSt
@@ -2583,19 +2583,27 @@
 tStream(
+tmpFile
 );%0A
+%0A
         
@@ -3309,24 +3309,694 @@
 w.close();%0A%0A
+        String location = home+%22job/%22+projectNameEnc+%22/postBuildResult%22;%0A        while(true) %7B%0A            try %7B%0A                // start a remote connection%0A                HttpURLConnection con = (HttpURLConnection) new URL(location).openConnection();%0A                con.setDoOutput(true);%0A                // this tells HttpURLConnection not to buffer the whole thing%0A                con.setFixedLengthStreamingMode((int)tmpFile.length());%0A                con.connect();%0A                // send the data%0A                FileInputStream in = new FileInputStream(tmpFile);%0A                Util.copyStream(in,con.getOutputStream());%0A                in.close();%0A%0A        
         if(c
@@ -4016,32 +4016,40 @@
 eCode()!=200) %7B%0A
+        
             Util
@@ -4094,35 +4094,51 @@
 m.err);%0A        
-%7D%0A%0A
+        %7D%0A%0A        
         return r
@@ -4141,16 +4141,360 @@
 rn ret;%0A
+            %7D catch (HttpRetryException e) %7B%0A                if(e.getLocation()!=null) %7B%0A                    // retry with the new location%0A                    location = e.getLocation();%0A                    continue;%0A                %7D%0A                // otherwise failed for reasons beyond us.%0A                throw e;%0A            %7D%0A        %7D%0A
     %7D%0A%7D%0A

write to a file first and used the fixed content-length mode to avoid buffering.