Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implicit convert TaskKey with the macro! #119

Merged
merged 4 commits into from
Mar 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Add the following in your `build.sbt`:
lazy val root = (project in file(".")).
enablePlugins(BuildInfoPlugin).
settings(
buildInfoKeys := BuildInfoKey.ofN(name, version, scalaVersion, sbtVersion),
buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion),
buildInfoPackage := "hello"
)
```
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
lazy val commonSettings: Seq[Setting[_]] = Seq(
git.baseVersion in ThisBuild := "0.8.0",
git.baseVersion in ThisBuild := "0.9.0",
organization in ThisBuild := "com.eed3si9n"
)

Expand Down
44 changes: 44 additions & 0 deletions notes/0.9.0.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[@dwijnand]: https://github.com/dwijnand

sbt-buildinfo 0.9.0 is published for sbt 1.

### `TaskKey` to `BuildInfoKey` conversion potentially breaking semantic change

*TL;DR* No need for `BuildInfoKey.of(...)` or `BuildInfoKey.ofN(...)` any more. Use
`BuildInfoKey.outOfGraphUnsafe` if your build definition is now circular.

sbt-buildinfo 0.8.0 deprecated the original `TaskKey[A]` to `BuildInfoKey.Entry[A]` implicit and explicit
conversions (`BuildInfoKey.task` and `BuildInfoKey.apply` respectively), that executed the underlying sbt Task
out of sbt's task graph execution, in favour of a newly introduced `BuildInfoKey.of(...)` and
`BuildInfoKey.ofN(...)` API, which correctly wired up the task graph. See [#114][].

As it was implemented (and released) it interacted poorly with sbt-buildinfo's `BuildInfoKey.map` API
([#117][]), due to a mistake in the implementation and test coverage.

In resolving the issue it became clear that instead of introducing a new API, that required sbt-buildinfo users
to change their source code to use, the already used conversions could have been modified to use the new
Task-based semantics.

However, this change breaks any build definition that declares as a build info key any `TaskKey` that depends on
`sourceGenerators` or `resourceGenerators`, because the build definiton would now be circular and fail to load.
To fix this breaking semantic change the user has to either drop the key used, choose another key, or fallback
to the previous semantics by using the not-deprecated `BuildInfoKey.outOfGraphUnsafe` API, also introduced in
sbt-buildinfo 0.8.0.

[#117][]/[#119][] by [@dwijnand][]

[#114]: https://github.com/sbt/sbt-buildinfo/pull/114
[#117]: https://github.com/sbt/sbt-buildinfo/issues/117
[#119]: https://github.com/sbt/sbt-buildinfo/pull/119

### Add direct support for sbt's `Attributed`

A number of keys defined by sbt use sbt's `Attributed` type, specifically the keys that define classpaths.
Prior to this change defining any of these keys as a build info key would generate `Seq[String]` as `Attributed`
would be simply converted to string with `toString`. sbt-buildinfo 0.9.0 introduces direct support for these
keys so they generate `Seq[File]` instead.

[#112][]/[#120][] by [@dwijnand][]

[#112]: https://github.com/sbt/sbt-buildinfo/issues/112
[#120]: https://github.com/sbt/sbt-buildinfo/pull/120
17 changes: 11 additions & 6 deletions src/main/scala/sbtbuildinfo/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ package object sbtbuildinfo {
type BuildInfoKey = BuildInfoKey.Entry[_]
object BuildInfoKey {
implicit def setting[A](key: SettingKey[A]): Entry[A] = Setting(key)
@deprecated("Explicitly wrap in BuildInfoKey.of/ofN. Or if out-of-graph execution is required use BuildInfoKey.outOfGraphUnsafe", "0.7.1")
implicit def task[A](key: TaskKey[A]): Entry[A] = Task(key)
implicit def task[A](key: TaskKey[A]): Entry[A] = macro BuildInfoKeyMacros.taskImpl
implicit def taskValue[A: Manifest](task: sbt.Task[A]): Entry[A] = TaskValue(task)
implicit def constant[A: Manifest](tuple: (String, A)): Entry[A] = Constant(tuple)

def apply[A](key: SettingKey[A]): Entry[A] = Setting(key)
@deprecated("Explicitly wrap in BuildInfoKey.of/ofN. Or if out-of-graph execution is required use BuildInfoKey.outOfGraphUnsafe", "0.7.1")
def apply[A](key: TaskKey[A]): Entry[A] = Task(key)
def apply[A](key: TaskKey[A]): Entry[A] = macro BuildInfoKeyMacros.taskImpl
def apply[A: Manifest](tuple: (String, A)): Entry[A] = Constant(tuple)
def map[A, B: Manifest](from: Entry[A])(fun: ((String, A)) => (String, B)): Entry[B] =
BuildInfoKey.Mapped(from, fun)
def action[A: Manifest](name: String)(fun: => A): Entry[A] = Action(name, () => fun)

def of(x: Any): BuildInfoKey = macro BuildInfoKeyMacros.ofImpl
def ofN(xs: Any*): Seq[BuildInfoKey] = macro BuildInfoKeyMacros.ofNImpl
def of[A](x: BuildInfoKey.Entry[A]): BuildInfoKey.Entry[A] = x
def ofN(xs: BuildInfoKey*): Seq[BuildInfoKey] = xs

def outOfGraphUnsafe[A](key: TaskKey[A]): Entry[A] = Task(key)

Expand Down Expand Up @@ -54,6 +52,12 @@ package object sbtbuildinfo {

val BuildInfoKey = q"_root_.sbtbuildinfo.BuildInfoKey"

def taskImpl(key: Tree): Tree = {
val A = key.tpe.typeArgs.head
q"$BuildInfoKey.taskValue[$A]($key.taskValue)($key.key.manifest.typeArguments.head.asInstanceOf[Manifest[$A]])"
}

@deprecated("No longer used", "0.9.0")
def ofImpl(x: Tree): Tree = {
x.tpe match {
case tpe if tpe <:< typeOf[SettingKey[_]] =>
Expand All @@ -72,6 +76,7 @@ package object sbtbuildinfo {
}
}

@deprecated("No longer used", "0.9.0")
def ofNImpl(xs: Tree*): Tree = q"_root_.scala.Seq(..${xs map ofImpl})"

}
Expand Down
2 changes: 1 addition & 1 deletion src/sbt-test/sbt-buildinfo/simple/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ lazy val root = (project in file(".")).
""" /** The value is "helloworld". */"""::
""" val name: String = "helloworld"""" ::
""" /** The value is 0.1. */"""::
""" val projectVersion: scala.Double = 0.1""" ::
""" val projectVersion = 0.1""" ::
""" /** The value is "2.11.8". */""" ::
""" val scalaVersion: String = "2.11.8"""" ::
""" /** The value is scala.collection.Seq(). */""" ::
Expand Down
2 changes: 1 addition & 1 deletion src/sbt-test/sbt-buildinfo/task/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ val projOutOfTaskGraph1 = project settings (
val projOutOfTaskGraph2 = project dependsOn projOutOfTaskGraph1 settings (
BuildInfoPlugin.buildInfoDefaultSettings,
addBuildInfoToConfig(Test),
buildInfoKeys in Test += fullClasspath in Compile // intentionally uses the deprecated implicit conversion
buildInfoKeys in Test += BuildInfoKey.outOfGraphUnsafe(fullClasspath in Compile),
)

val projInTaskGraph1 = project settings (
Expand Down
2 changes: 1 addition & 1 deletion src/sbt-test/sbt-buildinfo/usepackageaspath/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ lazy val root = (project in file(".")).
""" /** The value is "helloworld". */"""::
""" val name: String = "helloworld"""" ::
""" /** The value is 0.1. */"""::
""" val projectVersion: scala.Double = 0.1""" ::
""" val projectVersion = 0.1""" ::
""" /** The value is "2.10.2". */""" ::
""" val scalaVersion: String = "2.10.2"""" ::
""" /** The value is scala.collection.Seq(). */""" ::
Expand Down
21 changes: 12 additions & 9 deletions src/test/scala/sbtbuildinfo/BuildInfoKeySpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package sbtbuildinfo
import sbt._, Keys._
import BuildInfoPlugin.autoImport._

/** This is a compile-only test of the BuildInfoKey syntax/macros. */
object BuildInfoKeySpec {
// duplicate the out of box implicit so we don't get deprecation warnings in this testing code
implicit def task[A](key: TaskKey[A]): BuildInfoKey.Entry[A] = BuildInfoKey.Task(key)

buildInfoKeys := Seq(name, version) // test `:=` works with setting keys
buildInfoKeys := Seq(products, fullClasspath) // test `:=` works with task keys
buildInfoKeys := Seq(name, fullClasspath) // test `:=` works with setting and task keys
Expand All @@ -15,25 +13,28 @@ object BuildInfoKeySpec {
fullClasspath,
"year" -> 2012,
BuildInfoKey.action("buildTime") { 1234L },
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble }
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble },
BuildInfoKey.map(fullClasspath) { case (ident, cp) => ident -> cp.files },
)

buildInfoKeys += name // test `+=` works with a setting key
buildInfoKeys += fullClasspath // test `+=` works with a task key
//buildInfoKeys += fullClasspath // test `+=` works with a task key
buildInfoKeys += (fullClasspath: BuildInfoKey) // test `+=` works with a task key
buildInfoKeys += "year" -> 2012 // test `+=` works with constants
buildInfoKeys += BuildInfoKey.action("buildTime") { 1234L } // test `+=` works with BuildInfoKey's
buildInfoKeys += BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble }

buildInfoKeys ++= Seq(name, version) // test `++=` works with setting keys
buildInfoKeys ++= Seq(fullClasspath) // test `++=` works with 1 task key
buildInfoKeys ++= Seq[BuildInfoKey](fullClasspath) // test `++=` works with 1 task key
buildInfoKeys ++= Seq[BuildInfoKey](products, fullClasspath) // test `++=` works with n task keys
buildInfoKeys ++= Seq[BuildInfoKey](name, fullClasspath) // test `++=` works with setting and task keys
buildInfoKeys ++= Seq[BuildInfoKey]( // test `++=` works with misc things
name,
fullClasspath,
"year" -> 2012,
BuildInfoKey.action("buildTime") { 1234L },
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble }
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble },
BuildInfoKey.map(fullClasspath) { case (ident, cp) => ident -> cp.files },
)


Expand All @@ -45,7 +46,8 @@ object BuildInfoKeySpec {
fullClasspath,
"year" -> 2012,
BuildInfoKey.action("buildTime") { 1234L },
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble }
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble },
BuildInfoKey.map(fullClasspath) { case (ident, cp) => ident -> cp.files },
)

buildInfoKeys += BuildInfoKey.of(name) // test `+=` works with a setting key
Expand All @@ -60,6 +62,7 @@ object BuildInfoKeySpec {
fullClasspath,
"year" -> 2012,
BuildInfoKey.action("buildTime") { 1234L },
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble }
BuildInfoKey.map(version) { case (_, v) => "projectVersion" -> v.toDouble },
BuildInfoKey.map(fullClasspath) { case (ident, cp) => ident -> cp.files },
)
}