package org.elasticsearch.gradle;

import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.gradle.api.tasks.Exec;
import org.gradle.process.BaseExecSpec;
import org.gradle.process.ExecResult;
import org.gradle.process.ExecSpec;
import org.gradle.process.JavaExecSpec;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.function.Function;

/**
 * A wrapper around gradle's Exec task to capture output and log on error.
 */
@SuppressWarnings("unchecked")
public class LoggedExec extends Exec {

    public LoggedExec() {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        if (getLogger().isInfoEnabled() == false) {
            setStandardOutput(output);
            setErrorOutput(output);
            setIgnoreExitValue(true);
            doLast((unused) -> {
                    if (getExecResult().getExitValue() != 0) {
                        try {
                            for (String line : output.toString("UTF-8").split("\\R")) {
                                getLogger().error(line);
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new GradleException("Failed to read exec output", e);
                        }
                        throw new GradleException(
                            String.format(
                                "Process '%s %s' finished with non-zero exit value %d",
                                getExecutable(),
                                getArgs(),
                                getExecResult().getExitValue()
                            )
                        );
                    }
                }
            );
        }
    }

    public static ExecResult exec(Project project, Action<ExecSpec> action) {
        return genericExec(project, project::exec, action);
    }

    public static ExecResult javaexec(Project project, Action<JavaExecSpec> action) {
        return genericExec(project, project::javaexec, action);
    }

    private static <T extends BaseExecSpec>  ExecResult genericExec(
        Project project,
        Function<Action<T>,ExecResult> function,
        Action<T> action
    ) {
        if (project.getLogger().isInfoEnabled()) {
            return function.apply(action);
        }
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        try {
            return function.apply(spec -> {
                spec.setStandardOutput(output);
                spec.setErrorOutput(output);
                action.execute(spec);
            });
        } catch (Exception e) {
            try {
                for (String line : output.toString("UTF-8").split("\\R")) {
                    project.getLogger().error(line);
                }
            } catch (UnsupportedEncodingException ue) {
                throw new GradleException("Failed to read exec output", ue);
            }
            throw e;
        }
    }
}

@@ -677,32 +677,99 @@
 OutputStream();%0A
+        ByteArrayOutputStream error = new ByteArrayOutputStream();%0A
         if (getL
@@ -800,24 +800,24 @@
 == false) %7B%0A
-
             
@@ -862,38 +862,37 @@
  setErrorOutput(
-output
+error
 );%0A            s
@@ -1070,35 +1070,101 @@
         
-for (String line : 
+getLogger().error(%22Standard output:%22);%0A                            getLogger().error(
 output.t
@@ -1179,36 +1179,19 @@
 %22UTF-8%22)
-.split(%22%5C%5CR%22)) %7B%0A   
+);%0A
         
@@ -1202,33 +1202,32 @@
                 
- 
 getLogger().erro
@@ -1220,36 +1220,49 @@
 tLogger().error(
-line
+%22Standard error:%22
 );%0A             
@@ -1268,33 +1268,75 @@
                 
-%7D
+getLogger().error(error.toString(%22UTF-8%22));
 %0A               
@@ -2609,32 +2609,99 @@
 OutputStream();%0A
+        ByteArrayOutputStream error = new ByteArrayOutputStream();%0A
         try %7B%0A  
@@ -2690,32 +2690,32 @@
 ;%0A        try %7B%0A
-
             retu
@@ -2822,30 +2822,29 @@
 ErrorOutput(
-output
+error
 );%0A         
@@ -2958,27 +2958,97 @@
     
-for (String line : 
+project.getLogger().error(%22Standard output:%22);%0A                project.getLogger().error(
 outp
@@ -3071,29 +3071,11 @@
 -8%22)
-.split(%22%5C%5CR%22)) %7B%0A    
+);%0A
     
@@ -3116,12 +3116,25 @@
 ror(
-line
+%22Standard error:%22
 );%0A 
@@ -3140,33 +3140,83 @@
                 
-%7D
+project.getLogger().error(error.toString(%22UTF-8%22));
 %0A            %7D c

Improve logged exec output readability (#36217)