diff options
-rw-r--r-- | examples/scalafmt-example/README.md | 16 | ||||
-rw-r--r-- | examples/scalafmt-example/build/build.scala | 29 | ||||
-rw-r--r-- | examples/scalafmt-example/build/build/build.scala | 5 | ||||
-rw-r--r-- | examples/scalafmt-example/resources/reference.conf | 8 | ||||
-rw-r--r-- | examples/scalafmt-example/src/Main.scala | 16 | ||||
-rw-r--r-- | examples/scalariform-example/README.md | 15 | ||||
-rw-r--r-- | examples/scalariform-example/build/build.scala | 10 | ||||
-rw-r--r-- | plugins/scalafmt/Scalafmt.scala | 69 | ||||
-rw-r--r-- | plugins/scalafmt/build/build.scala | 9 | ||||
-rw-r--r-- | plugins/scalariform/Scalariform.scala | 9 | ||||
-rw-r--r-- | stage1/logger.scala | 38 | ||||
-rw-r--r-- | stage2/BuildBuild.scala | 1 | ||||
-rw-r--r-- | test/test.scala | 4 |
13 files changed, 199 insertions, 30 deletions
diff --git a/examples/scalafmt-example/README.md b/examples/scalafmt-example/README.md new file mode 100644 index 0000000..0a59f96 --- /dev/null +++ b/examples/scalafmt-example/README.md @@ -0,0 +1,16 @@ +This example shows integration with scalafmt plugin. + +Reformat executed on every `cbt compile` call, and affects only *.scala source files. + +You can provide your custom scalfmt preferences in build via `scalafmtConfig`. + +To see formatting in action: execute `cbt breakFormatting` to break formatting and then execute`cbt scalafmt` to get formatting back. + +To check if your code is properly formatted(for example as part of CI validation), you can execute: + +``` +cbt scalafmt +git diff --exit-code +``` + +Last command will return non-zero code, if your code isn't properly formatted. diff --git a/examples/scalafmt-example/build/build.scala b/examples/scalafmt-example/build/build.scala new file mode 100644 index 0000000..6f77108 --- /dev/null +++ b/examples/scalafmt-example/build/build.scala @@ -0,0 +1,29 @@ +import cbt._ +import org.scalafmt.ScalafmtStyle + +class Build(val context: Context) extends BuildBuild with Scalafmt { + override def compile = { + scalafmt + super.compile + } + + override def scalafmtConfig: ScalafmtStyle = ScalafmtStyle.defaultWithAlign + + def breakFormatting = { + import java.nio.file._ + import java.nio.charset.Charset + import scala.collection.JavaConverters._ + val utf8 = Charset.forName("UTF-8") + sourceFiles foreach { file => + try { + val path = file.toPath + val fileLines = Files.readAllLines(path, utf8).asScala + val brokenLines = fileLines map (_.dropWhile(_ ==' ')) + Files.write(path, brokenLines.asJava, utf8) + } catch { + case e: Exception => System.err.print(s"Error happend when breaking formatting: ${e}") + } + } + System.err.println("Done breaking formatting") + } +} diff --git a/examples/scalafmt-example/build/build/build.scala b/examples/scalafmt-example/build/build/build.scala new file mode 100644 index 0000000..aa70f36 --- /dev/null +++ b/examples/scalafmt-example/build/build/build.scala @@ -0,0 +1,5 @@ +import cbt._ + +class Build(val context: Context) extends BuildBuild { + override def dependencies = super.dependencies :+ plugins.scalafmt +} diff --git a/examples/scalafmt-example/resources/reference.conf b/examples/scalafmt-example/resources/reference.conf new file mode 100644 index 0000000..f3e122d --- /dev/null +++ b/examples/scalafmt-example/resources/reference.conf @@ -0,0 +1,8 @@ +// should not reformat this, cause it is not in source files +some { + inside { + foo: 22 + bar: false + baz: "hello" + } +} diff --git a/examples/scalafmt-example/src/Main.scala b/examples/scalafmt-example/src/Main.scala new file mode 100644 index 0000000..595cede --- /dev/null +++ b/examples/scalafmt-example/src/Main.scala @@ -0,0 +1,16 @@ +import scala.concurrent.{Await, Future} +import scala.concurrent.duration._ + +object Main extends App { + println("fooo") + val futureRes = Await.result(Future.successful(1), 5.seconds) + List(1, 2, 4, 5, 6) match { + case h :: _ => println("not empty list") + case Nil => println("empty list") + } + + List(1 -> 2, 2 -> 3, 3 -> 4) match { + case (1, 2) :: _ => 90 -> 1 + case (22, 44) :: _ => 1 -> 150 + } +} diff --git a/examples/scalariform-example/README.md b/examples/scalariform-example/README.md index e599b5b..28ad226 100644 --- a/examples/scalariform-example/README.md +++ b/examples/scalariform-example/README.md @@ -1,5 +1,16 @@ This example shows integration with scalariform plugin. + Reformat executed on every `cbt compile` call, and affects only *.scala source files. + You can provide your custom scalariform preferences in build via `scalariformPreferences`. -To test formatting in action you can execute: `cbt breakFormatting` to break formatting -and `cbt scalariformReformat` to get formatting back. + +To see formatting in action: execute `cbt breakFormatting` to break formatting and then execute `cbt scalariformFormat` to get formatting back. + +To check if your code is properly formatted(for example as part of CI validation), you can execute: + +``` +cbt scalariformFormat +git diff --exit-code +``` + +Last command will return non-zero code, if your code isn't properly formatted. diff --git a/examples/scalariform-example/build/build.scala b/examples/scalariform-example/build/build.scala index b9caa59..5f7b7ff 100644 --- a/examples/scalariform-example/build/build.scala +++ b/examples/scalariform-example/build/build.scala @@ -1,7 +1,7 @@ import cbt._ import scalariform.formatter.preferences._ -class Build(val context: Context) extends BuildBuild with Scalariform { +class Build(val context: Context) extends BaseBuild with Scalariform { override def compile = { scalariformFormat super.compile @@ -13,15 +13,17 @@ class Build(val context: Context) extends BuildBuild with Scalariform { .setPreference(DoubleIndentClassDeclaration, true) .setPreference(RewriteArrowSymbols, true) - def breakFormatting = { + final def breakFormatting = { import java.nio.file._ + import java.nio.charset.Charset import scala.collection.JavaConverters._ + val utf8 = Charset.forName("UTF-8") sourceFiles foreach { file => try { val path = file.toPath - val fileLines = Files.readAllLines(path).asScala + val fileLines = Files.readAllLines(path, utf8).asScala val brokenLines = fileLines map (_.dropWhile(_ ==' ')) - Files.write(path, brokenLines.asJava) + Files.write(path, brokenLines.asJava, utf8) } catch { case e: Exception => System.err.print(s"Error happend when breaking formatting: ${e}") } diff --git a/plugins/scalafmt/Scalafmt.scala b/plugins/scalafmt/Scalafmt.scala new file mode 100644 index 0000000..94670cb --- /dev/null +++ b/plugins/scalafmt/Scalafmt.scala @@ -0,0 +1,69 @@ +package cbt + +import org.scalafmt.{FormatResult, ScalafmtStyle} + +import java.io.File +import java.nio.file.Files._ +import java.nio.file.{FileSystems, Path} + +/** + * This plugin provides scalafmt support for cbt. + * + */ +trait Scalafmt extends BaseBuild { + /** + * Reformat scala source code according to `scalafmtConfig` rules + * + * @return always returns `ExitCode.Success` + */ + final def scalafmt: ExitCode = { + Scalafmt.format(sourceFiles, scalafmtConfig) + ExitCode.Success + } + + /** + * Scalafmt formatting config + */ + def scalafmtConfig: ScalafmtStyle = Scalafmt.defaultConfig +} + +object Scalafmt { + + val defaultConfig = ScalafmtStyle.default + + def format(files: Seq[File], style: ScalafmtStyle): Unit = { + var reformattedCount: Int = 0 + scalaSourceFiles(files) foreach { path => + handleFormatted(path, style) { case (original, result) => + result match { + case FormatResult.Success(formatted) => + if (original != formatted) { + write(path, formatted.getBytes) + reformattedCount += 1 + } + case FormatResult.Failure(e) => + System.err.println(s"Failed to format file: $path, cause: ${e}") + case FormatResult.Incomplete(e) => + System.err.println(s"Couldn't complete file reformat: $path") + } + } + } + if (reformattedCount > 0) System.err.println(s"Formatted $reformattedCount Scala sources") + } + + private val scalaFileMatcher = FileSystems.getDefault.getPathMatcher("glob:**.scala") + + private def scalaSourceFiles(files: Seq[File]): Seq[Path] = { + files collect { + case f if f.exists + && scalaFileMatcher.matches(f.toPath) => f.toPath + } + } + + private def handleFormatted[T](path: Path, style: ScalafmtStyle)(handler: (String, FormatResult) => T): T = { + val original = new String(readAllBytes(path)) + val result = org.scalafmt.Scalafmt.format(original, style) + handler(original, result) + } + +} diff --git a/plugins/scalafmt/build/build.scala b/plugins/scalafmt/build/build.scala new file mode 100644 index 0000000..e8ce270 --- /dev/null +++ b/plugins/scalafmt/build/build.scala @@ -0,0 +1,9 @@ +import cbt._ + +class Build(val context: Context) extends Plugin { + override def dependencies = + super.dependencies ++ + Resolver( mavenCentral ).bind( + ScalaDependency("com.geirsson", "scalafmt", "0.2.5") + ) +} diff --git a/plugins/scalariform/Scalariform.scala b/plugins/scalariform/Scalariform.scala index 1f6e51f..0612469 100644 --- a/plugins/scalariform/Scalariform.scala +++ b/plugins/scalariform/Scalariform.scala @@ -4,13 +4,12 @@ import java.io.File import java.nio.file.FileSystems import java.nio.file.Files._ -import scala.util.Try import scalariform.formatter.ScalaFormatter import scalariform.formatter.preferences.FormattingPreferences import scalariform.parser.ScalaParserException trait Scalariform extends BaseBuild { - def scalariformFormat: ExitCode = { + final def scalariformFormat: ExitCode = { Scalariform.format(sourceFiles, scalariformPreferences, scalaVersion) ExitCode.Success } @@ -35,7 +34,7 @@ object Scalariform { private val scalaFileMatcher = FileSystems.getDefault.getPathMatcher("glob:**.scala") - def format(files: Seq[File], preferences: FormattingPreferences, scalaVersion: String) = { + def format(files: Seq[File], preferences: FormattingPreferences, scalaVersion: String): Unit = { var reformattedCount: Int = 0 for (file <- files if file.exists) { val path = file.toPath @@ -52,11 +51,11 @@ object Scalariform { reformattedCount += 1 } } catch { - case e: ScalaParserException => System.err.println(s"Scalariform parser error: ${e.getMessage} when formatting source: $file") + case e: ScalaParserException => System.err.println(s"Scalariform parser error: ${e.getMessage} when formatting: $file") } } } - System.err.println(s"Reformatted $reformattedCount Scala sources") + if (reformattedCount > 0) System.err.println(s"Formatted $reformattedCount Scala sources") } } diff --git a/stage1/logger.scala b/stage1/logger.scala index 1e0a693..0b352a1 100644 --- a/stage1/logger.scala +++ b/stage1/logger.scala @@ -11,22 +11,26 @@ case class Logger(enabledLoggers: Set[String], start: Long) { def this(enabledLoggers: Option[String], start: Long) = this( enabledLoggers.toVector.flatMap( _.split(",") ).toSet, start ) def log(name: String, msg: => String) = { - val timeTaken = ((System.currentTimeMillis.toDouble - start) / 1000).toString - System.err.println( s"[$timeTaken][$name] $msg" ) + if( + (enabledLoggers contains name) + || (enabledLoggers contains "all") + ){ + logUnguarded(name, msg) + } } def showInvocation(method: String, args: Any) = method ++ "( " ++ args.toString ++ " )" - final def stage1(msg: => String) = logGuarded(names.stage1, msg) - final def stage2(msg: => String) = logGuarded(names.stage2, msg) - final def loop(msg: => String) = logGuarded(names.loop, msg) - final def task(msg: => String) = logGuarded(names.task, msg) - final def composition(msg: => String) = logGuarded(names.composition, msg) - final def resolver(msg: => String) = logGuarded(names.resolver, msg) - final def lib(msg: => String) = logGuarded(names.lib, msg) - final def test(msg: => String) = logGuarded(names.test, msg) - final def git(msg: => String) = logGuarded(names.git, msg) - final def pom(msg: => String) = logGuarded(names.pom, msg) + final def stage1(msg: => String) = log(names.stage1, msg) + final def stage2(msg: => String) = log(names.stage2, msg) + final def loop(msg: => String) = log(names.loop, msg) + final def task(msg: => String) = log(names.task, msg) + final def composition(msg: => String) = log(names.composition, msg) + final def resolver(msg: => String) = log(names.resolver, msg) + final def lib(msg: => String) = log(names.lib, msg) + final def test(msg: => String) = log(names.test, msg) + final def git(msg: => String) = log(names.git, msg) + final def pom(msg: => String) = log(names.pom, msg) private object names{ val stage1 = "stage1" @@ -41,12 +45,8 @@ case class Logger(enabledLoggers: Set[String], start: Long) { val git = "git" } - private def logGuarded(name: String, msg: => String) = { - if( - (enabledLoggers contains name) - || (enabledLoggers contains "all") - ){ - log(name, msg) - } + private def logUnguarded(name: String, msg: => String) = { + val timeTaken = ((System.currentTimeMillis.toDouble - start) / 1000).toString + System.err.println( s"[$timeTaken][$name] $msg" ) } } diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala index 83ea7ec..dec438b 100644 --- a/stage2/BuildBuild.scala +++ b/stage2/BuildBuild.scala @@ -12,6 +12,7 @@ trait BuildBuild extends BaseBuild{ final val sbtLayout = DirectoryDependency( managedContext.cbtHome ++ "/plugins/sbt_layout" ) final val scalaJs = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalajs" ) final val scalariform = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalariform" ) + final val scalafmt = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalafmt" ) } override def dependencies = diff --git a/test/test.scala b/test/test.scala index 050be1f..4ed7e97 100644 --- a/test/test.scala +++ b/test/test.scala @@ -158,8 +158,12 @@ object Main{ compile("simple-fixed") compile("../plugins/sbt_layout") + compile("../plugins/scalafmt") compile("../plugins/scalajs") + compile("../plugins/scalariform") compile("../plugins/scalatest") + compile("../examples/scalafmt-example") + compile("../examples/scalariform-example") compile("../examples/scalatest-example") compile("../examples/scalajs-react-example/js") compile("../examples/scalajs-react-example/jvm") |