package com.codicesoftware.plugins.hudson;

import hudson.AbortException;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Proc;
import hudson.model.TaskListener;
import hudson.util.ForkOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.logging.Logger;

/**
 * Class that encapsulates the Plastic SCM command client.
 *
 * @author Erik Ramfelt
 * @author Dick Porter
 */
public class PlasticTool {
    private final String executable;
    private Launcher launcher;
    private TaskListener listener;
    private FilePath workspace;

    private static final int MAX_RETRIES = 3;
    private static final int TIME_BETWEEN_RETRIES = 500;

    private static final Logger logger = Logger.getLogger(PlasticTool.class.getName());

    public PlasticTool(String executable, Launcher launcher, TaskListener listener,
            FilePath workspace) {
        this.executable = executable;
        this.launcher = launcher;
        this.listener = listener;
        this.workspace = workspace;
    }

    /**
     * Execute the arguments, and return the console output as a Reader
     * @param arguments arguments to send to the command-line client.
     * @return a Reader containing the console output
     * @throws IOException
     * @throws InterruptedException
     */
    public Reader execute(String[] arguments) throws IOException, InterruptedException {
        return execute(arguments, null);
    }
    public Reader execute(String[] arguments, FilePath executionPath) throws IOException, InterruptedException {
        String[] cmdArgs = getToolArguments(arguments);

        int retries = 0;
        while (retries < MAX_RETRIES) {
            Reader result = tryExecute(cmdArgs, executionPath);
            if (result != null)
                return result;

            retries++;
            logger.warning(String.format(
                "The cm command '%s' failed. Retrying after %d ms... (%d)",
                arguments[0], TIME_BETWEEN_RETRIES, retries));
            Thread.sleep(TIME_BETWEEN_RETRIES);
        }
        listener.fatalError(String.format(
            "The cm command '%s' failed after %d retries", arguments[0], MAX_RETRIES));
        throw new AbortException();
    }

    private String[] getToolArguments(String[] cmArgs) {
        String[] result = new String[cmArgs.length + 1];
        result[0] = executable;
        System.arraycopy(cmArgs, 0, result, 1, cmArgs.length);
        return result;
    }

    private Reader tryExecute(String[] cmdArgs, FilePath executionPath) throws IOException, InterruptedException {
        if(executionPath == null)
            executionPath = workspace;
        ByteArrayOutputStream consoleStream = new ByteArrayOutputStream();
        Proc proc = launcher.launch().cmds(cmdArgs)
                .stdout(new ForkOutputStream(consoleStream, listener.getLogger()))
                .pwd(executionPath).start();
        consoleStream.close();

        if (proc.join() == 0)
            return new InputStreamReader(new ByteArrayInputStream(consoleStream.toByteArray()));
        return null;
    }
}
@@ -1719,16 +1719,62 @@
 uments);
+%0A        String cliLine = getCliLine(cmdArgs);
 %0A%0A      
@@ -2117,28 +2117,23 @@
         
-arguments%5B0%5D
+cliLine
 , TIME_B
@@ -2217,24 +2217,25 @@
       %7D%0A
+%0A
         
 listener
@@ -2230,28 +2230,30 @@
     
-listener.fatalError(
+String errorMessage = 
 Stri
@@ -2255,32 +2255,36 @@
  String.format(%0A
+    
             %22The
@@ -2330,20 +2330,15 @@
 s%22, 
-arguments%5B0%5D
+cliLine
 , MA
@@ -2347,16 +2347,58 @@
 RETRIES)
+;%0A        listener.fatalError(errorMessage
 );%0A     
@@ -2425,16 +2425,28 @@
 ception(
+errorMessage
 );%0A    %7D
@@ -2678,32 +2678,327 @@
  result;%0A    %7D%0A%0A
+    private String getCliLine(String%5B%5D args) %7B%0A        StringBuilder builder = new StringBuilder();%0A        for (String arg : args) %7B%0A            if (builder.length() != 0)%0A                builder.append(' ');%0A            builder.append(arg);%0A        %7D%0A        return builder.toString();%0A    %7D%0A%0A
     private Read

Improve error logging and exception message in PlasticTool