public static void setNotifierConfiguration(String id, PropertyTree config, Project project) {
    PropertyTree current = getSubTree(KEY_NOTIFIERS).getSubTree(project.getId()).getSubTree(id);

    for (String name : config.getPropertyNames()) {
      current.setProperty(name, config.getProperty(name));
    }
  }
  protected static void runBuild(
      CommandLineProject project,
      PropertyTree config,
      File dir,
      File output,
      Build build,
      long buildId) {
    int result = -1;
    Writer buildOut = null;
    Process process = null;
    StreamGobbler serr = null, sout = null;
    try {
      buildOut = new FileWriter(output);

      String command = config.getProperty(CIApplication.CONFIGURATION_COMMAND_LINE.getKey());
      if (command == null) {
        command = (String) CIApplication.CONFIGURATION_COMMAND_LINE.getDefault();
      }

      // wrap it in a shell call so we can do things like "make && make install"
      String[] commands = new String[3];
      commands[0] = "sh";
      commands[1] = "-c";
      commands[2] = command;
      process = Runtime.getRuntime().exec(commands, null, dir);

      serr = new StreamGobbler(new InputStreamReader(process.getErrorStream()), buildOut);
      sout = new StreamGobbler(new InputStreamReader(process.getInputStream()), buildOut);
      serr.start();
      sout.start();

      result = process.waitFor();
    } catch (InterruptedException e) {
      // TODO use this hook when we cancel the process
    } catch (IOException e) {
      e.printStackTrace(new PrintWriter(buildOut));
      log.error("Unable to write to build output file - reported in build log", e);
    } finally {
      if (process != null) {
        // defensively try to close the gobblers
        if (serr != null && sout != null) {
          // check that our gobblers are finished...
          while (!serr.isComplete() || !sout.isComplete()) {
            log.debug("waiting 1s to close gobbler");
            try {
              Thread.sleep(1000);
            } catch (InterruptedException e) {
              // we were just trying to tidy up...
            }
          }
        }

        IOUtil.close(process.getOutputStream());
        IOUtil.close(process.getErrorStream());
        IOUtil.close(process.getInputStream());
        process.destroy();
      }

      IOUtil.close(buildOut);
    }

    build.setEndTime(new Date());
    if (result != 0) {
      build.setStatus(Build.BUILD_FAILED);
    } else {
      build.setStatus(Build.BUILD_SUCCEEDED);
    }
  }