/scalate-core/src/main/scala/org/fusesource/scalate/support/SiteGenerator.scala

http://github.com/scalate/scalate · Scala · 174 lines · 116 code · 30 blank · 28 comment · 29 complexity · 5b013d103d10f193cc0df44c2af3af51 MD5 · raw file

  1. /**
  2. * Copyright (C) 2009-2011 the original author or authors.
  3. * See the notice.md file distributed with this work for additional
  4. * information regarding copyright ownership.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.fusesource.scalate.support
  19. import java.io.{ File, PrintWriter }
  20. import java.{ util => ju }
  21. import org.fusesource.scalate._
  22. import org.fusesource.scalate.servlet.ServletTemplateEngine
  23. import org.fusesource.scalate.util._
  24. import scala.collection.JavaConverters._
  25. object SiteGenerator extends Log
  26. import org.fusesource.scalate.support.SiteGenerator._
  27. import scala.language.reflectiveCalls
  28. /**
  29. * This class generates static HTML files for your website using the Scalate templates, filters and wiki markups
  30. * you are using.
  31. *
  32. * @author <a href="http://macstrac.blogspot.com">James Strachan</a>
  33. */
  34. class SiteGenerator {
  35. var workingDirectory: File = _
  36. var webappDirectory: File = _
  37. var targetDirectory: File = _
  38. var templateProperties: ju.Map[String, String] = _
  39. var bootClassName: String = _
  40. var info: { def apply(v1: String): Unit } = (value: String) => println(value)
  41. def execute() = {
  42. targetDirectory.mkdirs()
  43. if (webappDirectory == null || !webappDirectory.exists) {
  44. throw new IllegalArgumentException("The webappDirectory properly is not properly set")
  45. }
  46. info("Generating static website from Scalate Templates and wiki files...")
  47. info("template properties: " + templateProperties)
  48. val engine = new DummyTemplateEngine(webappDirectory)
  49. engine.classLoader = Thread.currentThread.getContextClassLoader
  50. if (bootClassName != null) {
  51. engine.bootClassName = bootClassName
  52. }
  53. if (workingDirectory != null) {
  54. engine.workingDirectory = workingDirectory
  55. workingDirectory.mkdirs()
  56. }
  57. engine.boot
  58. val attributes: Map[String, Any] = if (templateProperties != null) {
  59. templateProperties.asScala.toMap
  60. } else {
  61. Map()
  62. }
  63. def processFile(file: File, baseuri: String): Unit = {
  64. if (file.isDirectory()) {
  65. if (file.getName != "WEB-INF" && !file.getName.startsWith("_")) {
  66. val children = file.listFiles()
  67. if (children != null) {
  68. for (child <- children) {
  69. if (child.isDirectory) {
  70. processFile(child, baseuri + "/" + child.getName)
  71. } else {
  72. processFile(child, baseuri)
  73. }
  74. }
  75. }
  76. }
  77. } else {
  78. val parts = file.getName.split('.')
  79. if (parts.size > 1 && !file.getName.startsWith("_")) {
  80. val uri = baseuri + "/" + file.getName()
  81. // uri = uri.replace(':', '_')
  82. val ext = parts.last
  83. if (engine.extensions.contains(ext)) {
  84. try {
  85. val source = TemplateSource.fromFile(file, uri)
  86. val html = engine.layout(source, attributes)
  87. val sourceFile = new File(targetDirectory, appendHtmlPostfix(uri.stripPrefix("/")))
  88. info(" processing " + file + " with uri: " + uri + " => ")
  89. sourceFile.getParentFile.mkdirs
  90. //IOUtil.writeBinaryFile(sourceFile, transformHtml(html, uri, rootDir).getBytes("UTF-8"))
  91. IOUtil.writeBinaryFile(sourceFile, html.getBytes("UTF-8"))
  92. } catch {
  93. case e: NoValueSetException => info(e.getMessage + ". Ignored template file due to missing attributes: " + file.getCanonicalPath)
  94. case e: VirtualMachineError => throw e
  95. case e: ThreadDeath => throw e
  96. case e: Throwable => throw new Exception(e.getMessage + ". When processing file: " + file.getCanonicalPath, e)
  97. }
  98. } else {
  99. // let's copy the file across if its not a template
  100. debug(" copying " + file + " with uri: " + uri + " extension: " + ext + " not in " + engine.extensions)
  101. val sourceFile = new File(targetDirectory, uri.stripPrefix("/"))
  102. IOUtil.copy(file, sourceFile)
  103. }
  104. }
  105. }
  106. }
  107. processFile(webappDirectory, "")
  108. }
  109. protected var validFileExtensions = Set("js", "css", "rss", "atom", "htm", "xml", "csv", "json")
  110. protected def appendHtmlPostfix(uri: String): String = {
  111. val answer = Files.dropExtension(uri)
  112. val ext = Files.extension(answer)
  113. if (validFileExtensions.contains(ext)) {
  114. answer
  115. } else {
  116. answer + ".html"
  117. }
  118. }
  119. }
  120. class DummyTemplateEngine(
  121. rootDirectory: File) extends TemplateEngine(Some(rootDirectory)) {
  122. override protected def createRenderContext(
  123. uri: String,
  124. out: PrintWriter) = new DummyRenderContext(uri, this, out)
  125. private[this] val responseClassName = "_root_." + classOf[DummyResponse].getName
  126. bindings = List(
  127. Binding("context", "_root_." + classOf[DummyRenderContext].getName, true, isImplicit = true),
  128. Binding("response", responseClassName, defaultValue = Some("new " + responseClassName + "()")))
  129. ServletTemplateEngine.setLayoutStrategy(this)
  130. }
  131. class DummyRenderContext(
  132. val _requestUri: String,
  133. _engine: TemplateEngine,
  134. _out: PrintWriter) extends DefaultRenderContext(_requestUri, _engine, _out) {
  135. // for static website stuff we must zap the root dir typically
  136. override def uri(name: String) = {
  137. // lets deal with links to / as being to /index.html
  138. val link = if (name == "/") "/index.html" else name
  139. Links.convertAbsoluteLinks(link, requestUri)
  140. }
  141. }
  142. class DummyResponse {
  143. def setContentType(value: String): Unit = {}
  144. }