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

com.fulcrumgenomics.util.Rscript.scala Maven / Gradle / Ivy

The newest version!
/*
 * The MIT License
 *
 * Copyright (c) 2017 Fulcrum Genomics LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.fulcrumgenomics.util

import java.nio.file.Path

import com.fulcrumgenomics.commons.util.LazyLogging

import scala.util.{Success, Try}

/**
  * Object that enables running of R scripts via the Rscript command line too.
  */
object Rscript extends LazyLogging {
  /** The name of the Rscript executable. */
  private val Executable = "Rscript"

  /** Exception class that holds onto an executable's exit/status code. */
  case class RscriptException(status: Int) extends RuntimeException {
    override def getMessage: String = s"Rscript failed with exit code ${status}."
  }

  /** Returns true if R and ggplot2 are available and false otherwise. */
  lazy val Available: Boolean = {
    try {
      val process = new ProcessBuilder(Executable, "-e", "stopifnot(require(ggplot2))").redirectErrorStream(true).start()
      process.waitFor() == 0
    }
    catch { case e: Exception => false }
  }

  /** Executes an Rscript from the classpath if Rscript is available. */
  def execIfAvailable(scriptResource: String, args: String*): Try[Unit] =
    if (Available) exec(scriptResource, args:_*) else Success(())

  /** Executes an Rscript from a script stored at a Path if Rscript is available. */
  def execIfAvailable(script: Path, args: String*): Try[Unit] =
    if (Available) exec(script, args:_*) else Success(())

  /** Executes an Rscript from the classpath. */
  def exec(scriptResource: String, args: String*): Try[Unit] =
    Try { writeResourceToTempFile(scriptResource) }.map(path => exec(path, args:_*))

  /** Executes an Rscript from a script stored at a Path. */
  def exec(script: Path, args: String*): Try[Unit] = Try {
    val command = Rscript.Executable +: script.toAbsolutePath.toString +: args
    val process = new ProcessBuilder(command:_*).redirectErrorStream(false).start()
    val pipe1   = Io.pipeStream(process.getErrorStream, logger.info)
    val pipe2   = Io.pipeStream(process.getInputStream, logger.debug)
    val retval  = process.waitFor()
    pipe1.close()
    pipe2.close()

    if (retval != 0) throw RscriptException(retval)
  }

  /** Extracts a resource from the classpath and writes it to a temp file on disk. */
  private def writeResourceToTempFile(resource: String): Path = {
    val lines = Io.readLinesFromResource(resource).toSeq
    val path = Io.makeTempFile("script.", ".R")
    path.toFile.deleteOnExit()
    Io.writeLines(path, lines)
    path
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy