From 89a03b7dae92be54879c5a1a73708916e7c2deb3 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 29 Nov 2016 10:53:22 +0000 Subject: [PATCH 1/7] Scala 2.12.0 & sbt/io 1.0.0-M7 --- project/Dependencies.scala | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 7ebe4c8ed..f9fd1706f 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -2,11 +2,11 @@ import sbt._ import Keys._ object Dependencies { - lazy val scala210 = "2.10.6" - lazy val scala211 = "2.11.8" - lazy val scala212 = "2.12.0-M4" + val scala210 = "2.10.6" + val scala211 = "2.11.8" + val scala212 = "2.12.0" - private lazy val sbtIO = "org.scala-sbt" %% "io" % "1.0.0-M6" + private val sbtIO = "org.scala-sbt" %% "io" % "1.0.0-M7" def getSbtModulePath(key: String, name: String) = { val localProps = new java.util.Properties() @@ -26,17 +26,17 @@ object Dependencies { def addSbtIO(p: Project): Project = addSbtModule(p, sbtIoPath, "io", sbtIO) - lazy val jline = "jline" % "jline" % "2.13" + val jline = "jline" % "jline" % "2.13" - lazy val scalaCompiler = Def.setting { "org.scala-lang" % "scala-compiler" % scalaVersion.value } - lazy val scalaReflect = Def.setting { "org.scala-lang" % "scala-reflect" % scalaVersion.value } + val scalaCompiler = Def.setting { "org.scala-lang" % "scala-compiler" % scalaVersion.value } + val scalaReflect = Def.setting { "org.scala-lang" % "scala-reflect" % scalaVersion.value } val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.13.1" val scalatest = "org.scalatest" %% "scalatest" % "2.2.6" - lazy val parserCombinator211 = "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4" + val parserCombinator211 = "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4" - lazy val sjsonnewVersion = "0.5.1" - lazy val sjsonnew = "com.eed3si9n" %% "sjson-new-core" % sjsonnewVersion - lazy val sjsonnewScalaJson = "com.eed3si9n" %% "sjson-new-scalajson" % sjsonnewVersion + val sjsonnewVersion = "0.5.1" + val sjsonnew = "com.eed3si9n" %% "sjson-new-core" % sjsonnewVersion + val sjsonnewScalaJson = "com.eed3si9n" %% "sjson-new-scalajson" % sjsonnewVersion } From d86eab7a7a1e90082de121245cbd32397a1246ec Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 29 Nov 2016 11:07:36 +0000 Subject: [PATCH 2/7] sbt-doge 0.1.5 for plz --- project/doge.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/doge.sbt b/project/doge.sbt index fedea9490..e1274c941 100644 --- a/project/doge.sbt +++ b/project/doge.sbt @@ -1 +1 @@ -addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.3") +addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.5") From 875a30cc70acae2b3aff1219ae052879f23e3753 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 30 Nov 2016 15:03:38 +0000 Subject: [PATCH 3/7] Cleanup FileInfo --- .../scala/sbt/internal/util/FileInfo.scala | 145 ++++++++---------- 1 file changed, 61 insertions(+), 84 deletions(-) diff --git a/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala b/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala index cf83d01dd..28cf7de86 100644 --- a/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala +++ b/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala @@ -3,115 +3,101 @@ */ package sbt.internal.util -import sbt.io.Hash - import java.io.File -import sjsonnew.{ Builder, deserializationError, JsonFormat, Unbuilder } +import sbt.io.Hash +import sjsonnew.{ Builder, JsonFormat, Unbuilder, deserializationError } import CacheImplicits._ -sealed trait FileInfo { - def file: File -} - -sealed trait HashFileInfo extends FileInfo { - def hash: List[Byte] -} - -sealed trait ModifiedFileInfo extends FileInfo { - def lastModified: Long -} - -sealed trait PlainFileInfo extends FileInfo { - def exists: Boolean -} +sealed trait FileInfo { def file: File } +sealed trait HashFileInfo extends FileInfo { def hash: List[Byte] } +sealed trait ModifiedFileInfo extends FileInfo { def lastModified: Long } +sealed trait PlainFileInfo extends FileInfo { def exists: Boolean } sealed trait HashModifiedFileInfo extends HashFileInfo with ModifiedFileInfo + private final case class PlainFile(file: File, exists: Boolean) extends PlainFileInfo private final case class FileModified(file: File, lastModified: Long) extends ModifiedFileInfo private final case class FileHash(file: File, hash: List[Byte]) extends HashFileInfo private final case class FileHashModified(file: File, hash: List[Byte], lastModified: Long) extends HashModifiedFileInfo -object FileInfo { +final case class FilesInfo[F <: FileInfo] private (files: Set[F]) +object FilesInfo { + implicit def format[F <: FileInfo]: JsonFormat[FilesInfo[F]] = implicitly + def empty[F <: FileInfo]: FilesInfo[F] = FilesInfo(Set.empty[F]) +} +object FileInfo { sealed trait Style { type F <: FileInfo + implicit val format: JsonFormat[F] def apply(file: File): F - def apply(files: Set[File]): FilesInfo[F] = FilesInfo(files map apply) def unapply(info: F): File = info.file - def unapply(infos: FilesInfo[F]): Set[File] = infos.files map (_.file) } object full extends Style { - override type F = HashModifiedFileInfo + type F = HashModifiedFileInfo - override implicit val format: JsonFormat[HashModifiedFileInfo] = new JsonFormat[HashModifiedFileInfo] { - override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): HashModifiedFileInfo = - jsOpt match { - case Some(js) => - unbuilder.beginObject(js) - val file = unbuilder.readField[File]("file") - val hash = unbuilder.readField[List[Byte]]("hash") - val lastModified = unbuilder.readField[Long]("lastModified") - unbuilder.endObject() - FileHashModified(file, hash, lastModified) - case None => - deserializationError("Expected JsObject but found None") - } - - override def write[J](obj: HashModifiedFileInfo, builder: Builder[J]): Unit = { + implicit val format: JsonFormat[HashModifiedFileInfo] = new JsonFormat[HashModifiedFileInfo] { + def write[J](obj: HashModifiedFileInfo, builder: Builder[J]) = { builder.beginObject() builder.addField("file", obj.file) builder.addField("hash", obj.hash) builder.addField("lastModified", obj.lastModified) builder.endObject() } + + def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]) = jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val file = unbuilder.readField[File]("file") + val hash = unbuilder.readField[List[Byte]]("hash") + val lastModified = unbuilder.readField[Long]("lastModified") + unbuilder.endObject() + FileHashModified(file, hash, lastModified) + case None => deserializationError("Expected JsObject but found None") + } } - override implicit def apply(file: File): HashModifiedFileInfo = + implicit def apply(file: File): HashModifiedFileInfo = FileHashModified(file.getAbsoluteFile, Hash(file).toList, file.lastModified) } object hash extends Style { - override type F = HashFileInfo + type F = HashFileInfo - override implicit val format: JsonFormat[HashFileInfo] = new JsonFormat[HashFileInfo] { - override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): HashFileInfo = - jsOpt match { - case Some(js) => - unbuilder.beginObject(js) - val file = unbuilder.readField[File]("file") - val hash = unbuilder.readField[List[Byte]]("hash") - unbuilder.endObject() - FileHash(file, hash) - case None => - deserializationError("Expected JsObject but found None") - } - - override def write[J](obj: HashFileInfo, builder: Builder[J]): Unit = { + implicit val format: JsonFormat[HashFileInfo] = new JsonFormat[HashFileInfo] { + def write[J](obj: HashFileInfo, builder: Builder[J]) = { builder.beginObject() builder.addField("file", obj.file) builder.addField("hash", obj.hash) builder.endObject() } + + def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]) = jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val file = unbuilder.readField[File]("file") + val hash = unbuilder.readField[List[Byte]]("hash") + unbuilder.endObject() + FileHash(file, hash) + case None => deserializationError("Expected JsObject but found None") + } } - override implicit def apply(file: File): HashFileInfo = - FileHash(file.getAbsoluteFile, computeHash(file)) + implicit def apply(file: File): HashFileInfo = FileHash(file.getAbsoluteFile, computeHash(file)) - private def computeHash(file: File): List[Byte] = - try Hash(file).toList - catch { case _: Exception => Nil } + private def computeHash(file: File): List[Byte] = try Hash(file).toList catch { case _: Exception => Nil } } object lastModified extends Style { - override type F = ModifiedFileInfo + type F = ModifiedFileInfo - override implicit val format: JsonFormat[ModifiedFileInfo] = new JsonFormat[ModifiedFileInfo] { + implicit val format: JsonFormat[ModifiedFileInfo] = new JsonFormat[ModifiedFileInfo] { override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): ModifiedFileInfo = jsOpt match { case Some(js) => @@ -132,43 +118,34 @@ object FileInfo { } } - override implicit def apply(file: File): ModifiedFileInfo = - FileModified(file.getAbsoluteFile, file.lastModified) + implicit def apply(file: File): ModifiedFileInfo = FileModified(file.getAbsoluteFile, file.lastModified) } object exists extends Style { - override type F = PlainFileInfo + type F = PlainFileInfo - override implicit val format: JsonFormat[PlainFileInfo] = new JsonFormat[PlainFileInfo] { - override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): PlainFileInfo = - jsOpt match { - case Some(js) => - unbuilder.beginObject(js) - val file = unbuilder.readField[File]("file") - val exists = unbuilder.readField[Boolean]("exists") - unbuilder.endObject() - PlainFile(file, exists) - case None => - deserializationError("Expected JsObject but found None") - } - - override def write[J](obj: PlainFileInfo, builder: Builder[J]): Unit = { + implicit val format: JsonFormat[PlainFileInfo] = new JsonFormat[PlainFileInfo] { + def write[J](obj: PlainFileInfo, builder: Builder[J]): Unit = { builder.beginObject() builder.addField("file", obj.file) builder.addField("exists", obj.exists) builder.endObject() } + + def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]) = jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val file = unbuilder.readField[File]("file") + val exists = unbuilder.readField[Boolean]("exists") + unbuilder.endObject() + PlainFile(file, exists) + case None => deserializationError("Expected JsObject but found None") + } } - override implicit def apply(file: File): PlainFileInfo = { + implicit def apply(file: File): PlainFileInfo = { val abs = file.getAbsoluteFile PlainFile(abs, abs.exists) } } } - -final case class FilesInfo[F <: FileInfo] private (files: Set[F]) -object FilesInfo { - implicit def format[F <: FileInfo]: JsonFormat[FilesInfo[F]] = implicitly - def empty[F <: FileInfo]: FilesInfo[F] = FilesInfo(Set.empty[F]) -} From 71d104da3df26ae223d2b1f489a0b015e5f111eb Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 30 Nov 2016 15:03:53 +0000 Subject: [PATCH 4/7] Tweaks in FileInfo --- .../src/main/scala/sbt/internal/util/FileInfo.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala b/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala index 28cf7de86..b9d89b594 100644 --- a/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala +++ b/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala @@ -4,6 +4,7 @@ package sbt.internal.util import java.io.File +import scala.util.control.NonFatal import sbt.io.Hash import sjsonnew.{ Builder, JsonFormat, Unbuilder, deserializationError } import CacheImplicits._ @@ -30,7 +31,7 @@ object FileInfo { sealed trait Style { type F <: FileInfo - implicit val format: JsonFormat[F] + implicit def format: JsonFormat[F] def apply(file: File): F def apply(files: Set[File]): FilesInfo[F] = FilesInfo(files map apply) @@ -91,7 +92,7 @@ object FileInfo { implicit def apply(file: File): HashFileInfo = FileHash(file.getAbsoluteFile, computeHash(file)) - private def computeHash(file: File): List[Byte] = try Hash(file).toList catch { case _: Exception => Nil } + private def computeHash(file: File): List[Byte] = try Hash(file).toList catch { case NonFatal(_) => Nil } } object lastModified extends Style { From c6e793b03cbc0763d6af0ed45478b712df79950d Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 30 Nov 2016 15:04:27 +0000 Subject: [PATCH 5/7] Test FilesInfo brokenness --- .../src/test/scala/FileInfoSpec.scala | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 internal/util-cache/src/test/scala/FileInfoSpec.scala diff --git a/internal/util-cache/src/test/scala/FileInfoSpec.scala b/internal/util-cache/src/test/scala/FileInfoSpec.scala new file mode 100644 index 000000000..974956bc4 --- /dev/null +++ b/internal/util-cache/src/test/scala/FileInfoSpec.scala @@ -0,0 +1,23 @@ +package sbt.internal.util + +import scala.json.ast.unsafe._ +import sjsonnew._, support.scalajson.unsafe._ + +class FileInfoSpec extends UnitSpec { + val file = new java.io.File(".") + val fileInfo: ModifiedFileInfo = FileModified(file, file.lastModified()) + val filesInfo = FilesInfo(Set(fileInfo)) + + it should "round trip" in assertRoundTrip(filesInfo) + + def assertRoundTrip[A: JsonWriter: JsonReader](x: A) = { + val jsonString: String = toJsonString(x) + val jValue: JValue = Parser.parseUnsafe(jsonString) + val y: A = Converter.fromJson[A](jValue).get + assert(x === y) + } + + def assertJsonString[A: JsonWriter](x: A, s: String) = assert(toJsonString(x) === s) + + def toJsonString[A: JsonWriter](x: A): String = CompactPrinter(Converter.toJson(x).get) +} From 1368f5f9dbcd03fe35b02bbbbc8d035635ffc520 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 30 Nov 2016 16:21:37 +0000 Subject: [PATCH 6/7] Cleanup Input/Output/CacheStore --- .../scala/sbt/internal/util/CacheStore.scala | 88 +++++-------------- .../main/scala/sbt/internal/util/Input.scala | 25 ++---- .../main/scala/sbt/internal/util/Output.scala | 27 +++--- 3 files changed, 36 insertions(+), 104 deletions(-) diff --git a/internal/util-cache/src/main/scala/sbt/internal/util/CacheStore.scala b/internal/util-cache/src/main/scala/sbt/internal/util/CacheStore.scala index 175525658..c7e2674b7 100644 --- a/internal/util-cache/src/main/scala/sbt/internal/util/CacheStore.scala +++ b/internal/util-cache/src/main/scala/sbt/internal/util/CacheStore.scala @@ -1,23 +1,17 @@ package sbt.internal.util +import java.io.{ File, InputStream, OutputStream } +import sbt.io.syntax.fileToRichFile +import sbt.io.{ IO, Using } import sjsonnew.{ IsoString, JsonReader, JsonWriter, SupportConverter } -import java.io.{ File, InputStream, OutputStream } - -import sbt.io.{ IO, Using } -import sbt.io.syntax.fileToRichFile - -/** - * A `CacheStore` is used by the caching infrastructure to persist cached information. - */ +/** A `CacheStore` is used by the caching infrastructure to persist cached information. */ trait CacheStore extends Input with Output { /** Delete the persisted information. */ def delete(): Unit } -/** - * Factory that can derive new stores. - */ +/** Factory that can derive new stores. */ trait CacheStoreFactory { /** Create a new store. */ def derive(identifier: String): CacheStore @@ -26,74 +20,32 @@ trait CacheStoreFactory { def sub(identifier: String): CacheStoreFactory } -/** - * A factory that creates new stores persisted in `base`. - */ +/** A factory that creates new stores persisted in `base`. */ class DirectoryStoreFactory[J: IsoString](base: File, converter: SupportConverter[J]) extends CacheStoreFactory { - IO.createDirectory(base) - override def derive(identifier: String): CacheStore = - new FileBasedStore(base / identifier, converter) + def derive(identifier: String): CacheStore = new FileBasedStore(base / identifier, converter) - override def sub(identifier: String): CacheStoreFactory = - new DirectoryStoreFactory(base / identifier, converter) + def sub(identifier: String): CacheStoreFactory = new DirectoryStoreFactory(base / identifier, converter) } -/** - * A `CacheStore` that persists information in `file`. - */ +/** A `CacheStore` that persists information in `file`. */ class FileBasedStore[J: IsoString](file: File, converter: SupportConverter[J]) extends CacheStore { - IO.touch(file, setModified = false) - override def delete(): Unit = - IO.delete(file) + def read[T: JsonReader]() = Using.fileInputStream(file)(stream => new PlainInput(stream, converter).read()) - override def read[T: JsonReader](): T = - Using.fileInputStream(file) { stream => - val input = new PlainInput(stream, converter) - input.read() - } - - override def read[T: JsonReader](default: => T): T = - try read[T]() - catch { case _: Exception => default } - - override def write[T: JsonWriter](value: T): Unit = - Using.fileOutputStream(append = false)(file) { stream => - val output = new PlainOutput(stream, converter) - output.write(value) - } - - override def close(): Unit = () + def write[T: JsonWriter](value: T) = + Using.fileOutputStream(append = false)(file)(stream => new PlainOutput(stream, converter).write(value)) + def delete() = IO.delete(file) + def close() = () } -/** - * A store that reads from `inputStream` and writes to `outputStream - */ +/** A store that reads from `inputStream` and writes to `outputStream`. */ class StreamBasedStore[J: IsoString](inputStream: InputStream, outputStream: OutputStream, converter: SupportConverter[J]) extends CacheStore { - - override def delete(): Unit = () - - override def read[T: JsonReader](): T = { - val input = new PlainInput(inputStream, converter) - input.read() - } - - override def read[T: JsonReader](default: => T): T = - try read[T]() - catch { case _: Exception => default } - - override def write[T: JsonWriter](value: T): Unit = { - val output = new PlainOutput(outputStream, converter) - output.write(value) - } - - override def close(): Unit = { - inputStream.close() - outputStream.close() - } - -} \ No newline at end of file + def read[T: JsonReader]() = new PlainInput(inputStream, converter).read() + def write[T: JsonWriter](value: T) = new PlainOutput(outputStream, converter).write(value) + def delete() = () + def close() = { inputStream.close(); outputStream.close() } +} diff --git a/internal/util-cache/src/main/scala/sbt/internal/util/Input.scala b/internal/util-cache/src/main/scala/sbt/internal/util/Input.scala index 75eb92463..3426c117d 100644 --- a/internal/util-cache/src/main/scala/sbt/internal/util/Input.scala +++ b/internal/util-cache/src/main/scala/sbt/internal/util/Input.scala @@ -1,20 +1,18 @@ package sbt.internal.util -import sbt.io.{ IO, Using } - import java.io.{ Closeable, InputStream } - -import scala.util.{ Failure, Success } - +import scala.util.control.NonFatal import sjsonnew.{ IsoString, JsonReader, SupportConverter } +import sbt.io.{ IO, Using } trait Input extends Closeable { def read[T: JsonReader](): T - def read[T: JsonReader](default: => T): T + def read[T: JsonReader](default: => T): T = try read[T]() catch { case NonFatal(_) => default } } class PlainInput[J: IsoString](input: InputStream, converter: SupportConverter[J]) extends Input { val isoFormat: IsoString[J] = implicitly + private def readFully(): String = { Using.streamReader(input, IO.utf8) { reader => val builder = new StringBuilder() @@ -28,18 +26,7 @@ class PlainInput[J: IsoString](input: InputStream, converter: SupportConverter[J } } - override def read[T: JsonReader](): T = { - val string = readFully() - val json = isoFormat.from(string) - converter.fromJson(json) match { - case Success(value) => value - case Failure(ex) => throw ex - } - } + def read[T: JsonReader]() = converter.fromJson(isoFormat.from(readFully())).get - override def read[T: JsonReader](default: => T): T = - try read[T]() - catch { case _: Exception => default } - - override def close(): Unit = input.close() + def close() = input.close() } diff --git a/internal/util-cache/src/main/scala/sbt/internal/util/Output.scala b/internal/util-cache/src/main/scala/sbt/internal/util/Output.scala index 6e99db9ac..0472adee4 100644 --- a/internal/util-cache/src/main/scala/sbt/internal/util/Output.scala +++ b/internal/util-cache/src/main/scala/sbt/internal/util/Output.scala @@ -1,12 +1,8 @@ package sbt.internal.util -import sbt.io.Using - import java.io.{ Closeable, OutputStream } - -import scala.util.{ Failure, Success } - import sjsonnew.{ IsoString, JsonWriter, SupportConverter } +import sbt.io.Using trait Output extends Closeable { def write[T: JsonWriter](value: T): Unit @@ -14,19 +10,16 @@ trait Output extends Closeable { class PlainOutput[J: IsoString](output: OutputStream, converter: SupportConverter[J]) extends Output { val isoFormat: IsoString[J] = implicitly - override def write[T: JsonWriter](value: T): Unit = { - converter.toJson(value) match { - case Success(js) => - val asString = isoFormat.to(js) - Using.bufferedOutputStream(output) { writer => - val out = new java.io.PrintWriter(writer) - out.print(asString) - out.flush() - } - case Failure(ex) => - throw ex + + def write[T: JsonWriter](value: T) = { + val js = converter.toJson(value).get + val asString = isoFormat.to(js) + Using.bufferedOutputStream(output) { writer => + val out = new java.io.PrintWriter(writer) + out.print(asString) + out.flush() } } - override def close(): Unit = output.close() + def close() = output.close() } From 92e90c559ba01a5acdaa2dadb37e7def13cf5782 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 30 Nov 2016 16:49:59 +0000 Subject: [PATCH 7/7] Fix stackoverflow in implicit FilesInfo JsonFormat Fixes #61 * move it back into style * use that in Tracked (uncomment some code) * specify the style in the spec test * must define absolute file.. (doesn't pass with relative, which is wrong imo) --- .../src/main/scala/sbt/internal/util/FileInfo.scala | 2 +- internal/util-cache/src/test/scala/FileInfoSpec.scala | 4 ++-- .../src/main/scala/sbt/internal/util/Tracked.scala | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala b/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala index b9d89b594..b86068cfd 100644 --- a/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala +++ b/internal/util-cache/src/main/scala/sbt/internal/util/FileInfo.scala @@ -23,7 +23,6 @@ private final case class FileHashModified(file: File, hash: List[Byte], lastModi final case class FilesInfo[F <: FileInfo] private (files: Set[F]) object FilesInfo { - implicit def format[F <: FileInfo]: JsonFormat[FilesInfo[F]] = implicitly def empty[F <: FileInfo]: FilesInfo[F] = FilesInfo(Set.empty[F]) } @@ -32,6 +31,7 @@ object FileInfo { type F <: FileInfo implicit def format: JsonFormat[F] + implicit def formats: JsonFormat[FilesInfo[F]] = project(_.files, (fs: Set[F]) => FilesInfo(fs)) def apply(file: File): F def apply(files: Set[File]): FilesInfo[F] = FilesInfo(files map apply) diff --git a/internal/util-cache/src/test/scala/FileInfoSpec.scala b/internal/util-cache/src/test/scala/FileInfoSpec.scala index 974956bc4..55ad18666 100644 --- a/internal/util-cache/src/test/scala/FileInfoSpec.scala +++ b/internal/util-cache/src/test/scala/FileInfoSpec.scala @@ -4,11 +4,11 @@ import scala.json.ast.unsafe._ import sjsonnew._, support.scalajson.unsafe._ class FileInfoSpec extends UnitSpec { - val file = new java.io.File(".") + val file = new java.io.File(".").getAbsoluteFile val fileInfo: ModifiedFileInfo = FileModified(file, file.lastModified()) val filesInfo = FilesInfo(Set(fileInfo)) - it should "round trip" in assertRoundTrip(filesInfo) + it should "round trip" in assertRoundTrip(filesInfo)(FileInfo.lastModified.formats, FileInfo.lastModified.formats) def assertRoundTrip[A: JsonWriter: JsonReader](x: A) = { val jsonString: String = toJsonString(x) diff --git a/internal/util-tracking/src/main/scala/sbt/internal/util/Tracked.scala b/internal/util-tracking/src/main/scala/sbt/internal/util/Tracked.scala index 47f0b0f00..4db2acc0c 100644 --- a/internal/util-tracking/src/main/scala/sbt/internal/util/Tracked.scala +++ b/internal/util-tracking/src/main/scala/sbt/internal/util/Tracked.scala @@ -131,7 +131,7 @@ class Difference(val store: CacheStore, val style: FileInfo.Style, val defineCle } private def clearCache() = store.delete() - private def cachedFilesInfo = store.read(default = FilesInfo.empty[style.F]).files //(style.formats).files + private def cachedFilesInfo = store.read(default = FilesInfo.empty[style.F])(style.formats).files private def raw(fs: Set[style.F]): Set[File] = fs.map(_.file) def apply[T](files: Set[File])(f: ChangeReport[File] => T): T = @@ -164,7 +164,7 @@ class Difference(val store: CacheStore, val style: FileInfo.Style, val defineCle val result = f(report) val info = if (filesAreOutputs) style(abs(extractFiles(result))) else currentFilesInfo - store.write(info) + store.write(info)(style.formats) result }