alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Play Framework/Scala example source code file (RoutesCompiler.scala)

This example Play Framework source code file (RoutesCompiler.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Play Framework (and Scala) source code examples by using tags.

All credit for the original source code belongs to Play Framework; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Play Framework tags/keywords

api, boolean, file, left, logger, nil, play, play framework, plugin, routescompilerop, sbt, seq, settingkey, taskkey, whether

The RoutesCompiler.scala Play Framework example source code

/*
 * Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
 */
package play.sbtplugin.routes

import sbt._
import sbt.Keys._
import play.PlayExceptions.RoutesCompilationException
import com.typesafe.sbt.web.incremental._
import play.api.PlayException
import play.router.RoutesCompiler.RoutesCompilationError
import sbt.plugins.JvmPlugin

object RoutesKeys {
  val routesFiles = TaskKey[Seq[File]]("play-routes-files", "The routes files to compile")
  val routes = TaskKey[Seq[File]]("play-routes", "Compile the routes files")
  val routesImport = SettingKey[Seq[String]]("play-routes-imports", "Imports for the router")
  val generateReverseRouter = SettingKey[Boolean]("play-generate-reverse-router",
    "Whether the reverse router should be generated. Setting to false may reduce compile times if it's not needed.")
  val generateRefReverseRouter = SettingKey[Boolean]("play-generate-ref-reverse-router",
    "Whether the ref reverse router should be generated along with reverse router. Setting to false will make it easy to export routes to other projects and improve compile time.")
  val namespaceReverseRouter = SettingKey[Boolean]("play-namespace-reverse-router",
    "Whether the reverse router should be namespaced. Useful if you have many routers that use the same actions.")
}

object RoutesCompiler extends AutoPlugin {
  import RoutesKeys._

  override def trigger = noTrigger

  override def requires = JvmPlugin
  
  val autoImport = RoutesKeys
  
  override def projectSettings =
    defaultSettings ++
    inConfig(Compile)(routesSettings) ++
    inConfig(Test)(routesSettings)

  def routesSettings = Seq(
    routesFiles := Nil,

    watchSources in Defaults.ConfigGlobal <++= routesFiles,

    target in routes := crossTarget.value / "routes" / Defaults.nameForSrc(configuration.value.name),

    routes <<= compileRoutesFiles,

    sourceGenerators <+= routes,
    managedSourceDirectories <+= target in routes
  )

  def defaultSettings = Seq(
    routesImport := Nil,
    generateReverseRouter := true,
    generateRefReverseRouter := true,
    namespaceReverseRouter := false
  )

  private val compileRoutesFiles = Def.task[Seq[File]] {
    compileRoutes(routesFiles.value, (target in routes).value, routesImport.value, generateReverseRouter.value,
      generateRefReverseRouter.value, namespaceReverseRouter.value, streams.value.cacheDirectory, state.value.log)
  }

  def compileRoutes(files: Seq[File], generatedDir: File, additionalImports: Seq[String], reverseRouter: Boolean,
                    reverseRefRouter: Boolean, namespaceRouter: Boolean, cacheDirectory: File, log: Logger): Seq[File] = {
    val ops = files.map(f => RoutesCompilerOp(f, additionalImports, reverseRouter, reverseRefRouter, namespaceRouter))
    val (products, errors) = syncIncremental(cacheDirectory, ops) { opsToRun: Seq[RoutesCompilerOp] =>

      val results = opsToRun.map { op =>
        op -> play.router.RoutesCompiler.compile(op.file, generatedDir, op.additionalImports, op.reverseRouter, op.reverseRefRouter,
          op.namespaceReverseRouter)
      }
      val opResults = results.map {
        case (op, Right(inputs)) => op -> OpSuccess(Set(op.file), inputs.toSet)
        case (op, Left(_)) => op -> OpFailure
      }.toMap
      val errors = results.collect {
        case (_, Left(e)) => e
      }.flatten
      (opResults, errors)
    }

    if (errors.nonEmpty) {
      val exceptions = errors.map {
        case RoutesCompilationError(source, message, line, column) =>
          reportCompilationError(log, RoutesCompilationException(source, message, line, column.map(_ - 1)))
      }
      throw exceptions.head
    }

    products.to[Seq]
  }

  private def reportCompilationError(log: Logger, error: PlayException.ExceptionSource) = {
    // log the source file and line number with the error message
    log.error(Option(error.sourceName).getOrElse("") + Option(error.line).map(":" + _).getOrElse("") + ": " + error.getMessage)
    Option(error.interestingLines(0)).map(_.focus).flatMap(_.headOption) map { line =>
    // log the line
      log.error(line)
      Option(error.position).map { pos =>
      // print a carat under the offending character
        val spaces = (line: Seq[Char]).take(pos).map {
          case '\t' => '\t'
          case x => ' '
        }
        log.error(spaces.mkString + "^")
      }
    }
    error
  }
}

private case class RoutesCompilerOp(file: File, additionalImports: Seq[String], reverseRouter: Boolean,
                                    reverseRefRouter: Boolean, namespaceReverseRouter: Boolean)

Other Play Framework source code examples

Here is a short list of links related to this Play Framework RoutesCompiler.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.