diff options
author | Johannes Rudolph <johannes_rudolph@gmx.de> | 2012-10-10 09:57:18 +0200 |
---|---|---|
committer | Johannes Rudolph <johannes_rudolph@gmx.de> | 2012-10-10 09:57:18 +0200 |
commit | 7ccabd803ca26cde46c970c7fea45d59b7c54b3d (patch) | |
tree | e4ad3f720071c9864e22168afb1f2a0e8fd3428f | |
parent | 14435c6e5264d8bf665695b503cbcb574e96aaa3 (diff) | |
download | sbt-boilerplate-7ccabd803ca26cde46c970c7fea45d59b7c54b3d.tar.gz sbt-boilerplate-7ccabd803ca26cde46c970c7fea45d59b7c54b3d.tar.bz2 sbt-boilerplate-7ccabd803ca26cde46c970c7fea45d59b7c54b3d.zip |
first version of plugin
-rw-r--r-- | build.sbt | 41 | ||||
-rw-r--r-- | project/build.properties | 1 | ||||
-rw-r--r-- | project/plugins.sbt | 8 | ||||
-rw-r--r-- | src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala | 37 | ||||
-rw-r--r-- | src/main/scala/cc/spray/boilerplate/Generator.scala | 75 |
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)) + } +} |