PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/sbtPlugins/src/main/scala/scales/sbtplugins/SiteProject.scala

http://scala-scales.googlecode.com/
Scala | 371 lines | 226 code | 53 blank | 92 comment | 24 complexity | dfff45a5ef02db31ca192b08c9516197 MD5 | raw file
  1. package scales.sbtplugins
  2. import sbt._
  3. import FileUtilities._
  4. import Utils._
  5. import SbtWiki._
  6. trait SiteBase {
  7. self : MavenStyleScalaPaths =>
  8. /**
  9. * Site wide base css
  10. */
  11. def siteCSS = baseCss(this)
  12. /**
  13. * Site wide base jquery
  14. */
  15. def siteJQuery = resourcesOutDir(this) / "jquery-1.5.min.js"
  16. }
  17. trait ArtifactsHelper extends BasicManagedProject {
  18. self : SiteProject =>
  19. val siteArtifact = Artifact(artifactID, "zip", "zip", Some("site"), Nil, None)
  20. def packageSiteZip = defaultJarPath("-site.zip")
  21. val docsArtifact = Artifact(artifactID, "docs", "jar", Some("docs"),
  22. Nil, None)
  23. val sourceArtifact = Artifact(artifactID, "src", "jar", Some("sources"),
  24. Nil, None)
  25. val publishScalaDocs = true
  26. val publishSiteZip = true
  27. val publishSources = true
  28. override def artifacts =
  29. super.artifacts ++ {
  30. if (publishSiteZip) Seq( siteArtifact )
  31. else Seq()
  32. } ++ {
  33. if (publishScalaDocs) Seq( docsArtifact )
  34. else Seq()
  35. } ++ {
  36. if (publishSources) Seq( sourceArtifact )
  37. else Seq()
  38. }
  39. override def packageToPublishActions = Seq(packageSite, packageDocs, packageSrc) ++ super.packageToPublishActions
  40. }
  41. case class Copy( from : String, to : String )
  42. object Copy {
  43. def apply( from : String ) : Copy = Copy(from, from)
  44. }
  45. /**
  46. * siteDesc is a mediawiki snippet (will simply be embedded)
  47. * to represent the part of the site that copy refers to.
  48. * siteLink is optionally the target html to load for that link,
  49. * defaulting to copy.to / index.html.
  50. *
  51. * It MUST be in utf-8 format
  52. *
  53. * The ignore list can be tailored for just a site, it will be added to
  54. * the siteIgnore list upon running site.
  55. */
  56. case class Site( copy : Copy, siteDesc : String, siteLink : Option[String], ignore : Iterable[FileFilter])
  57. object Site{
  58. def apply( copy : Copy, siteDesc : String ) : Site = Site(copy,siteDesc, None, List())
  59. def apply( copy : Copy, siteDesc : String, siteLink : String ) : Site = Site(copy,siteDesc, Some(siteLink), List())
  60. def apply( copy : Copy, siteDesc : String, siteLink : Option[String] ) : Site = Site(copy,siteDesc, siteLink, List())
  61. def apply( copy : Copy, siteDesc : String, siteLink : String, ignore : Iterable[FileFilter] ) : Site = Site(copy,siteDesc, Some(siteLink), ignore)
  62. }
  63. /**
  64. * Utilities and tasks for creating a site
  65. */
  66. trait SiteProject extends BasicScalaProject with DocWrapper with SiteBase with ArtifactsHelper {
  67. val xraySite = Site(Copy("classes.sxr"), "Scala XRay Specs view of the source, also available via the Scaladocs")
  68. val docsSite = Site(Copy("doc/main/api", "doc"), "ScalaDocs for ${artifactID}")
  69. val xrayTestsSite = Site(Copy("test-classes.sxr"), "Scala XRay Specs view of the test source")
  70. val scctSite = Site(Copy("coverage-report"), "SCCT - Scala TestCoverage")
  71. // here we don't have an index just the dir
  72. val surefireRepSite = Site(Copy("surefire-reports"), "Surefire Reports", "surefire-reports/")
  73. val testReviewSite = Site(Copy("test-review"), "Test Review Results")
  74. def sites = List(xraySite, docsSite, xrayTestsSite, scctSite, surefireRepSite, testReviewSite)
  75. lazy val packageSite = packageSiteAction
  76. def packageSiteAction = zipTask(siteOutputPath ** "*", packageSiteZip).dependsOn(site)
  77. lazy val sitePublishRelative = getSitePublishRelative
  78. // by default we don't want the release to show any intermediate builds for the docs
  79. def getSitePublishRelative = projectOrganization.value +"/"+ artifactID +"/"+ (projectVersion.value.toString.replaceAll("-.*",""))
  80. // paths don't like relatives and forward slashes
  81. lazy val siteDeployFile = getSiteDeployFile
  82. def getSiteDeployFile = new java.io.File("./../sites").getAbsoluteFile()
  83. /**
  84. * List of files to ignore when deploying the site, defaults to siteIgnore
  85. */
  86. def deploySiteIgnore = siteIgnore
  87. /**
  88. * Deploys the zip file with a locally useable site and the remote with further changed paths
  89. */
  90. lazy val deploySite = deploySiteAction
  91. def deploySiteAction = task {
  92. // make dirs, copy over the site then zip
  93. import FileUtilities._
  94. import java.io.File
  95. val dir = new File(siteDeployFile, sitePublishRelative).getCanonicalFile
  96. val parent = dir.getParentFile
  97. val sitesrc = siteOutputPath.asFile
  98. val sitezip = packageSiteZip.asFile.getCanonicalFile
  99. println("Attempting to publish from "+sitesrc.getCanonicalPath+" with zip "+sitezip.getCanonicalPath)
  100. copyDir(sitesrc, dir, deploySiteIgnore, log) ~~>
  101. copyFile(sitezip, new File(dir, sitezip.getName), log)
  102. } dependsOn(packageSite)
  103. /**
  104. * Override to change the tasks executed before the site is run.
  105. */
  106. def siteAllActions = "clean;test-coverage;test-review;doc"
  107. def canFailActions = List("test-coverage","test-review")
  108. def ignoreFailActionsForSite = true
  109. lazy val siteAll = siteAllAction
  110. def siteAllAction = task {
  111. callCommands(siteAllActions+";site", this, if (ignoreFailActionsForSite) canFailActions else Nil)
  112. }
  113. lazy val siteResource = siteResourceDir
  114. def siteResourceDir = sourcePath / "site"
  115. def siteIndexHeader = siteResourceDir / "siteIndexHeader.mw"
  116. def siteIndexFooter = siteResourceDir / "siteIndexFooter.mw"
  117. val userF = ()=>{
  118. var env = System.getenv("USERNAME")
  119. if (env eq null)
  120. env = System.getenv("USER")
  121. if (env eq null)
  122. "Unknown User"
  123. else
  124. env
  125. }
  126. val sysEnv = {
  127. import scala.collection.jcl.Conversions._
  128. System.getenv().map{(x) => (x._1, () => x._2)}
  129. }
  130. val sysProperties = {
  131. import scala.collection.jcl.Conversions._
  132. System.getProperties().map{(x) => (x._1.toString, () => x._2.toString)}
  133. }
  134. /**
  135. * Override to change the pre code end for cend tokens
  136. */
  137. def cend() = () => "</pre>"
  138. /**
  139. * Override to change the code@lang pre for cXX tokens
  140. */
  141. def cbs(lang : String) = () => "<pre class=\"language-"+lang+"\">"
  142. def siteTokens = Map[String, ()=>String]( "User" -> userF, "timestamp" -> { () => {new java.util.Date().toString}},
  143. "datetime" -> {() => {java.text.DateFormat.getDateTimeInstance.format(new java.util.Date())}},
  144. "artifactID" -> {() => artifactID},
  145. "projectName" -> {() => projectName.value},
  146. "projectVersion" -> {() => projectVersion.value.toString},
  147. "projectOrganization" -> {() => projectOrganization.value},
  148. "projectOrganisation" -> {() => projectOrganization.value},
  149. "FullVersion" -> {() => projectOrganization.value+ " : " + artifactID + "-" + projectVersion.value.toString},
  150. "cscala" -> cbs("scala"),
  151. "bxml" -> (() => "<code class=\"xml\">"),
  152. "cxml" -> cbs("xml"),
  153. "exml" -> (() => "</code>"),
  154. "cjava" -> cbs("java"),
  155. "cend" -> cend()
  156. ) ++ sysEnv ++ sysProperties
  157. /**
  158. * By default deletes markup files after calling site-docs
  159. */
  160. val siteMarkupDelete = true
  161. /**
  162. * Override to change/disable the use of highlight.
  163. *
  164. * NOTE: It does some crazy looking stuff in here, but its
  165. * due to bugs in <IE9 that strip newlines out of pre's.
  166. * The outerHTML trick gets around that limitation.
  167. *
  168. * In both cases we wrap a code in the middle, letting highlight.js do its
  169. * thing.
  170. */
  171. def highlightScripts =
  172. js("./highlight/highlight.pack.js") +
  173. """<script type="text/javascript">
  174. $(function() {
  175. $("pre[class^='language-']").each(function(i,elem) {
  176. var clazz = $(elem).attr('class');
  177. var str = elem.innerHTML//.replace(/\r\n|\r|\n/g,"<br/>");
  178. // Workaround for IE <PRE> innerHTML normalization quirk
  179. if (elem.tagName == "PRE" && "outerHTML" in elem)
  180. {
  181. elem.outerHTML = "<PRE><CODE class='"+clazz+"'>" + str + "</CODE></PRE>";
  182. }
  183. else
  184. {
  185. elem.innerHTML = "<CODE class='"+clazz+"'>" + str + "</CODE>"; //.replace(/\r\n|\r|\n/g,"<br/>");;
  186. }
  187. });
  188. hljs.initHighlighting();
  189. });
  190. </script>
  191. """
  192. /**
  193. * String representing the headers for each generated site html.
  194. *
  195. * Defaults to the site wide CSS, includes a jquery (override siteJQuery to change versions etc) and adds highlight.js (override sitHightlightStyle to change the style used). NOTE as a default only xml, java and scala are provided
  196. */
  197. def siteHeaders = css("./scales_base.css") + css("./site_docs.css") + siteHighlightStyle + js("./jquery.js") + highlightScripts
  198. def siteMediaWikiTemplates : List[(String, String)] = List(("code","""<code class="{{{lang}}}"><pre>{{{2}}}</pre></code>"""));
  199. /**
  200. * Override to change the highlight style used during the site-docs run.
  201. */
  202. def siteHighlightStyle = css("./highlight/styles/idea.css")
  203. /**
  204. * List of files to ignore when generating the site docs, defaults to siteIgnore
  205. */
  206. def siteDocsIgnore = siteIgnore
  207. /**
  208. * Generates user documentation from the
  209. * src/site directory (configure with siteDocsBase).
  210. * Whatever is in there is copied to target and all known markup
  211. * extensions are converted.
  212. *
  213. * Note by default it will delete all original markup
  214. * files after conversion.
  215. * Use siteMarkupDelete to control this behaviour.
  216. *
  217. */
  218. lazy val siteDocs = siteDocsAction
  219. def siteDocsAction = task { // TODO - allow the source zip for highlighting and site_docs to be replaced
  220. ( if (siteResourceDir.exists) None else Some("The site directory "+siteResourceDir+" does not exist, please create it, or override siteResourceDir before calling site.") ) ~~>
  221. unpackResources(this) ~~>
  222. FileUtilities.copyFile(siteCSS, siteOutputPath / "scales_base.css", log) ~~>
  223. FileUtilities.copyFile(siteJQuery, siteOutputPath / "jquery.js", log) ~~>
  224. FileUtilities.copyFile(resourcesOutDir(this)./("site_docs.css"), siteOutputPath / "site_docs.css", log) ~~>
  225. {FileUtilities.unzip(resourcesOutDir(this)./("highlight.zip"), siteOutputPath, log);None } ~~>
  226. SbtWiki.templates.withValue(siteMediaWikiTemplates) {
  227. copyAndConvert(siteResourceDir, siteOutputPath, siteDocsIgnore,
  228. siteHeaders, siteTokens, log, siteMarkupDelete, siteMarkupDocHeaders)
  229. }
  230. }
  231. /**
  232. * A list of markup docs that will be shown in the index.
  233. * The pair is relative filename without extension -> description.
  234. */
  235. val siteMarkupDocs : List[(String, String)]
  236. /**
  237. * Users wishing to add a title or override other headers should
  238. * add their markup document here, relative filename to MarkupHeader
  239. */
  240. def siteMarkupDocHeaders : Map[String, MarkupHeader] =
  241. Map[String, MarkupHeader]()
  242. /**
  243. * List of files to ignore when building a site
  244. */
  245. def siteIgnore : Iterable[FileFilter] = List(new ExactFilter(siteIndexHeader.name), new ExactFilter(siteIndexFooter.name), new ExactFilter(".svn"), // all svn files
  246. GlobFilter("*.*~")) // all emacs backups
  247. lazy val site = siteAction
  248. def siteAction = task {
  249. import FileUtilities._
  250. // create target dir
  251. val outDir = siteOutputPath
  252. val siteIndex = outDir / "index.html"
  253. val siteIndexMd = outDir / "index.mw"
  254. val siteIndexMdf = siteIndexMd.asFile
  255. val siteIgnores = siteIgnore
  256. // doesn't matter if it fails
  257. createDirectory(outDir, log)
  258. val sitesc = sites
  259. // copy them over
  260. sitesc.foldLeft( None : Option[String]){
  261. (x, y) =>
  262. x ~~> {
  263. val from = new java.io.File(outputPath.asFile, y.copy.from)
  264. val to = new java.io.File( outDir.asFile, y.copy.to)
  265. if (from.exists)
  266. copyDir(from, to, siteIgnores ++ y.ignore, log)
  267. else {
  268. log.debug("Could not find directory "+from.getAbsolutePath+" skipping copy")
  269. None
  270. }
  271. }
  272. } ~~> {
  273. // create cover page..
  274. val wikiBase = if (siteIndexHeader.exists) readString(siteIndexHeader.asFile, utf8, log)
  275. else Right("= ${FullVersion} Site =\n")
  276. wikiBase.fold(Some(_),{b => write(siteIndexMdf, b+"\n<br/>\n", utf8, log) ~~> {
  277. // middle
  278. sitesc.foldLeft( None : Option[String] ){
  279. (x,y) =>
  280. x ~~> {
  281. if (new java.io.File(outputPath.asFile, y.copy.from).exists) {
  282. val link = y.siteLink.getOrElse{"./"+y.copy.to+"/index.html"}
  283. append(siteIndexMdf, "* ["+link+" "+y.siteDesc+"]\n", utf8, log)
  284. } else x
  285. }
  286. } ~~> (
  287. if (siteMarkupDocs.size > 0) {
  288. append(siteIndexMdf, "\n<br/>\n== Project Documentation ==\n<br/>\n", utf8, log)
  289. siteMarkupDocs.foldLeft( None : Option[String] ){
  290. (x,y) =>
  291. x ~~> {
  292. val f = new java.io.File(outDir.asFile, y._1 + ".html")
  293. if (f.exists) {
  294. append(siteIndexMdf, "* [./"+y._1+".html "+y._2+"]\n", utf8, log)
  295. } else Some("File "+f.getCanonicalPath + " does not exist")
  296. }
  297. }
  298. } else None
  299. ) ~~> {
  300. // footer
  301. val wikiEnd = if (siteIndexFooter.exists) readString(siteIndexFooter.asFile, utf8, log)
  302. else Right("<br/>\n[./"+packageSiteZip.name+" Download Site Zip]\n\nBuilt By: ${User}, ${timestamp}")
  303. wikiEnd.fold(Some(_),{f=>append(siteIndexMdf, f, utf8, log)})
  304. }
  305. }}) ~~> {
  306. // convert to html
  307. try{
  308. unpackResources(this) ~~>
  309. FileUtilities.copyFile(siteCSS, outDir / "scales_base.css", log) ~~>
  310. convert(siteIndexMd, siteIndex, title("${FullVersion} Site") + siteHeaders, siteTokens, log)
  311. } catch {
  312. case e : Exception => Some(e.getMessage)
  313. }
  314. }
  315. }
  316. } dependsOn siteDocs
  317. def siteOutputPath = outputPath / "site"
  318. }