aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Rudolph <johannes_rudolph@gmx.de>2012-10-10 09:57:18 +0200
committerJohannes Rudolph <johannes_rudolph@gmx.de>2012-10-10 09:57:18 +0200
commit7ccabd803ca26cde46c970c7fea45d59b7c54b3d (patch)
treee4ad3f720071c9864e22168afb1f2a0e8fd3428f
parent14435c6e5264d8bf665695b503cbcb574e96aaa3 (diff)
downloadsbt-boilerplate-7ccabd803ca26cde46c970c7fea45d59b7c54b3d.tar.gz
sbt-boilerplate-7ccabd803ca26cde46c970c7fea45d59b7c54b3d.tar.bz2
sbt-boilerplate-7ccabd803ca26cde46c970c7fea45d59b7c54b3d.zip
first version of plugin
-rw-r--r--build.sbt41
-rw-r--r--project/build.properties1
-rw-r--r--project/plugins.sbt8
-rw-r--r--src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala37
-rw-r--r--src/main/scala/cc/spray/boilerplate/Generator.scala75
5 files changed, 162 insertions, 0 deletions
diff --git a/build.sbt b/build.sbt
new file mode 100644
index 0000000..1061a87
--- /dev/null
+++ b/build.sbt
@@ -0,0 +1,41 @@
+name := "sbt-boilerplate"
+
+organization := "cc.spray"
+
+version := "0.5.0-SNAPSHOT"
+
+description := "An SBT plugin for simple generation of boilerplate"
+
+startYear := Some(2012)
+
+homepage := Some(url("http://github.com/spray/sbt-boilerplate"))
+
+organizationHomepage := Some(url("http://spray.cc"))
+
+licenses in GlobalScope += "Apache License 2.0" -> url("https://github.com/spray/sbt-boilerplate/raw/master/LICENSE")
+
+sbtPlugin := true
+
+scalacOptions := Seq("-deprecation", "-encoding", "utf8")
+
+CrossBuilding.crossSbtVersions := Seq("0.11.3", "0.12")
+
+///////////////
+// publishing
+///////////////
+
+credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
+
+publishMavenStyle := false
+
+publishTo := Some(Resolver.url("sbt-plugin-releases repo", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns))
+
+///////////////
+// ls-sbt
+///////////////
+
+seq(lsSettings :_*)
+
+(LsKeys.tags in LsKeys.lsync) := Seq("sbt-plugin", "sbt", "plugin", "boilerplate", "code-generation")
+
+(LsKeys.docsUrl in LsKeys.lsync) <<= homepage \ No newline at end of file
diff --git a/project/build.properties b/project/build.properties
new file mode 100644
index 0000000..a8c2f84
--- /dev/null
+++ b/project/build.properties
@@ -0,0 +1 @@
+sbt.version=0.12.0
diff --git a/project/plugins.sbt b/project/plugins.sbt
new file mode 100644
index 0000000..a031b5f
--- /dev/null
+++ b/project/plugins.sbt
@@ -0,0 +1,8 @@
+resolvers ++= Seq(
+ "less is" at "http://repo.lessis.me",
+ "coda" at "http://repo.codahale.com"
+)
+
+addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2")
+
+addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.7.0-RC2")
diff --git a/src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala b/src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala
new file mode 100644
index 0000000..0d8b9c3
--- /dev/null
+++ b/src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala
@@ -0,0 +1,37 @@
+package cc.spray.boilerplate
+
+import sbt._
+import Keys._
+
+object BoilerplatePlugin extends Plugin {
+ object Boilerplate {
+ val boilerplateGenerate = TaskKey[Seq[File]]("boilerplate-generate", "Generates boilerplate from template files")
+
+ val settings = seq(
+ sourceDirectory in boilerplateGenerate <<= (sourceDirectory in Compile) / "boilerplate",
+
+ target in boilerplateGenerate <<= (sourceManaged in Compile),
+
+ boilerplateGenerate <<= (streams, sourceDirectory in boilerplateGenerate, target in boilerplateGenerate) map Generator.generateFromTemplates,
+
+ (sourceGenerators in Compile) <+= boilerplateGenerate,
+ (managedSourceDirectories in Compile) <+= target in boilerplateGenerate,
+
+ // watch sources support
+ includeFilter in boilerplateGenerate := "*.template",
+ excludeFilter in boilerplateGenerate <<= excludeFilter in Global,
+ watch(sourceDirectory in boilerplateGenerate, includeFilter in boilerplateGenerate, excludeFilter in boilerplateGenerate),
+
+ // add managed sources to the packaged sources
+ mappings in (Compile, packageSrc) <++=
+ (sourceManaged in Compile, managedSources in Compile) map { (base, srcs) =>
+ (srcs x (Path.relativeTo(base) | Path.flat))
+ }
+ )
+
+ def watch(sourceDirKey: SettingKey[File], filterKey: SettingKey[FileFilter], excludeKey: SettingKey[FileFilter]) =
+ watchSources <++= (sourceDirKey, filterKey, excludeKey) map descendents
+ def descendents(sourceDir: File, filt: FileFilter, excl: FileFilter) =
+ sourceDir.descendantsExcept(filt, excl).get
+ }
+}
diff --git a/src/main/scala/cc/spray/boilerplate/Generator.scala b/src/main/scala/cc/spray/boilerplate/Generator.scala
new file mode 100644
index 0000000..d171d7b
--- /dev/null
+++ b/src/main/scala/cc/spray/boilerplate/Generator.scala
@@ -0,0 +1,75 @@
+package cc.spray.boilerplate
+
+import sbt._
+import sbt.Keys._
+
+object Generator {
+ def generateFromTemplates(streams: TaskStreams, sourceDir: File, targetDir: File): Seq[File] = {
+ val files = sourceDir ** "*.template"
+
+ def changeExtension(f: File): File = {
+ val (ext, name) = f.getName.reverse.span(_ != '.')
+ new File(f.getParent, name.reverse.toString+"scala")
+ }
+
+ val mapping = (files x rebase(sourceDir, targetDir)).map {
+ case (orig, target) => (orig, changeExtension(target))
+ }
+
+ mapping foreach {
+ case (templateFile, target) =>
+ if (templateFile.lastModified > target.lastModified) {
+ streams.log.info("Generating '%s'" format target.getName)
+ val template = IO.read(templateFile)
+ IO.write(target, generateFromTemplate(template))
+ } else
+ streams.log.debug("Template '%s' older than target. Ignoring." format templateFile.getName)
+ }
+
+ mapping.map(_._2)
+ }
+
+ val ExpandReplacement = """(?s:\*\{(.*)\}\*)""".r
+ def generateFromTemplate(template: String): String =
+ ExpandReplacement.replaceAllIn(template, { m =>
+ val format = m.group(1)
+ (1 to 22).map(generate(format)).mkString
+ })
+
+ val SimpleReplacement = """\[\{(.*)\}\]""".r
+ val EnumerateReplacement = """\{\{([^}]*)\}([^}]+)?\}""".r
+
+ def generate(format: String)(idx: Int): String = {
+ val numChars = idx.toString.length
+ def formatNum0(num: Int) = num.formatted("%0"+numChars+"d")
+ def formatNumSpace(num: Int) = num.formatted("%"+numChars+"d")
+
+ def replaceSimple(pattern: String) =
+ SimpleReplacement.replaceAllIn(pattern, { m =>
+ val pattern = m.group(1)
+ replaceInPattern(pattern)(idx)
+ })
+
+ def replaceExpand(pattern: String) =
+ EnumerateReplacement.replaceAllIn(pattern, { m =>
+ val pattern = m.group(1)
+ val separator = m.group(2) match {
+ case null =>
+ if (pattern.endsWith(", ") || pattern.contains("\n")) "" else ", "
+ case sep => sep
+ }
+
+ (1 to idx).map(replaceInPattern(pattern)).mkString(separator)
+ })
+ def replaceInPattern(pattern: String)(idx: Int): String =
+ // in likely identifiers replace by '04' etc.
+ pattern.replaceAll("(?<!\\d)1(?!\\d)", formatNum0(idx))
+ .replaceAll("(?<=\\w)(?<!\\d)0(?!\\d)", formatNum0(idx - 1))
+
+ // in other places replace by ' 4' etc.
+ .replaceAll("(?<!\\w)(?<!\\d)1(?!\\d)", formatNumSpace(idx))
+ .replaceAll("(?<!\\w)(?<!\\d)0(?!\\d)", formatNumSpace(idx - 1))
+
+ replaceExpand(replaceSimple(format))
+ }
+}