/**
     * Runs Docker command using Docker CLI.
     *
     * @param cmd Command to be executed
     * @param logStdOut If true, propagate STDOUT to the build log
     * @param logStdErr If true, propagate STDERR to the build log
     * @return Execution result
     * @throws IOException Execution error
     * @throws InterruptedException The build has been interrupted
     */
    private @Nonnull Result executeCmd(@Nonnull String cmd, boolean logStdOut, boolean logStdErr)
        throws IOException, InterruptedException {
      ByteArrayOutputStream baosStdOut = new ByteArrayOutputStream();
      ByteArrayOutputStream baosStdErr = new ByteArrayOutputStream();
      OutputStream stdout =
          logStdOut ? new TeeOutputStream(listener.getLogger(), baosStdOut) : baosStdOut;
      OutputStream stderr =
          logStdErr ? new TeeOutputStream(listener.getLogger(), baosStdErr) : baosStdErr;

      // get Docker registry credentials
      KeyMaterial registryKey = getRegistry().newKeyMaterialFactory(build).materialize();
      // Docker server credentials. If server is null (right after upgrading) do not use credentials
      KeyMaterial serverKey =
          server == null ? null : server.newKeyMaterialFactory(build).materialize();

      logger.log(Level.FINER, "Executing: {0}", cmd);

      try {
        EnvVars env = new EnvVars();
        env.putAll(build.getEnvironment(listener));
        env.putAll(registryKey.env());
        if (serverKey != null) {
          env.putAll(serverKey.env());
        }

        boolean result =
            launcher
                    .launch()
                    .envs(env)
                    .pwd(build.getWorkspace())
                    .stdout(stdout)
                    .stderr(stderr)
                    .cmdAsSingleString(cmd)
                    .start()
                    .join()
                == 0;

        // capture the stdout so it can be parsed later on
        final String stdOutStr = DockerCLIHelper.getConsoleOutput(baosStdOut, logger);
        final String stdErrStr = DockerCLIHelper.getConsoleOutput(baosStdErr, logger);
        return new Result(result, stdOutStr, stdErrStr);

      } finally {
        registryKey.close();
        if (serverKey != null) {
          serverKey.close();
        }
      }
    }
    void processFingerprints(@Nonnull String image) throws IOException, InterruptedException {
      if (!createFingerprint) {
        return;
      }

      // Retrieve full image ID using another call
      final Result response = executeCmd("docker inspect " + image, false, true);
      if (!response.result) {
        return; // Bad result, cannot do anything
      }
      final InspectImageResponse rsp = DockerCLIHelper.parseInspectImageResponse(response.stdout);
      if (rsp == null) {
        return; // Cannot process the data
      }

      //  Create or retrieve the fingerprint
      DockerFingerprints.addFromFacet(rsp.getParent(), rsp.getId(), build);
    }