public static Killer startDaemon(
      InvocationOutputHandler buildLogHandler,
      InvocationOutputHandler consoleLogHandler,
      Map<String, String> envVarsForApp,
      CommandLine command,
      File projectRoot,
      Waiter startupWaiter) {
    long startTime = logStartInfo(command, projectRoot);
    Killer watchDog = new Killer(ExecuteWatchdog.INFINITE_TIMEOUT);
    Executor executor = createExecutor(consoleLogHandler, command, projectRoot, watchDog);

    try {
      DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
      executor.execute(command, envVarsForApp, handler);

      startupWaiter.or(c -> handler.hasResult()); // stop waiting if the process exist
      startupWaiter.blockUntilReady();

      if (handler.hasResult()) {
        String message =
            "The project at "
                + dirPath(projectRoot)
                + " started but exited all too soon. Check the console log for information.";
        buildLogHandler.consumeLine(message);
        throw new ProjectCannotStartException(message);
      }
    } catch (TimeoutException te) {
      String message =
          "Built successfully, but timed out waiting for startup at " + dirPath(projectRoot);
      watchDog.destroyProcess();
      buildLogHandler.consumeLine(message);
      throw new ProjectCannotStartException(message);
    } catch (ProjectCannotStartException pcse) {
      throw pcse;
    } catch (Exception e) {
      String message = "Built successfully, but error on start for " + dirPath(projectRoot);
      buildLogHandler.consumeLine(message);
      buildLogHandler.consumeLine(e.toString());
      throw new ProjectCannotStartException(message, e);
    }

    logEndTime(command, startTime);
    return watchDog;
  }