From 936733b2b10b4273ccc2a1731f6585e870b9c287 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 13 Sep 2017 12:02:21 +0100 Subject: [PATCH 1/4] Cleanup --- main-settings/src/main/scala/sbt/Def.scala | 41 ++++++++++++------- main-settings/src/main/scala/sbt/Scope.scala | 21 +++++++--- .../src/main/scala/sbt/ScopeMask.scala | 10 +++-- main/src/main/scala/sbt/Cross.scala | 32 ++++++++------- .../actions/cross-multiproject/build.sbt | 14 +++---- 5 files changed, 73 insertions(+), 45 deletions(-) diff --git a/main-settings/src/main/scala/sbt/Def.scala b/main-settings/src/main/scala/sbt/Def.scala index 6b195ba8d..534e674e3 100644 --- a/main-settings/src/main/scala/sbt/Def.scala +++ b/main-settings/src/main/scala/sbt/Def.scala @@ -27,26 +27,35 @@ object Def extends Init[Scope] with TaskMacroExtra { Invisible) lazy val showFullKey: Show[ScopedKey[_]] = showFullKey(None) + def showFullKey(keyNameColor: Option[String]): Show[ScopedKey[_]] = Show[ScopedKey[_]]((key: ScopedKey[_]) => displayFull(key, keyNameColor)) - def showRelativeKey(current: ProjectRef, - multi: Boolean, - keyNameColor: Option[String] = None): Show[ScopedKey[_]] = + def showRelativeKey( + current: ProjectRef, + multi: Boolean, + keyNameColor: Option[String] = None + ): Show[ScopedKey[_]] = Show[ScopedKey[_]]( - (key: ScopedKey[_]) => - Scope.display(key.scope, - withColor(key.key.label, keyNameColor), - ref => displayRelative(current, multi, ref))) + key => + Scope.display( + key.scope, + withColor(key.key.label, keyNameColor), + ref => displayRelative(current, multi, ref) + )) - def showBuildRelativeKey(currentBuild: URI, - multi: Boolean, - keyNameColor: Option[String] = None): Show[ScopedKey[_]] = + def showBuildRelativeKey( + currentBuild: URI, + multi: Boolean, + keyNameColor: Option[String] = None + ): Show[ScopedKey[_]] = Show[ScopedKey[_]]( - (key: ScopedKey[_]) => - Scope.display(key.scope, - withColor(key.key.label, keyNameColor), - ref => displayBuildRelative(currentBuild, multi, ref))) + key => + Scope.display( + key.scope, + withColor(key.key.label, keyNameColor), + ref => displayBuildRelative(currentBuild, multi, ref) + )) def displayRelative(current: ProjectRef, multi: Boolean, project: Reference): String = project match { @@ -55,15 +64,19 @@ object Def extends Init[Scope] with TaskMacroExtra { case ProjectRef(current.build, x) => x + "/" case _ => Reference.display(project) + "/" } + def displayBuildRelative(currentBuild: URI, multi: Boolean, project: Reference): String = project match { case BuildRef(`currentBuild`) => "{.}/" case ProjectRef(`currentBuild`, x) => x + "/" case _ => Reference.display(project) + "/" } + def displayFull(scoped: ScopedKey[_]): String = displayFull(scoped, None) + def displayFull(scoped: ScopedKey[_], keyNameColor: Option[String]): String = Scope.display(scoped.scope, withColor(scoped.key.label, keyNameColor)) + def displayMasked(scoped: ScopedKey[_], mask: ScopeMask): String = Scope.displayMasked(scoped.scope, scoped.key.label, mask) diff --git a/main-settings/src/main/scala/sbt/Scope.scala b/main-settings/src/main/scala/sbt/Scope.scala index 55665e783..25dd46c85 100644 --- a/main-settings/src/main/scala/sbt/Scope.scala +++ b/main-settings/src/main/scala/sbt/Scope.scala @@ -124,16 +124,22 @@ object Scope { } def display(config: ConfigKey): String = config.name + ":" + def display(scope: Scope, sep: String): String = displayMasked(scope, sep, showProject, ScopeMask()) + def displayMasked(scope: Scope, sep: String, mask: ScopeMask): String = displayMasked(scope, sep, showProject, mask) + def display(scope: Scope, sep: String, showProject: Reference => String): String = displayMasked(scope, sep, showProject, ScopeMask()) - def displayMasked(scope: Scope, - sep: String, - showProject: Reference => String, - mask: ScopeMask): String = { + + def displayMasked( + scope: Scope, + sep: String, + showProject: Reference => String, + mask: ScopeMask + ): String = { import scope.{ project, config, task, extra } val configPrefix = config.foldStrict(display, "*:", ".:") val taskPrefix = task.foldStrict(_.label + "::", "", ".::") @@ -148,9 +154,12 @@ object Scope { (!mask.task || a.task == b.task) && (!mask.extra || a.extra == b.extra) - def projectPrefix(project: ScopeAxis[Reference], - show: Reference => String = showProject): String = + def projectPrefix( + project: ScopeAxis[Reference], + show: Reference => String = showProject + ): String = project.foldStrict(show, "*/", "./") + def showProject = (ref: Reference) => Reference.display(ref) + "/" def transformTaskName(s: String) = { diff --git a/main-settings/src/main/scala/sbt/ScopeMask.scala b/main-settings/src/main/scala/sbt/ScopeMask.scala index 4e6d6096e..65b7acb80 100644 --- a/main-settings/src/main/scala/sbt/ScopeMask.scala +++ b/main-settings/src/main/scala/sbt/ScopeMask.scala @@ -1,10 +1,12 @@ package sbt /** Specifies the Scope axes that should be used for an operation. `true` indicates an axis should be used. */ -final case class ScopeMask(project: Boolean = true, - config: Boolean = true, - task: Boolean = true, - extra: Boolean = true) { +final case class ScopeMask( + project: Boolean = true, + config: Boolean = true, + task: Boolean = true, + extra: Boolean = true +) { def concatShow(p: String, c: String, t: String, sep: String, x: String): String = { val sb = new StringBuilder if (project) sb.append(p) diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 8cd7720b7..76487ade4 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -3,7 +3,7 @@ */ package sbt -import Keys.{ version, _ } +import Keys._ import sbt.internal.util.complete.{ DefaultParsers, Parser } import sbt.internal.util.AttributeKey import DefaultParsers._ @@ -225,12 +225,12 @@ object Cross { } private def switchScalaVersion(switch: Switch, state: State): State = { - val x = Project.extract(state) - import x._ + val extracted = Project.extract(state) + import extracted._ val (version, instance) = switch.version match { case ScalaHomeVersion(homePath, resolveVersion, _) => - val home = IO.resolve(x.currentProject.base, homePath) + val home = IO.resolve(extracted.currentProject.base, homePath) if (home.exists()) { val instance = ScalaInstance(home)(state.classLoaderCache.apply _) val version = resolveVersion.getOrElse(instance.actualVersion) @@ -243,8 +243,10 @@ object Cross { val binaryVersion = CrossVersion.binaryScalaVersion(version) - def logSwitchInfo(included: Seq[(ProjectRef, Seq[String])], - excluded: Seq[(ProjectRef, Seq[String])]) = { + def logSwitchInfo( + included: Seq[(ProjectRef, Seq[String])], + excluded: Seq[(ProjectRef, Seq[String])] + ) = { instance.foreach { case (home, instance) => @@ -274,14 +276,14 @@ object Cross { val projects: Seq[Reference] = { val projectScalaVersions = - structure.allProjectRefs.map(proj => proj -> crossVersions(x, proj)) + structure.allProjectRefs.map(proj => proj -> crossVersions(extracted, proj)) if (switch.version.force) { logSwitchInfo(projectScalaVersions, Nil) structure.allProjectRefs ++ structure.units.keys.map(BuildRef.apply) } else { val (included, excluded) = projectScalaVersions.partition { - case (proj, scalaVersions) => + case (_, scalaVersions) => scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion) } logSwitchInfo(included, excluded) @@ -289,14 +291,16 @@ object Cross { } } - setScalaVersionForProjects(version, instance, projects, state, x) + setScalaVersionForProjects(version, instance, projects, state, extracted) } - private def setScalaVersionForProjects(version: String, - instance: Option[(File, ScalaInstance)], - projects: Seq[Reference], - state: State, - extracted: Extracted): State = { + private def setScalaVersionForProjects( + version: String, + instance: Option[(File, ScalaInstance)], + projects: Seq[Reference], + state: State, + extracted: Extracted + ): State = { import extracted._ val newSettings = projects.flatMap { project => diff --git a/sbt/src/sbt-test/actions/cross-multiproject/build.sbt b/sbt/src/sbt-test/actions/cross-multiproject/build.sbt index 117efa724..23b73cbe5 100644 --- a/sbt/src/sbt-test/actions/cross-multiproject/build.sbt +++ b/sbt/src/sbt-test/actions/cross-multiproject/build.sbt @@ -1,19 +1,19 @@ -lazy val rootProj = (project in file(".")). - aggregate(libProj, fooPlugin). - settings( +lazy val rootProj = (project in file(".")) + .aggregate(libProj, fooPlugin) + .settings( scalaVersion := "2.12.1" ) -lazy val libProj = (project in file("lib")). - settings( +lazy val libProj = (project in file("lib")) + .settings( name := "foo-lib", scalaVersion := "2.12.1", crossScalaVersions := Seq("2.12.1", "2.11.8") ) -lazy val fooPlugin =(project in file("sbt-foo")). - settings( +lazy val fooPlugin = (project in file("sbt-foo")) + .settings( name := "sbt-foo", sbtPlugin := true, scalaVersion := "2.12.1", From 930fac2a78d0661a9354f8d103b248d18be202c2 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 13 Sep 2017 12:03:05 +0100 Subject: [PATCH 2/4] Restrict switchScalaVersion `projects` to just ResolvedReference's --- main/src/main/scala/sbt/Cross.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 76487ade4..3f9bca63a 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -274,7 +274,7 @@ object Cross { excluded.foreach(logProject.tupled) } - val projects: Seq[Reference] = { + val projects: Seq[ResolvedReference] = { val projectScalaVersions = structure.allProjectRefs.map(proj => proj -> crossVersions(extracted, proj)) if (switch.version.force) { From 3cb281945e6bd29df245e1cb0c26de110a5686d8 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 13 Sep 2017 15:32:57 +0100 Subject: [PATCH 3/4] Alias when strings are a scala version --- main/src/main/scala/sbt/Cross.scala | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 3f9bca63a..c89c32db0 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -228,6 +228,8 @@ object Cross { val extracted = Project.extract(state) import extracted._ + type ScalaVersion = String + val (version, instance) = switch.version match { case ScalaHomeVersion(homePath, resolveVersion, _) => val home = IO.resolve(extracted.currentProject.base, homePath) @@ -241,11 +243,9 @@ object Cross { case NamedScalaVersion(v, _) => (v, None) } - val binaryVersion = CrossVersion.binaryScalaVersion(version) - def logSwitchInfo( - included: Seq[(ProjectRef, Seq[String])], - excluded: Seq[(ProjectRef, Seq[String])] + included: Seq[(ProjectRef, Seq[ScalaVersion])], + excluded: Seq[(ProjectRef, Seq[ScalaVersion])] ) = { instance.foreach { @@ -264,7 +264,7 @@ object Cross { def detailedLog(msg: => String) = if (switch.verbose) state.log.info(msg) else state.log.debug(msg) - def logProject: (ProjectRef, Seq[String]) => Unit = (proj, scalaVersions) => { + def logProject: (ProjectRef, Seq[ScalaVersion]) => Unit = (proj, scalaVersions) => { val current = if (proj == currentRef) "*" else " " detailedLog(s" $current ${proj.project} ${scalaVersions.mkString("(", ", ", ")")}") } @@ -281,6 +281,7 @@ object Cross { logSwitchInfo(projectScalaVersions, Nil) structure.allProjectRefs ++ structure.units.keys.map(BuildRef.apply) } else { + val binaryVersion = CrossVersion.binaryScalaVersion(version) val (included, excluded) = projectScalaVersions.partition { case (_, scalaVersions) => From 71ae21184125320783a5b493e2ebcf518259e5a8 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 13 Sep 2017 15:45:52 +0100 Subject: [PATCH 4/4] Redefine crossScalaVersions, because it's Def.derive.. Fixes #3495 --- main/src/main/scala/sbt/Cross.scala | 49 +++++++++++-------- ...lusplus-not-changing-crossScalaVersions.md | 12 +++++ .../actions/cross-multiproject/build.sbt | 8 +++ .../sbt-test/actions/cross-multiproject/test | 7 +++ 4 files changed, 55 insertions(+), 21 deletions(-) create mode 100644 notes/1.0.2/plusplus-not-changing-crossScalaVersions.md diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index c89c32db0..02ff187ee 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -94,7 +94,7 @@ object Cross { (currentRef :: currentProject.aggregate.toList.flatMap(findAggregates)).distinct } - private def crossVersions(extracted: Extracted, proj: ProjectRef): Seq[String] = { + private def crossVersions(extracted: Extracted, proj: ResolvedReference): Seq[String] = { import extracted._ (crossScalaVersions in proj get structure.data) getOrElse { // reading scalaVersion is a one-time deal @@ -274,12 +274,14 @@ object Cross { excluded.foreach(logProject.tupled) } - val projects: Seq[ResolvedReference] = { + val projects: Seq[(ResolvedReference, Seq[ScalaVersion])] = { val projectScalaVersions = structure.allProjectRefs.map(proj => proj -> crossVersions(extracted, proj)) if (switch.version.force) { logSwitchInfo(projectScalaVersions, Nil) - structure.allProjectRefs ++ structure.units.keys.map(BuildRef.apply) + projectScalaVersions ++ structure.units.keys + .map(BuildRef.apply) + .map(proj => proj -> crossVersions(extracted, proj)) } else { val binaryVersion = CrossVersion.binaryScalaVersion(version) @@ -288,7 +290,7 @@ object Cross { scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion) } logSwitchInfo(included, excluded) - included.map(_._1) + included } } @@ -298,36 +300,41 @@ object Cross { private def setScalaVersionForProjects( version: String, instance: Option[(File, ScalaInstance)], - projects: Seq[Reference], + projects: Seq[(ResolvedReference, Seq[String])], state: State, extracted: Extracted ): State = { import extracted._ - val newSettings = projects.flatMap { project => - val scope = Scope(Select(project), Zero, Zero, Zero) + val newSettings = projects.flatMap { + case (project, scalaVersions) => + val scope = Scope(Select(project), Zero, Zero, Zero) - instance match { - case Some((home, inst)) => - Seq( - scalaVersion in scope := version, - scalaHome in scope := Some(home), - scalaInstance in scope := inst - ) - case None => - Seq( - scalaVersion in scope := version, - scalaHome in scope := None - ) - } + instance match { + case Some((home, inst)) => + Seq( + scalaVersion in scope := version, + crossScalaVersions in scope := scalaVersions, + scalaHome in scope := Some(home), + scalaInstance in scope := inst + ) + case None => + Seq( + scalaVersion in scope := version, + crossScalaVersions in scope := scalaVersions, + scalaHome in scope := None + ) + } } val filterKeys: Set[AttributeKey[_]] = Set(scalaVersion, scalaHome, scalaInstance).map(_.key) + val projectsContains: Reference => Boolean = projects.map(_._1).toSet.contains + // Filter out any old scala version settings that were added, this is just for hygiene. val filteredRawAppend = session.rawAppend.filter(_.key match { case ScopedKey(Scope(Select(ref), Zero, Zero, Zero), key) - if filterKeys.contains(key) && projects.contains(ref) => + if filterKeys.contains(key) && projectsContains(ref) => false case _ => true }) diff --git a/notes/1.0.2/plusplus-not-changing-crossScalaVersions.md b/notes/1.0.2/plusplus-not-changing-crossScalaVersions.md new file mode 100644 index 000000000..58e368794 --- /dev/null +++ b/notes/1.0.2/plusplus-not-changing-crossScalaVersions.md @@ -0,0 +1,12 @@ +[@dwijnand]: https://github.com/dwijnand + +[#3495]: https://github.com/sbt/sbt/issues/3495 +[#3526]: https://github.com/sbt/sbt/pull/3526 + +### Fixes with compatibility implications + +### Improvements + +### Bug fixes + +- Fixes `++` so it don't change the value of `crossScalaVersion`. [#3495][]/[#3526][] by [@dwijnand][] diff --git a/sbt/src/sbt-test/actions/cross-multiproject/build.sbt b/sbt/src/sbt-test/actions/cross-multiproject/build.sbt index 23b73cbe5..d0eff709c 100644 --- a/sbt/src/sbt-test/actions/cross-multiproject/build.sbt +++ b/sbt/src/sbt-test/actions/cross-multiproject/build.sbt @@ -1,3 +1,6 @@ +inThisBuild(List( + crossScalaVersions := Seq("2.12.1", "2.11.8") +)) lazy val rootProj = (project in file(".")) .aggregate(libProj, fooPlugin) @@ -20,4 +23,9 @@ lazy val fooPlugin = (project in file("sbt-foo")) crossScalaVersions := Seq("2.12.1") ) +lazy val extrasProj = (project in file("extras")) + .settings( + name := "foo-extras", + ) + addCommandAlias("build", "compile") diff --git a/sbt/src/sbt-test/actions/cross-multiproject/test b/sbt/src/sbt-test/actions/cross-multiproject/test index 154e71c2c..5458dcaf6 100644 --- a/sbt/src/sbt-test/actions/cross-multiproject/test +++ b/sbt/src/sbt-test/actions/cross-multiproject/test @@ -46,3 +46,10 @@ $ exists lib/target/scala-2.12 -$ exists lib/target/scala-2.11 $ exists sbt-foo/target/scala-2.12 -$ exists sbt-foo/target/scala-2.11 + +> clean +# Test ++ leaves crossScalaVersions unchanged +> ++2.12.1 +> +extrasProj/compile +$ exists extras/target/scala-2.11 +$ exists extras/target/scala-2.12