class DockerClient {

  public String load(ImageTarball imageTarball, Consumer<Long> writtenByteCountListener)
      throws InterruptedException, IOException {
    // Runs 'docker load'.
    Process dockerProcess = docker("load");

    try (NotifyingOutputStream stdin =
        new NotifyingOutputStream(dockerProcess.getOutputStream(), writtenByteCountListener)) {
      imageTarball.writeTo(stdin);

    } catch (IOException ex) {
      // Tries to read from stderr. Not using getStderrOutput(), as we want to show the error
      // message from the tarball I/O write failure when reading from stderr fails.
      String error;
      try (InputStreamReader stderr =
          new InputStreamReader(dockerProcess.getErrorStream(), StandardCharsets.UTF_8)) {
        error = CharStreams.toString(stderr);
      } catch (IOException ignored) {
        // This ignores exceptions from reading stderr and uses the original exception from
        // writing to stdin.
        error = ex.getMessage();
      }
      throw new IOException("'docker load' command failed with error: " + error, ex);
    }

    try (InputStreamReader stdout =
        new InputStreamReader(dockerProcess.getInputStream(), StandardCharsets.UTF_8)) {
      String output = CharStreams.toString(stdout);

      if (dockerProcess.waitFor() != 0) {
        throw new IOException(
            "'docker load' command failed with error: " + getStderrOutput(dockerProcess));
      }

      return output;
    }
  }

  public  DockerClient(Path dockerExecutable, Map<String, String> dockerEnvironment);
  @VisibleForTesting  DockerClient(Function<List<String>, ProcessBuilder> processBuilderFactory);

}