The idea is to filter the sources, replacing @<var>@ occurrences with the mapping for <var> (which is currently hard-coded). @@ -> @. In order to make this work, I had to move the doc sources one directory down (into akka-docs/rst) so that the filtered result could be in a sibling directory so that relative links (to _sphinx plugins or real code) would continue to work. While I was at it I also changed it so that WARNINGs and ERRORs are not swallowed into the debug dump anymore but printed at [warn] level (minimum). One piece of fallout is that the (online) html build is now run after the normal one, not in parallel.
150 lines
6.6 KiB
Scala
150 lines
6.6 KiB
Scala
/**
|
|
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
|
*/
|
|
|
|
package akka
|
|
|
|
import sbt._
|
|
import sbt.Keys._
|
|
import java.io.{ File, PrintWriter }
|
|
|
|
object Sphinx {
|
|
val sphinxDocs = SettingKey[File]("sphinx-docs")
|
|
val sphinxTarget = SettingKey[File]("sphinx-target")
|
|
val sphinxPygmentsDir = SettingKey[File]("sphinx-pygments-dir")
|
|
val sphinxTags = SettingKey[Seq[String]]("sphinx-tags")
|
|
val sphinxPygments = TaskKey[File]("sphinx-pygments", "Sphinx: install pygments styles")
|
|
val sphinxHtml = TaskKey[File]("sphinx-html", "Sphinx: HTML documentation.")
|
|
val sphinxLatex = TaskKey[File]("sphinx-latex", "Sphinx: Latex documentation.")
|
|
val sphinxPdf = TaskKey[File]("sphinx-pdf", "Sphinx: PDF documentation.")
|
|
val sphinxVars = SettingKey[Map[String, String]]("sphinx-vars", "mappings key->value to be replaced within docs")
|
|
val sphinxExts = SettingKey[Set[String]]("sphinx-exts", "file extensions which will be filtered for replacements")
|
|
val sphinx = TaskKey[File]("sphinx", "Build all Sphinx documentation (HTML and PDF combined).")
|
|
|
|
lazy val settings = Seq(
|
|
sphinxDocs <<= baseDirectory / "rst",
|
|
sphinxTarget <<= crossTarget / "sphinx",
|
|
sphinxPygmentsDir <<= sphinxDocs { _ / ".." / "_sphinx" / "pygments" },
|
|
sphinxTags in sphinxHtml := Seq.empty,
|
|
sphinxTags in sphinxLatex := Seq.empty,
|
|
sphinxPygments <<= pygmentsTask,
|
|
sphinxHtml <<= buildTask("html", sphinxTags in sphinxHtml),
|
|
sphinxLatex <<= buildTask("latex", sphinxTags in sphinxLatex),
|
|
sphinxPdf <<= pdfTask,
|
|
sphinxVars := Map("" -> "@"), // this default makes the @@ -> @ subst work
|
|
sphinxExts := Set("rst"),
|
|
sphinx <<= sphinxTask
|
|
)
|
|
|
|
def pygmentsTask = (sphinxDocs, sphinxPygmentsDir, sphinxTarget, streams) map {
|
|
(cwd, pygments, baseTarget, s) => {
|
|
val target = baseTarget / "site-packages"
|
|
val empty = (target * "*.egg").get.isEmpty
|
|
if (empty) {
|
|
s.log.info("Installing Sphinx pygments styles...")
|
|
target.mkdirs()
|
|
val logger = newLogger(s)
|
|
val command = Seq("easy_install", "--install-dir", target.absolutePath, pygments.absolutePath)
|
|
val env = "PYTHONPATH" -> target.absolutePath
|
|
s.log.debug("Command: " + command.mkString(" ") + "\nEnv:" + env)
|
|
val exitCode = Process(command, cwd, env) ! logger
|
|
if (exitCode != 0) sys.error("Failed to install custom Sphinx pygments styles: exit code " + exitCode)
|
|
(pygments * ("*.egg-info" | "build" | "temp")).get.foreach(IO.delete)
|
|
s.log.info("Sphinx pygments styles installed at: " + target)
|
|
}
|
|
target
|
|
}
|
|
}
|
|
|
|
def buildTask(builder: String, tagsKey: SettingKey[Seq[String]]) = {
|
|
(cacheDirectory, sphinxDocs, sphinxTarget, sphinxPygments, tagsKey, streams, sphinxVars, sphinxExts) map {
|
|
(cacheDir, docs, baseTarget, pygments, tags, s, replacements, filterExt) => {
|
|
val target = baseTarget / builder
|
|
val doctrees = baseTarget / "doctrees" / builder
|
|
val temp = docs.getParentFile / (docs.getName + "_" + builder)
|
|
val cache = cacheDir / "sphinx" / builder
|
|
val cached = FileFunction.cached(cache)(FilesInfo.hash, FilesInfo.exists) { (in, out) =>
|
|
def dst(f: File) = temp.toPath.resolve(docs.toPath.relativize(f.toPath)).toFile
|
|
def filter(f: File) = filterExt contains f.getName.reverse.takeWhile('.' !=).reverse
|
|
val Replacer = """@(\w+)@""".r
|
|
in.removed foreach (f => IO delete dst(f))
|
|
(in.modified ++ (in.checked -- out.checked)).toSeq.sorted foreach { f =>
|
|
if (f.isFile)
|
|
if (filter(f)) {
|
|
s.log.debug("Changed documentation source: " + f)
|
|
IO.reader(f) { reader =>
|
|
IO.writer(dst(f), "", IO.defaultCharset, append = false) { writer =>
|
|
val wr = new PrintWriter(writer)
|
|
IO.foreachLine(reader) { line =>
|
|
wr.println(Replacer.replaceAllIn(line, m => replacements.getOrElse(m.group(1), {
|
|
s.log.warn("unknown replacement " + m.group(1) + " in " + replacements)
|
|
m.group(0)
|
|
})))
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
s.log.debug("Changed documentation source (copying): " + f)
|
|
IO.copyFile(f, dst(f))
|
|
}
|
|
}
|
|
val tagList = if (tags.isEmpty) "" else tags.mkString(" (", ", ", ")")
|
|
val desc = "%s%s" format (builder, tagList)
|
|
s.log.info("Building Sphinx %s documentation..." format desc)
|
|
val logger = newLogger(s)
|
|
val tagOptions = tags flatMap (Seq("-t", _))
|
|
val command = Seq("sphinx-build", "-aEN", "-b", builder, "-d", doctrees.absolutePath) ++ tagOptions ++ Seq(temp.absolutePath, target.absolutePath)
|
|
val env = "PYTHONPATH" -> pygments.absolutePath
|
|
s.log.debug("Command: " + command.mkString(" "))
|
|
val exitCode = Process(command, docs, env) ! logger
|
|
if (exitCode != 0) sys.error("Failed to build Sphinx %s documentation." format desc)
|
|
s.log.info("Sphinx %s documentation created: %s" format (desc, target))
|
|
temp.descendentsExcept("*", "").get.toSet
|
|
}
|
|
val toplevel = docs * ("*" - ".*" - "_sphinx" - "_build" - "disabled" - "target")
|
|
val inputs = toplevel.descendentsExcept("*", "").get.toSet
|
|
cached(inputs)
|
|
target
|
|
}
|
|
}
|
|
}
|
|
|
|
def pdfTask = (sphinxLatex, streams) map {
|
|
(latex, s) => {
|
|
val pdf = latex / "Akka.pdf"
|
|
def failed = sys.error("Failed to build Sphinx pdf documentation.")
|
|
if (!pdf.exists) {
|
|
s.log.info("Building Sphinx pdf documentation...")
|
|
val logger = newLogger(s)
|
|
val exitCode = Process(Seq("make", "all-pdf"), latex) ! logger
|
|
if (exitCode != 0) failed
|
|
s.log.info("Sphinx pdf documentation created: %s" format pdf)
|
|
}
|
|
pdf
|
|
}
|
|
}
|
|
|
|
def newLogger(streams: TaskStreams) = {
|
|
new ProcessLogger {
|
|
def info(message: => String): Unit = {
|
|
val m = message
|
|
if (m contains "ERROR") streams.log.error(message)
|
|
else if (m contains "WARNING") streams.log.warn(message)
|
|
else streams.log.debug(message)
|
|
}
|
|
def error(e: => String): Unit = streams.log.warn(e)
|
|
def buffer[T](f: => T): T = f
|
|
}
|
|
}
|
|
|
|
def sphinxTask = (sphinxHtml, sphinxPdf, sphinxTarget, streams) map {
|
|
(html, pdf, baseTarget, s) => {
|
|
val target = baseTarget / "docs"
|
|
IO.delete(target)
|
|
IO.copyDirectory(html, target)
|
|
IO.copyFile(pdf, target / pdf.name)
|
|
s.log.info("Combined Sphinx documentation: %s" format target)
|
|
target
|
|
}
|
|
}
|
|
}
|