package nu.studer.teamcity.buildscan.agent;

import jetbrains.buildServer.agent.BuildRunnerContext;
import jetbrains.buildServer.agent.ToolCannotBeFoundException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Executes Maven commands and returns their output, both standard output and standard error, when given a {@link BuildRunnerContext}.
 */
final class MavenCommandExecutor {

    private final BuildRunnerContext runnerContext;

    MavenCommandExecutor(BuildRunnerContext context) {
        this.runnerContext = context;
    }

    @NotNull
    Result execute(String args) throws IOException {
        File mavenExec = getMvnExec();
        if (mavenExec == null) {
            return new Result();
        }

        String command = mavenExec.getAbsolutePath() + " " + args;
        ProcessBuilder processBuilder = new ProcessBuilder(command.split(" ")).redirectErrorStream(true);
        return new Result(processBuilder.start());
    }

    @Nullable
    private File getMvnExec() {
        String mavenPath;
        try {
            mavenPath = runnerContext.getToolPath("maven");
        } catch (ToolCannotBeFoundException e) {
            return null;
        }

        File installationBinDir = new File(mavenPath, "bin");
        String mvnExecutableName = System.getProperty("os.name").toLowerCase().contains("win") ? "mvn.cmd" : "mvn";
        return new File(installationBinDir, mvnExecutableName);
    }

    public static class Result {

        private final Process process;
        private String output;

        public Result() {
            process = null;
        }

        public Result(Process process) {
            this.process = process;
        }

        public boolean isSuccessful() throws InterruptedException {
            if (process == null) {
                return false;
            }

            process.waitFor();

            return process.exitValue() == 0;
        }

        @NotNull
        public String getOutput() throws InterruptedException, IOException {
            if (process == null || !isSuccessful()) {
                return "";
            }

            if (output == null) {
                // this logic eagerly consumes the entire output into memory, which should not be an issue when only
                // used for `mvn --version`, which generates ~5 lines of output
                // this should be revisited if other commands are executed here
                StringBuilder sb = new StringBuilder();
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

                int ch;
                while ((ch = reader.read()) != -1) {
                    sb.append((char) ch);
                }

                output = sb.toString();
            }

            return output;
        }

    }

}

@@ -744,32 +744,54 @@
 rows IOException
+, InterruptedException
  %7B%0A        File 
@@ -1074,34 +1074,34 @@
         
-return new Result(
+Process process = 
 processB
@@ -1114,16 +1114,79 @@
 .start()
+;%0A        process.waitFor();%0A%0A        return new Result(process
 );%0A    %7D
@@ -1966,39 +1966,11 @@
 ul()
- throws InterruptedException
  %7B%0A
+
     
@@ -2049,40 +2049,8 @@
  %7D%0A%0A
-            process.waitFor();%0A%0A
     
@@ -2114,24 +2114,24 @@
    @NotNull%0A
+
         publ
@@ -2162,30 +2162,8 @@
 rows
- InterruptedException,
  IOE

Allow process to finish execution before constructing the result