001package io.ebean.docker.commands.process;
002
003import io.ebean.docker.commands.CommandException;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007import java.io.BufferedReader;
008import java.io.IOException;
009import java.io.InputStreamReader;
010import java.util.ArrayList;
011import java.util.List;
012
013/**
014 * Handle the external process response (exit code, std out, std err).
015 */
016public class ProcessHandler {
017
018  private static final Logger log = LoggerFactory.getLogger(ProcessHandler.class);
019
020  private final ProcessBuilder builder;
021
022  private Process process;
023
024  /**
025   * Both stdErr and stdOut merged.
026   */
027  private List<String> out = new ArrayList<>();
028
029  private String match;
030  private String clearMatch;
031
032
033  private ProcessHandler(ProcessBuilder builder, String match, String clearMatch) {
034    this.builder = builder;
035    this.match = match;
036    this.clearMatch = clearMatch;
037  }
038
039  public static ProcessResult matchCommand(String match, String clearMatch, String... command) {
040    return process(new ProcessBuilder(command), match, clearMatch);
041  }
042
043  /**
044   * Process a basic command.
045   */
046  public static ProcessResult command(String... command) {
047    return process(new ProcessBuilder(command));
048  }
049
050  public static ProcessResult command(List<String> commands) {
051    return process(new ProcessBuilder(commands));
052  }
053
054  public static ProcessResult process(ProcessBuilder pb) {
055    return process(pb, null, null);
056  }
057
058  /**
059   * Process a command.
060   */
061  private static ProcessResult process(ProcessBuilder pb, String match, String clearMatch) {
062    try {
063      ProcessHandler handler = new ProcessHandler(pb, match, clearMatch);
064      handler.start();
065      ProcessResult result = handler.read();
066      if (!result.success()) {
067        throw new CommandException("command failed: " + result.getOutLines(), result);
068      }
069      return result;
070
071    } catch (IOException e) {
072      throw new RuntimeException(e);
073    }
074  }
075
076  private void start() throws IOException {
077    // merge input and error streams
078    builder.redirectErrorStream(true);
079    process = builder.start();
080  }
081
082  private ProcessResult read() {
083
084    try {
085      BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
086      String s;
087      while ((s = stdInput.readLine()) != null) {
088        processLine(s, out);
089      }
090
091      int result = process.waitFor();
092      ProcessResult pr = new ProcessResult(result, out);
093      if (!pr.success() && log.isTraceEnabled()) {
094        log.trace(pr.debug());
095      }
096      return pr;
097
098    } catch (Exception e) {
099      throw new RuntimeException(e);
100    }
101  }
102
103  private void processLine(String lineContent, List<String> lines) {
104    if (clearMatch != null && lineContent.contains(clearMatch)) {
105      out.clear();
106    } else {
107      if (match != null) {
108        if (lineContent.contains(match)) {
109          out.add(lineContent);
110        }
111      } else {
112        lines.add(lineContent);
113      }
114    }
115  }
116
117}