All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.typesafe.dbuild.utils.InterruptibleProcess.scala Maven / Gradle / Ivy

The newest version!
// This wrapper class is used to keep track of running Process instances,
// so that they can be preemptively killed if needed, for example if a
// timeout occurs. One wrapper can keep track of only one Process at a time,
// so there will be usually one wrapper per build/extraction worker.
package com.typesafe.dbuild.utils
import sys.process._

class TrackedProcessBuilder {
  var interrupted = false
  var processOpt: Option[Process] = None

  def abort(): Unit = synchronized {
    interrupted = true
    // note: it is safe to call destroy() on the same tracked process multiple times.
    processOpt map { _.destroy() }
  }

  def reset(): Unit = synchronized {
    interrupted = false
    processOpt = None
  }

  def !!(pb: ProcessBuilder, log: ProcessLogger)  = slurp(pb, Some(log), withIn = false)
  def !(pb: ProcessBuilder, log: ProcessLogger)  = runBuffered(pb, log, connectInput = false)

  private def runBuffered(pb: ProcessBuilder, log: ProcessLogger, connectInput: Boolean) =
    log.buffer { track(pb.run(log, connectInput)) }

  private def slurp(pb: ProcessBuilder, log: Option[ProcessLogger], withIn: Boolean): String = {
    val buffer = new StringBuffer
    val code   = track(pb.run(BasicIO(withIn, buffer, log)))
    if (code == 0) buffer.toString
    else scala.sys.error("Nonzero exit value: " + code)
  }

  private def track(f: => Process): Int = {
    val p = synchronized {
      if (interrupted)
        sys.error("Cannot start process: interrupted")
      else {
        val pr = f
        processOpt = Some(pr)
        pr
      }
    }
    val exitVal = p.exitValue()
    synchronized {
      processOpt = None
    }
    exitVal
  }

  // Technically we shouldn't keep
  // tracker instances alive by adding
  // them to a list. However, in the usual
  // case of a single extractor and a single
  // builder, the grand total number of trackers
  // will be two. We can change indexing
  // mechanism, adding a better controller
  // object, in case we start using more
  // extractors and builders, or in the
  // (remote) case we should start creating
  // them dynamically, for some reason.
  TrackedProcessBuilder.record(this)
}

object TrackedProcessBuilder {
  val trackers = new scala.collection.mutable.MutableList[TrackedProcessBuilder]

  def record(t:TrackedProcessBuilder) = synchronized {
    trackers += t
  }

  def abortAll() = synchronized {
    trackers foreach { _.abort() }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy