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

skinny.assets.SassCompiler.scala Maven / Gradle / Ivy

There is a newer version: 2.3.0-RC1
Show newest version
package skinny.assets

import scala.sys.process._
import java.io.{ IOException, ByteArrayInputStream }
import skinny.util.LoanPattern._
import skinny.exception.AssetsPrecompileFailureException
import org.slf4j.LoggerFactory

/**
 * Sass Compiler
 *
 * @see https://github.com/jlitola/play-sass
 */
class SassCompiler {

  private[this] val log = LoggerFactory.getLogger(classOf[SassCompiler])

  private[this] def isWindows = System.getProperty("os.name").toLowerCase().indexOf("win") >= 0

  private[this] def sassCommand = if (isWindows) "sass.bat" else "sass"

  /**
   * Ensures sass command exists.
   */
  private[this] def ensureSassCommand() = {
    try {
      Seq(sassCommand, "-v").lines // > /dev/null
    } catch {
      case e: IOException =>
        throw new AssetsPrecompileFailureException(
          "Failed to run sass command! sass should be prepared in advance. " +
            "If you haven't install sass yet, just run `gem install sass` now."
        )
    }
  }

  /**
   * Compiles scss code to css code.
   * @param scssCode scss code
   * @return css code
   */
  def compile(path: String, scssCode: String): String = {
    ensureSassCommand()
    val (out, err) = (new StringBuilder, new StringBuilder)
    val processLogger = ProcessLogger(
      (o: String) => out ++= o ++= "\n",
      (e: String) => err ++= e ++= "\n"
    )
    using(new ByteArrayInputStream(scssCode.getBytes)) { stdin =>
      val exitCode = (Seq(sassCommand, "--stdin", "--trace", "--scss") #< stdin) ! processLogger
      if (exitCode == 0) out.toString
      else {
        val message = s"Failed to compile scss code! (exit code: ${exitCode})\n\n${err.toString}"
        log.error(message)
        throw new AssetsPrecompileFailureException(message)
      }
    }
  }

  /**
   * Compiles sass code to css code.
   *
   * @see http://sass-lang.com/documentation/file.INDENTED_SYNTAX.html
   * @param sassCode sass code
   * @return css code
   */
  def compileIndented(path: String, sassCode: String): String = {
    ensureSassCommand()
    val (out, err) = (new StringBuilder, new StringBuilder)
    val processLogger = ProcessLogger(
      (o: String) => out ++= o ++= "\n",
      (e: String) => err ++= e ++= "\n"
    )
    using(new ByteArrayInputStream(sassCode.getBytes)) { stdin =>
      val exitCode = (Seq(sassCommand, "--stdin", "--trace") #< stdin) ! processLogger
      if (exitCode == 0) out.toString
      else {
        val message = s"Failed to compile sass code! (exit code: ${exitCode})\n\n${err.toString}"
        log.error(message)
        throw new AssetsPrecompileFailureException(message)
      }
    }
  }

}

object SassCompiler extends SassCompiler




© 2015 - 2025 Weber Informatics LLC | Privacy Policy