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..02ff187ee 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._ @@ -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 @@ -225,12 +225,14 @@ object Cross { } private def switchScalaVersion(switch: Switch, state: State): State = { - val x = Project.extract(state) - import x._ + val extracted = Project.extract(state) + import extracted._ + + type ScalaVersion = String 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) @@ -241,10 +243,10 @@ object Cross { case NamedScalaVersion(v, _) => (v, None) } - val binaryVersion = CrossVersion.binaryScalaVersion(version) - - def logSwitchInfo(included: Seq[(ProjectRef, Seq[String])], - excluded: Seq[(ProjectRef, Seq[String])]) = { + def logSwitchInfo( + included: Seq[(ProjectRef, Seq[ScalaVersion])], + excluded: Seq[(ProjectRef, Seq[ScalaVersion])] + ) = { instance.foreach { case (home, instance) => @@ -262,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("(", ", ", ")")}") } @@ -272,57 +274,67 @@ object Cross { excluded.foreach(logProject.tupled) } - val projects: Seq[Reference] = { + val projects: Seq[(ResolvedReference, Seq[ScalaVersion])] = { 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) + projectScalaVersions ++ structure.units.keys + .map(BuildRef.apply) + .map(proj => proj -> crossVersions(extracted, proj)) } else { + val binaryVersion = CrossVersion.binaryScalaVersion(version) val (included, excluded) = projectScalaVersions.partition { - case (proj, scalaVersions) => + case (_, scalaVersions) => scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion) } logSwitchInfo(included, excluded) - included.map(_._1) + included } } - 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[(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 117efa724..d0eff709c 100644 --- a/sbt/src/sbt-test/actions/cross-multiproject/build.sbt +++ b/sbt/src/sbt-test/actions/cross-multiproject/build.sbt @@ -1,23 +1,31 @@ +inThisBuild(List( + crossScalaVersions := Seq("2.12.1", "2.11.8") +)) -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", 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