diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..12209ac --- /dev/null +++ b/build.sbt @@ -0,0 +1,29 @@ +organization := "com.lightbend" +name := "cloc-plugin" +scalaVersion := "2.12.4" +libraryDependencies ++= Seq( + "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", + "org.scalatest" %% "scalatest" % "3.0.4" % "test" +) +scalacOptions ++= Seq( + "-encoding", + "utf-8", + "-deprecation", + "-unchecked", + "-feature", + "-Xlint", + "-Xfatal-warnings", + "-Yno-adapted-args", + "-Ywarn-dead-code", + "-Ywarn-infer-any", + "-Ywarn-numeric-widen", + "-Ywarn-value-discard" +) +// so we can invoke the Scala compiler at runtime without weird problems +fork in Test := true + +val pluginPath = taskKey[File]("path to compiler plugin jar") +enablePlugins(BuildInfoPlugin) +buildInfoKeys := Seq[BuildInfoKey](pluginPath) +pluginPath := (artifactPath in packageBin in Compile).value // TODO +buildInfoPackage := "com.lightbend.tools" diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..c091b86 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.16 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..7947368 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,2 @@ +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.6.1") +addSbtPlugin("com.dwijnand" % "sbt-dynver" % "2.0.0") diff --git a/src/main/resources/scalac-plugin.xml b/src/main/resources/scalac-plugin.xml new file mode 100644 index 0000000..3c24618 --- /dev/null +++ b/src/main/resources/scalac-plugin.xml @@ -0,0 +1,4 @@ + + cloc + com.lightbend.tools.ClocPlugin + diff --git a/src/main/scala/com/lightbend/tools/ClocComponent.scala b/src/main/scala/com/lightbend/tools/ClocComponent.scala new file mode 100644 index 0000000..33d43f0 --- /dev/null +++ b/src/main/scala/com/lightbend/tools/ClocComponent.scala @@ -0,0 +1,31 @@ +package com.lightbend.tools + +import scala.tools.nsc, nsc.plugins._ +import java.io.File + +abstract class ClocComponent extends PluginComponent { + + override def description = "count lines of Scala code compiled" + + // the following two members override abstract members in Transform + val phaseName: String = "cloc" + def newPhase(prev: nsc.Phase): StdPhase = new ClocPhase(prev) + + class ClocPhase(prev: nsc.Phase) extends StdPhase(prev) { + override def apply(unit: global.CompilationUnit): Unit = { + val file = unit.source.file.file + println(s"$file: ${countLines(file)}") + } + override def run() { + super.run() + // TODO something at the end? + } + } + + private def countLines(file: File): Int = { + val source = io.Source.fromFile(file) + try source.getLines.size + finally source.close() + } + +} diff --git a/src/main/scala/com/lightbend/tools/ClocPlugin.scala b/src/main/scala/com/lightbend/tools/ClocPlugin.scala new file mode 100644 index 0000000..f5f50d5 --- /dev/null +++ b/src/main/scala/com/lightbend/tools/ClocPlugin.scala @@ -0,0 +1,30 @@ +package com.lightbend.tools + +import scala.tools.nsc, + nsc.Global, + nsc.plugins.{Plugin, PluginComponent} + +class ClocPlugin(val global: Global) extends Plugin { + + override val name = "cloc" + override val description = "count lines of Scala code compiled" + + object component extends { + override val global = ClocPlugin.this.global + } with ClocComponent { + override val runsAfter = List("parser") + override val runsRightAfter = Some("parser") + override val terminal = true + } + + override val components = List[PluginComponent](component) + + override val optionsHelp: Option[String] = Some( + """|TODO""".stripMargin) + + override def init(options: List[String], error: String => Unit) = { + assume(options.isEmpty) + true + } + +} diff --git a/src/test/scala/com/lightbend/tools/PluginScaffold.scala b/src/test/scala/com/lightbend/tools/PluginScaffold.scala new file mode 100644 index 0000000..85b9cd4 --- /dev/null +++ b/src/test/scala/com/lightbend/tools/PluginScaffold.scala @@ -0,0 +1,27 @@ +package com.lightbend.tools + +import scala.tools.nsc.{Settings, Global} +import scala.tools.nsc.io.VirtualDirectory +import scala.reflect.internal.util.BatchSourceFile +import scala.reflect.io.AbstractFile + +object PluginScaffold { + + def defaultSettings: Settings = { + val settings = new Settings + settings.processArgumentString( + s"""-usejavacp -Xplugin:${BuildInfo.pluginPath} -Xplugin-require:cloc""") + settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None)) + settings + } + + def compile(code: java.io.File, + showSourceInfo: Boolean = false): Unit = { + val settings = defaultSettings + val sources = List(new BatchSourceFile(AbstractFile.getFile(code))) + val compiler = new Global(settings) + val run = (new compiler.Run) + run.compileSources(sources) + } + +} diff --git a/src/test/scala/com/lightbend/tools/PluginTests.scala b/src/test/scala/com/lightbend/tools/PluginTests.scala new file mode 100644 index 0000000..0d6328b --- /dev/null +++ b/src/test/scala/com/lightbend/tools/PluginTests.scala @@ -0,0 +1,9 @@ +package com.lightbend.tools + +import org.scalatest.FunSuite + +class PluginTests extends FunSuite { + test("foo") { + PluginScaffold.compile(new java.io.File("/Users/tisue/euler/src/main/net/tisue/euler/BigRational.scala")) + } +}