diff --git a/ivy/CrossVersion.scala b/ivy/CrossVersion.scala new file mode 100644 index 000000000..59b51c795 --- /dev/null +++ b/ivy/CrossVersion.scala @@ -0,0 +1,94 @@ +package sbt + +final case class ScalaVersion(full: String, binary: String) + +sealed trait CrossVersion +object CrossVersion +{ + val TransitionScalaVersion = "2.10" + val TransitionSbtVersion = "0.12" + + object Disabled extends CrossVersion { override def toString = "disabled" } + final class Binary(val remapVersion: String => String) extends CrossVersion { + override def toString = "Binary" + } + final class Full(val remapVersion: String => String) extends CrossVersion { + override def toString = "Full" + } + + def full: CrossVersion = new Full(idFun) + def fullMapped(remapVersion: String => String): CrossVersion = new Full(remapVersion) + + def binary: CrossVersion = new Binary(idFun) + def binaryMapped(remapVersion: String => String): CrossVersion = new Full(remapVersion) + + private[this] def idFun[T]: T => T = x => x + def append(s: String): Option[String => String] = Some(x => crossName(x, s)) + + def apply(cross: CrossVersion, fullVersion: String, binaryVersion: String): Option[String => String] = + cross match + { + case Disabled => None + case b: Binary => append(b.remapVersion(binaryVersion)) + case f: Full => append(f.remapVersion(fullVersion)) + } + + def apply(module: ModuleID, is: IvyScala): Option[String => String] = + CrossVersion(module.crossVersion, is.scalaFullVersion, is.scalaBinaryVersion) + + def apply(module: ModuleID, is: Option[IvyScala]): Option[String => String] = + is flatMap { i => apply(module, i) } + + def substituteCross(artifacts: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] = + cross match { + case None => artifacts + case Some(is) => substituteCrossA(artifacts, cross) + } + + def applyCross(s: String, fopt: Option[String => String]): String = + fopt match { + case None => s + case Some(fopt) => fopt(s) + } + + def crossName(name: String, cross: String): String = + name + "_" + cross + def substituteCross(a: Artifact, cross: Option[String => String]): Artifact = + a.copy(name = applyCross(a.name, cross)) + def substituteCrossA(as: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] = + as.map(art => substituteCross(art, cross)) + + def apply(scalaFullVersion: String, scalaBinaryVersion: String): ModuleID => ModuleID = m => + { + val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion) + if(cross.isDefined) + m.copy(name = applyCross(m.name, cross), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross)) + else + m + } + + def isStable(v: String): Boolean = !v.contains("-") + def selectVersion(full: String, binary: String): String = if(isStable(full)) binary else full + + val PartialVersion = """(\d+)\.(\d+)(?:\..+)?""".r + def partialVersion(s: String): Option[(Int,Int)] = + s match { + case PartialVersion(major, minor) => Some(major.toInt, minor.toInt) + case _ => None + } + private[this] def isNewer(major: Int, minor: Int, minMajor: Int, minMinor: Int): Boolean = + major > minMajor || (major == minMajor && minor >= minMinor) + + def binaryScalaVersion(full: String): String = binaryVersion(full, TransitionScalaVersion) + def binarySbtVersion(full: String): String = binaryVersion(full, TransitionSbtVersion) + def binaryVersion(full: String, cutoff: String): String = + { + def sub(major: Int, minor: Int) = major + "." + minor + (partialVersion(full), partialVersion(cutoff)) match { + case (Some((major, minor)), None) => sub(major, minor) + case (Some((major, minor)), Some((minMajor, minMinor))) if isNewer(major, minor, minMajor, minMinor) => sub(major, minor) + case _ => full + } + } +} + diff --git a/ivy/DependencyBuilders.scala b/ivy/DependencyBuilders.scala index b878f206c..7d5812aaf 100755 --- a/ivy/DependencyBuilders.scala +++ b/ivy/DependencyBuilders.scala @@ -27,21 +27,28 @@ trait DependencyBuilders final class GroupID private[sbt] (groupID: String) { - def % (artifactID: String) = groupArtifact(artifactID, None) - def %% (artifactID: String, crossVersion: String => String = identity) = groupArtifact(artifactID, Some(crossVersion)) - def %% (artifactID: String, alternatives: (String, String)*) = groupArtifact(artifactID, Some(Map(alternatives: _*) orElse { case s => s })) - private def groupArtifact(artifactID: String, cross: Option[String => String]) = + def % (artifactID: String) = groupArtifact(artifactID, CrossVersion.Disabled) + def %% (artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary) + + @deprecated(deprecationMessage, "0.12.0") + def %% (artifactID: String, crossVersion: String => String) = groupArtifact(artifactID, CrossVersion.binaryMapped(crossVersion)) + @deprecated(deprecationMessage, "0.12.0") + def %% (artifactID: String, alternatives: (String, String)*) = groupArtifact(artifactID, CrossVersion.binaryMapped(Map(alternatives: _*) orElse { case s => s })) + + private def groupArtifact(artifactID: String, cross: CrossVersion) = { nonEmpty(artifactID, "Artifact ID") new GroupArtifactID(groupID, artifactID, cross) } + + private[this] def deprecationMessage = """Use the cross method on the constructed ModuleID. For example: ("a" % "b" % "1").cross(...)""" } -final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: Option[String => String]) +final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: CrossVersion) { def % (revision: String): ModuleID = { nonEmpty(revision, "Revision") - ModuleID(groupID, artifactID, revision).cross(!crossVersion.isEmpty, crossVersion.getOrElse(identity)) + ModuleID(groupID, artifactID, revision).cross(crossVersion) } } final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID) diff --git a/ivy/Ivy.scala b/ivy/Ivy.scala index 19252fb28..400490086 100644 --- a/ivy/Ivy.scala +++ b/ivy/Ivy.scala @@ -299,24 +299,19 @@ private object IvySbt } private def substituteCross(m: ModuleSettings): ModuleSettings = - m.ivyScala match { case None => m; case Some(is) => substituteCross(m, is.substituteCross) } - private def substituteCross(m: ModuleSettings, sub: ModuleID => ModuleID): ModuleSettings = + m.ivyScala match { + case None => m + case Some(is) => substituteCross(m, is.scalaFullVersion, is.scalaBinaryVersion) + } + private def substituteCross(m: ModuleSettings, scalaFullVersion: String, scalaBinaryVersion: String): ModuleSettings = + { + val sub = CrossVersion(scalaFullVersion, scalaBinaryVersion) m match { case ec: EmptyConfiguration => ec.copy(module = sub(ec.module)) case ic: InlineConfiguration => ic.copy(module = sub(ic.module), dependencies = ic.dependencies map sub) case _ => m } - def crossName(name: String, cross: String): String = - name + "_" + cross - def substituteCross(a: Artifact, cross: String): Artifact = - a.copy(name = crossName(a.name, cross)) - def substituteCrossA(as: Seq[Artifact], cross: String): Seq[Artifact] = - as.map(art => substituteCross(art, cross)) - def substituteCross(m: ModuleID, cross: String): ModuleID = - if(m.crossVersion) - m.copy(name = crossName(m.name, m.crossVersionRemap(cross)), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross)) - else - m + } private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, configurations: Iterable[String]): MDArtifact = { diff --git a/ivy/IvyActions.scala b/ivy/IvyActions.scala index 1cabd0a31..059d48997 100644 --- a/ivy/IvyActions.scala +++ b/ivy/IvyActions.scala @@ -88,8 +88,8 @@ object IvyActions val resolver = ivy.getSettings.getResolver(resolverName) if(resolver eq null) error("Undefined resolver '" + resolverName + "'") val ivyArtifact = ivyFile map { file => (MDArtifact.newIvyArtifact(md), file) } - val is = crossIvyScala(module.moduleSettings) - val as = mapArtifacts(md, is, artifacts) ++ ivyArtifact.toList + val cross = crossVersionMap(module.moduleSettings) + val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = true) } } } @@ -102,18 +102,16 @@ object IvyActions try { act } finally { resolver.setChecksums(previous mkString ",") } } - private def crossIvyScala(moduleSettings: ModuleSettings): Option[IvyScala] = + private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] = moduleSettings match { - case i: InlineConfiguration if i.module.crossVersion => i.ivyScala - case e: EmptyConfiguration if e.module.crossVersion => e.ivyScala + case i: InlineConfiguration => CrossVersion(i.module, i.ivyScala) + case e: EmptyConfiguration => CrossVersion(e.module, e.ivyScala) case _ => None } - def substituteCross(ivyScala: Option[IvyScala], artifacts: Seq[Artifact]): Seq[Artifact] = - ivyScala match { case None => artifacts; case Some(is) => IvySbt.substituteCrossA(artifacts, is.scalaVersion) } - def mapArtifacts(module: ModuleDescriptor, ivyScala: Option[IvyScala], artifacts: Map[Artifact, File]): Seq[(IArtifact, File)] = + def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Seq[(IArtifact, File)] = { val rawa = artifacts.keys.toSeq - val seqa = substituteCross(ivyScala, rawa) + val seqa = CrossVersion.substituteCross(rawa, cross) val zipped = rawa zip IvySbt.mapArtifacts(module, seqa) zipped map { case (a, ivyA) => (ivyA, artifacts(a)) } } @@ -199,7 +197,7 @@ object IvyActions report.allMissing flatMap { case (_, mod, art) => art.classifier.map { c => (restrictedCopy(mod, false), c) } } groupBy(_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) } private[this] def restrictedCopy(m: ModuleID, confs: Boolean) = - ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, crossVersionRemap = m.crossVersionRemap, extraAttributes = m.extraAttributes, configurations = if(confs) m.configurations else None) + ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, extraAttributes = m.extraAttributes, configurations = if(confs) m.configurations else None) private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): (ResolveReport, Option[ResolveException]) = { val resolveOptions = new ResolveOptions diff --git a/ivy/IvyInterface.scala b/ivy/IvyInterface.scala index 8d921c2ec..d5ffc4d6a 100644 --- a/ivy/IvyInterface.scala +++ b/ivy/IvyInterface.scala @@ -9,14 +9,21 @@ import scala.xml.NodeSeq import org.apache.ivy.plugins.resolver.{DependencyResolver, IBiblioResolver} import org.apache.ivy.util.url.CredentialsStore -final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String,String] = Map.empty, crossVersion: Boolean = false, crossVersionRemap: String => String = identity) +final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String,String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled) { override def toString = organization + ":" + name + ":" + revision + (configurations match { case Some(s) => ":" + s; case None => "" }) + (if(extraAttributes.isEmpty) "" else " " + extraString) def extraString = extraAttributes.map { case (k,v) => k + "=" + v } mkString("(",", ",")") - def cross(v: Boolean, verRemap: String => String = identity) = copy(crossVersion = v, crossVersionRemap = verRemap) + + @deprecated("Use the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0") + def cross(v: Boolean): ModuleID = cross(if(v) CrossVersion.binary else CrossVersion.Disabled) + @deprecated("Use the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0") + def cross(v: Boolean, verRemap: String => String): ModuleID = cross(if(v) CrossVersion.binaryMapped(verRemap) else CrossVersion.Disabled) + + def cross(v: CrossVersion): ModuleID = copy(crossVersion = v) + // () required for chaining def notTransitive() = intransitive() def intransitive() = copy(isTransitive = false) @@ -418,14 +425,14 @@ object Artifact val base = if(i >= 0) name.substring(0, i) else name Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Nil, Some(file.toURI.toURL)) } - def artifactName(scalaVersion: String, module: ModuleID, artifact: Artifact): String = + def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String = { import artifact._ val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c } - val base = if(module.crossVersion) IvySbt.crossName(artifact.name, module.crossVersionRemap(scalaVersion)) else artifact.name + val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary) + val base = CrossVersion.applyCross(artifact.name, cross) base + "-" + module.revision + classifierStr + "." + artifact.extension } - def cross(enable: Boolean, scalaVersion: String): String = if(enable) "_" + scalaVersion else "" val classifierConfMap = Map(SourceClassifier -> Sources, DocClassifier -> Docs) val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType) diff --git a/ivy/IvyScala.scala b/ivy/IvyScala.scala index 54f95ccf6..647df693f 100644 --- a/ivy/IvyScala.scala +++ b/ivy/IvyScala.scala @@ -26,7 +26,7 @@ object SbtArtifacts import ScalaArtifacts._ -final case class IvyScala(scalaVersion: String, configurations: Iterable[Configuration], checkExplicit: Boolean, filterImplicit: Boolean, overrideScalaVersion: Boolean, substituteCross: ModuleID => ModuleID) +final case class IvyScala(scalaFullVersion: String, scalaBinaryVersion: String, configurations: Iterable[Configuration], checkExplicit: Boolean, filterImplicit: Boolean, overrideScalaVersion: Boolean) private object IvyScala { @@ -34,11 +34,11 @@ private object IvyScala def checkModule(module: DefaultModuleDescriptor, conf: String)(check: IvyScala) { if(check.checkExplicit) - checkDependencies(module, check.scalaVersion, check.configurations) + checkDependencies(module, check.scalaBinaryVersion, check.configurations) if(check.filterImplicit) excludeScalaJars(module, check.configurations) if(check.overrideScalaVersion) - overrideScalaVersion(module, check.scalaVersion) + overrideScalaVersion(module, check.scalaFullVersion) } def overrideScalaVersion(module: DefaultModuleDescriptor, version: String) { @@ -54,14 +54,15 @@ private object IvyScala /** Checks the immediate dependencies of module for dependencies on scala jars and verifies that the version on the * dependencies matches scalaVersion. */ - private def checkDependencies(module: ModuleDescriptor, scalaVersion: String, configurations: Iterable[Configuration]) + private def checkDependencies(module: ModuleDescriptor, scalaBinaryVersion: String, configurations: Iterable[Configuration]) { val configSet = if(configurations.isEmpty) (c: String) => true else configurationSet(configurations) for(dep <- module.getDependencies.toList) { val id = dep.getDependencyRevisionId - if(id.getOrganisation == Organization && id.getRevision != scalaVersion && dep.getModuleConfigurations.exists(configSet)) - error("Version specified for dependency " + id + " differs from Scala version in project (" + scalaVersion + ").") + val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision) + if(id.getOrganisation == Organization && depBinaryVersion != scalaBinaryVersion && dep.getModuleConfigurations.exists(configSet)) + error("Binary version for dependency " + id + " (" + depBinaryVersion + ") differs from Scala binary version in project (" + scalaBinaryVersion + ").") } } private def configurationSet(configurations: Iterable[Configuration]) = configurations.map(_.toString).toSet diff --git a/main/Defaults.scala b/main/Defaults.scala index 99e51b8ba..720928af6 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -10,6 +10,7 @@ package sbt import Load.LoadedBuild import Artifact.{DocClassifier, SourceClassifier} import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test} + import CrossVersion.{binarySbtVersion, binaryScalaVersion, isStable, selectVersion} import complete._ import std.TaskExtra._ import inc.{FileValueCache, Locate} @@ -48,16 +49,16 @@ object Defaults extends BuildCommon def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq( managedDirectory <<= baseDirectory(_ / "lib_managed") - )) def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(Seq( + crossVersion :== CrossVersion.Disabled, buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies, taskTemporaryDirectory := IO.createTemporaryDirectory, onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) }, concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions, parallelExecution :== true, sbtVersion <<= appConfiguration { _.provider.id.version }, - sbtBinaryVersion <<= sbtVersion(v => binaryVersion(v, "0.12")), + sbtBinaryVersion <<= sbtVersion apply binarySbtVersion, sbtResolver <<= sbtVersion { sbtV => if(sbtV endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeResolver }, pollInterval :== 500, logBuffered :== false, @@ -190,7 +191,13 @@ object Defaults extends BuildCommon scalacOptions in GlobalScope :== Nil, scalaInstance <<= scalaInstanceSetting, scalaVersion in GlobalScope <<= appConfiguration( _.provider.scalaProvider.version), - scalaBinaryVersion <<= scalaVersion(v => binaryVersion(v, "2.10")), + scalaBinaryVersion in GlobalScope <<= scalaVersion apply binaryScalaVersion, + crossVersion <<= (crossPaths, scalaVersion) { (enabled, sv) => + if(enabled) + if(isStable(sv)) CrossVersion.binary else CrossVersion.full + else + CrossVersion.Disabled + }, crossScalaVersions in GlobalScope <<= Seq(scalaVersion).join, crossTarget <<= (target, scalaBinaryVersion, sbtBinaryVersion, sbtPlugin, crossPaths)(makeCrossTarget) ) @@ -379,7 +386,10 @@ object Defaults extends BuildCommon def collectFiles(dirs: ScopedTaskable[Seq[File]], filter: ScopedTaskable[FileFilter], excludes: ScopedTaskable[FileFilter]): Initialize[Task[Seq[File]]] = (dirs, filter, excludes) map { (d,f,excl) => d.descendantsExcept(f,excl).get } - def artifactPathSetting(art: SettingKey[Artifact]) = (crossTarget, projectID, art, scalaBinaryVersion in artifactName, artifactName) { (t, module, a, sv, toString) => t / toString(sv, module, a) asFile } + def artifactPathSetting(art: SettingKey[Artifact]) = (crossTarget, projectID, art, scalaVersion in artifactName, scalaBinaryVersion in artifactName, artifactName) { + (t, module, a, sv, sbv, toString) => + t / toString(ScalaVersion(sv, sbv), module, a) asFile + } def artifactSetting = ((artifact, artifactClassifier).identity zipWith configuration.?) { case ((a,classifier),cOpt) => val cPart = cOpt flatMap { c => if(c == Compile) None else Some(c.name) } val combined = cPart.toList ++ classifier.toList @@ -511,7 +521,8 @@ object Defaults extends BuildCommon }) } - def sbtPluginExtra(m: ModuleID, sbtV: String, scalaV: String): ModuleID = m.extra(CustomPomParser.SbtVersionKey -> sbtV, CustomPomParser.ScalaVersionKey -> scalaV).copy(crossVersion = false) + def sbtPluginExtra(m: ModuleID, sbtV: String, scalaV: String): ModuleID = + m.extra(CustomPomParser.SbtVersionKey -> sbtV, CustomPomParser.ScalaVersionKey -> scalaV).copy(crossVersion = CrossVersion.Disabled) def writePluginsDescriptor(plugins: Set[String], dir: File): Seq[File] = { val descriptor: File = dir / "sbt" / "sbt.plugins" @@ -597,25 +608,6 @@ object Defaults extends BuildCommon (if(aggregate) p.aggregate else Nil) } - val PartialVersion = """(\d+)\.(\d+)(?:\..+)?""".r - def partialVersion(s: String): Option[(Int,Int)] = - s match { - case PartialVersion(major, minor) => Some(major.toInt, minor.toInt) - case _ => None - } - private[this] def isNewer(major: Int, minor: Int, minMajor: Int, minMinor: Int): Boolean = - major > minMajor || (major == minMajor && minor >= minMinor) - - def binaryVersion(full: String, cutoff: String): String = - { - def sub(major: Int, minor: Int) = major + "." + minor - (partialVersion(full), partialVersion(cutoff)) match { - case (Some((major, minor)), None) => sub(major, minor) - case (Some((major, minor)), Some((minMajor, minMinor))) if isNewer(major, minor, minMajor, minMinor) => sub(major, minor) - case _ => full - } - } - val CompletionsID = "completions" def noAggregation: Seq[Scoped] = Seq(run, console, consoleQuick, consoleProject) @@ -744,16 +736,16 @@ object Classpaths ivyLoggingLevel in GlobalScope :== UpdateLogging.DownloadOnly, ivyXML in GlobalScope :== NodeSeq.Empty, ivyValidate in GlobalScope :== false, - ivyScala <<= ivyScala or (scalaHome, scalaVersion, scalaBinaryVersion in update) { (sh,v,vu) => - Some(new IvyScala(v, Nil, filterImplicit = true, checkExplicit = true, overrideScalaVersion = sh.isEmpty, substituteCross = x => IvySbt.substituteCross(x, vu))) + ivyScala <<= ivyScala or (scalaHome, scalaVersion in update, scalaBinaryVersion in update) { (sh,fv,bv) => + Some(new IvyScala(fv, bv, Nil, filterImplicit = true, checkExplicit = true, overrideScalaVersion = sh.isEmpty)) }, moduleConfigurations in GlobalScope :== Nil, publishTo in GlobalScope :== None, artifactPath in makePom <<= artifactPathSetting(artifact in makePom), publishArtifact in makePom <<= publishMavenStyle, artifact in makePom <<= moduleName(Artifact.pom), - projectID <<= (organization,moduleName,version,artifacts,crossPaths){ (org,module,version,as,crossEnabled) => - ModuleID(org, module, version).cross(crossEnabled).artifacts(as : _*) + projectID <<= (organization,moduleName,version,artifacts,crossVersion in projectID){ (org,module,version,as,cross) => + ModuleID(org, module, version).cross(cross).artifacts(as : _*) }, projectID <<= pluginProjectID, resolvers in GlobalScope :== Nil, @@ -797,12 +789,19 @@ object Classpaths } tag(Tags.Update, Tags.Network), sbtDependency in GlobalScope <<= appConfiguration { app => val id = app.provider.id - val base = ModuleID(id.groupID, id.name, id.version, crossVersion = id.crossVersioned) - IvySbt.substituteCross(base, app.provider.scalaProvider.version).copy(crossVersion = false) + val scalaVersion = app.provider.scalaProvider.version + val binVersion = binaryScalaVersion(scalaVersion) + val cross = if(id.crossVersioned) if(isStable(scalaVersion)) CrossVersion.binary else CrossVersion.full else CrossVersion.Disabled + val base = ModuleID(id.groupID, id.name, id.version, crossVersion = cross) + CrossVersion(scalaVersion, binVersion)(base).copy(crossVersion = CrossVersion.Disabled) } ) - def pluginProjectID: Initialize[ModuleID] = (sbtBinaryVersion in update, scalaBinaryVersion in update, projectID, sbtPlugin) { (sbtV, scalaV, pid, isPlugin) => - if(isPlugin) sbtPluginExtra(pid, sbtV, scalaV) else pid + def pluginProjectID: Initialize[ModuleID] = (sbtVersion in update, sbtBinaryVersion in update, scalaVersion in update, scalaBinaryVersion in update, projectID, sbtPlugin) { + (sbtV, sbtBV, scalaV, scalaBV, pid, isPlugin) => + if(isPlugin) + sbtPluginExtra(pid, selectVersion(sbtV, sbtBV), selectVersion(scalaV, scalaBV)) + else + pid } def ivySbt0: Initialize[Task[IvySbt]] = (ivyConfiguration, credentials, streams) map { (conf, creds, s) => diff --git a/main/IvyConsole.scala b/main/IvyConsole.scala index d974c82fe..9cdf09725 100644 --- a/main/IvyConsole.scala +++ b/main/IvyConsole.scala @@ -56,7 +56,9 @@ object IvyConsole def parseManaged(arg: String, log: Logger): Seq[ModuleID] = arg match { - case DepPattern(group, cross, name, version) => ModuleID(group.trim, name.trim, version.trim, crossVersion = !cross.trim.isEmpty) :: Nil + case DepPattern(group, cross, name, version) => + val crossV = if(cross.trim.isEmpty) CrossVersion.Disabled else CrossVersion.binary + ModuleID(group.trim, name.trim, version.trim, crossVersion = crossV) :: Nil case _ => log.warn("Ignoring invalid argument '" + arg + "'"); Nil } } diff --git a/main/Keys.scala b/main/Keys.scala index c3e767ab9..ae875d36b 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -138,6 +138,7 @@ object Keys val scalaVersion = SettingKey[String]("scala-version", "The version of Scala used for building.") val scalaBinaryVersion = SettingKey[String]("scala-binary-version", "The Scala version substring describing binary compatibility.") val crossScalaVersions = SettingKey[Seq[String]]("cross-scala-versions", "The versions of Scala used when cross-building.") + val crossVersion = SettingKey[CrossVersion]("cross-version", "Configures handling of the Scala version when cross-building.") val classpathOptions = SettingKey[ClasspathOptions]("classpath-options", "Configures handling of Scala classpaths.") val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins", "The set of names of Plugin implementations defined by this project.") val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.") @@ -165,7 +166,7 @@ object Keys val artifactPath = SettingKey[File]("artifact-path", "The location of a generated artifact.") val artifact = SettingKey[Artifact]("artifact", "Describes an artifact.") val artifactClassifier = SettingKey[Option[String]]("artifact-classifier", "Sets the classifier used by the default artifact definition.") - val artifactName = SettingKey[(String, ModuleID, Artifact) => String]("artifact-name", "Function that produces the artifact name from its definition.") + val artifactName = SettingKey[(ScalaVersion, ModuleID, Artifact) => String]("artifact-name", "Function that produces the artifact name from its definition.") val mappings = TaskKey[Seq[(File,String)]]("mappings", "Defines the mappings from a file to a path, used by packaging, for example.") val fileMappings = TaskKey[Seq[(File,File)]]("file-mappings", "Defines the mappings from a file to a file, used for copying files, for example.") diff --git a/main/actions/CacheIvy.scala b/main/actions/CacheIvy.scala index 528bd7e1b..3a5c74b89 100644 --- a/main/actions/CacheIvy.scala +++ b/main/actions/CacheIvy.scala @@ -8,7 +8,7 @@ package sbt import FileInfo.{exists, hash} import java.io.File import java.net.URL - import Types.:+: + import Types.{:+:, idFun} import scala.xml.NodeSeq import sbinary.{DefaultProtocol,Format} import DefaultProtocol.{immutableMapFormat, immutableSetFormat, optionsAreFormat} @@ -80,8 +80,19 @@ object CacheIvy ) implicit def exclusionRuleFormat(implicit sf: Format[String]): Format[ExclusionRule] = wrap[ExclusionRule, (String, String, String, Seq[String])]( e => (e.organization, e.name, e.artifact, e.configurations), { case (o,n,a,cs) => ExclusionRule(o,n,a,cs) }) + + implicit def crossVersionFormat: Format[CrossVersion] = wrap(crossToInt, crossFromInt) + + private[this] final val DisabledValue = 0 + private[this] final val BinaryValue = 1 + private[this] final val FullValue = 2 + + import CrossVersion.{Binary, Disabled, Full} + private[this] val crossFromInt = (i: Int) => i match { case BinaryValue => new Binary(idFun); case FullValue => new Full(idFun); case _ => Disabled } + private[this] val crossToInt = (c: CrossVersion) => c match { case Disabled => 0; case b: Binary => BinaryValue; case f: Full => FullValue } + implicit def moduleIDFormat(implicit sf: Format[String], af: Format[Artifact], bf: Format[Boolean], ef: Format[ExclusionRule]): Format[ModuleID] = - wrap[ModuleID, ((String,String,String,Option[String]),(Boolean,Boolean,Seq[Artifact],Seq[ExclusionRule],Map[String,String],Boolean))]( + wrap[ModuleID, ((String,String,String,Option[String]),(Boolean,Boolean,Seq[Artifact],Seq[ExclusionRule],Map[String,String],CrossVersion))]( m => ((m.organization,m.name,m.revision,m.configurations), (m.isChanging, m.isTransitive, m.explicitArtifacts, m.exclusions, m.extraAttributes, m.crossVersion)), { case ((o,n,r,cs),(ch,t,as,excl,x,cv)) => ModuleID(o,n,r,cs,ch,t,as,excl,x,cv) } ) @@ -144,6 +155,7 @@ object CacheIvy implicit def artifactToHL = (a: Artifact) => a.name :+: a.`type` :+: a.extension :+: a.classifier :+: names(a.configurations) :+: a.url :+: a.extraAttributes :+: HNil implicit def exclusionToHL = (e: ExclusionRule) => e.organization :+: e.name :+: e.artifact :+: e.configurations :+: HNil + implicit def crossToHL = (c: CrossVersion) => crossToInt(c) :+: HNil /* implicit def deliverConfToHL = (p: DeliverConfiguration) => p.deliverIvyPattern :+: p.status :+: p.configurations :+: HNil implicit def publishConfToHL = (p: PublishConfiguration) => p.ivyFile :+: p.resolverName :+: p.artifacts :+: HNil*/ @@ -156,13 +168,14 @@ object CacheIvy implicit def connectionIC: InputCache[SshConnection] = wrapIn implicit def artifactIC: InputCache[Artifact] = wrapIn implicit def exclusionIC: InputCache[ExclusionRule] = wrapIn + implicit def crossVersionIC: InputCache[CrossVersion] = wrapIn /* implicit def publishConfIC: InputCache[PublishConfiguration] = wrapIn implicit def deliverConfIC: InputCache[DeliverConfiguration] = wrapIn*/ object L1 { implicit def retrieveToHL = (r: RetrieveConfiguration) => exists(r.retrieveDirectory) :+: r.outputPattern :+: HNil implicit def ivyPathsToHL = (p: IvyPaths) => exists(p.baseDirectory) :+: p.ivyHome.map(exists.apply) :+: HNil - implicit def ivyScalaHL = (i: IvyScala) => i.scalaVersion :+: names(i.configurations) :+: i.checkExplicit :+: i.filterImplicit :+: HNil + implicit def ivyScalaHL = (i: IvyScala) => i.scalaFullVersion :+: i.scalaBinaryVersion :+: names(i.configurations) :+: i.checkExplicit :+: i.filterImplicit :+: HNil implicit def configurationToHL = (c: Configuration) => c.name :+: c.description :+: c.isPublic :+: names(c.extendsConfigs) :+: c.transitive :+: HNil implicit def passwordToHL = (s: PasswordAuthentication) => Hash(s.user) :+: password(s.password) :+: HNil diff --git a/sbt/src/sbt-test/dependency-management/info/project/InfoTest.scala b/sbt/src/sbt-test/dependency-management/info/project/InfoTest.scala index e491e3ea0..a3562c68c 100644 --- a/sbt/src/sbt-test/dependency-management/info/project/InfoTest.scala +++ b/sbt/src/sbt-test/dependency-management/info/project/InfoTest.scala @@ -7,6 +7,7 @@ object InfoTest extends Build lazy val root = Project("root", file(".")) settings( ivyPaths <<= (baseDirectory, target)( (dir, t) => new IvyPaths(dir, Some(t / "ivy-cache"))), ivyXML <<= (customInfo, organization, moduleName, version) apply inlineXML, + scalaVersion := "2.9.0", projectID ~= (_ cross false), customInfo <<= baseDirectory{_ / "info" exists }, TaskKey[Unit]("check-download") <<= checkDownload, @@ -24,9 +25,9 @@ object InfoTest extends Build ScalaQuery is a type-safe database query API for Scala. - ) + ) else - + def checkDownload = (dependencyClasspath in Compile) map { cp => if(cp.isEmpty) error("Dependency not downloaded"); () } def checkInfo = (customInfo, delivered) map { (addInfo, d) => diff --git a/sbt/src/sbt-test/dependency-management/inline-dependencies-a/build.sbt b/sbt/src/sbt-test/dependency-management/inline-dependencies-a/build.sbt index 32c57329e..c07e5707e 100644 --- a/sbt/src/sbt-test/dependency-management/inline-dependencies-a/build.sbt +++ b/sbt/src/sbt-test/dependency-management/inline-dependencies-a/build.sbt @@ -1,3 +1,5 @@ +resolvers += ScalaToolsReleases + libraryDependencies += "org.scalacheck" % "scalacheck" % "1.5" ivyPaths <<= baseDirectory( dir => new IvyPaths(dir, Some(dir / "ivy-home"))) @@ -7,4 +9,4 @@ TaskKey[Unit]("check") <<= update map { report => assert(!files.isEmpty, "ScalaCheck module not found in update report") val missing = files.filter(! _.exists) assert(missing.isEmpty, "Reported ScalaCheck artifact files don't exist: " + missing.mkString(", ")) -} \ No newline at end of file +} diff --git a/sbt/src/sbt-test/dependency-management/inline-dependencies-a/project/build.properties b/sbt/src/sbt-test/dependency-management/inline-dependencies-a/project/build.properties deleted file mode 100644 index 2a3934bd8..000000000 --- a/sbt/src/sbt-test/dependency-management/inline-dependencies-a/project/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Project properties -#Fri Jan 30 20:49:57 EST 2009 -project.name=Inline Dependency Test A -project.version=1.0 diff --git a/sbt/src/sbt-test/dependency-management/inline-dependencies-a/project/build/src/UpdateTestProject.scala b/sbt/src/sbt-test/dependency-management/inline-dependencies-a/project/build/src/UpdateTestProject.scala deleted file mode 100644 index 8f7323f9e..000000000 --- a/sbt/src/sbt-test/dependency-management/inline-dependencies-a/project/build/src/UpdateTestProject.scala +++ /dev/null @@ -1,8 +0,0 @@ -import sbt._ - -class UpdateTestProject(info: ProjectInfo) extends DefaultProject(info) -{ - val sc = "org.scalacheck" % "scalacheck" % "1.5" - override def ivyCacheDirectory = Some(outputPath / "ivy-cache") - override def disableCrossPaths = true -} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/make-pom/project/MakePomTest.scala b/sbt/src/sbt-test/dependency-management/make-pom/project/MakePomTest.scala index df2fe56e4..60f39d2f0 100644 --- a/sbt/src/sbt-test/dependency-management/make-pom/project/MakePomTest.scala +++ b/sbt/src/sbt-test/dependency-management/make-pom/project/MakePomTest.scala @@ -5,6 +5,7 @@ object MakePomTest extends Build { lazy val root = Project("root", file(".")) settings( + resolvers += ScalaToolsReleases, readPom <<= makePom map XML.loadFile, TaskKey[Unit]("check-pom") <<= checkPom, TaskKey[Unit]("check-extra") <<= checkExtra, diff --git a/sbt/src/sbt-test/dependency-management/module-confs/Test.sbt b/sbt/src/sbt-test/dependency-management/module-confs/Test.sbt index 6915c14a5..1a5aca7db 100644 --- a/sbt/src/sbt-test/dependency-management/module-confs/Test.sbt +++ b/sbt/src/sbt-test/dependency-management/module-confs/Test.sbt @@ -4,6 +4,6 @@ moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots) } -libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-165" +libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-256" resolvers := Nil \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongOrg.sbt b/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongOrg.sbt index 887396f7d..6c9395ba8 100644 --- a/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongOrg.sbt +++ b/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongOrg.sbt @@ -4,6 +4,6 @@ moduleConfigurations += ModuleConfiguration("org.not-scala-lang", "*", "2.10.0-.*", scalaSnapshots) } -libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-165" +libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-256" resolvers := Nil \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongPattern.sbt b/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongPattern.sbt index 10bb7b25d..488cafab1 100644 --- a/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongPattern.sbt +++ b/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongPattern.sbt @@ -4,6 +4,6 @@ moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots) } -libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-165" +libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-256" resolvers := Nil \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongVersion.sbt b/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongVersion.sbt index f9946aa8e..ee1d7ed86 100644 --- a/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongVersion.sbt +++ b/sbt/src/sbt-test/dependency-management/module-confs/changes/WrongVersion.sbt @@ -4,6 +4,6 @@ moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots) } -libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-164" +libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-255" resolvers := Nil \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/parent-publish/project/Parent.scala b/sbt/src/sbt-test/dependency-management/parent-publish/project/Parent.scala index bf204ab00..9dd7af242 100644 --- a/sbt/src/sbt-test/dependency-management/parent-publish/project/Parent.scala +++ b/sbt/src/sbt-test/dependency-management/parent-publish/project/Parent.scala @@ -3,7 +3,7 @@ object ParentTest extends Build { lazy val parent: Project = Project("Flowmodel", file(".")) aggregate(core, reporters) - lazy val core: Project = Project("Flowmodel core", file("core"), delegates = parent :: Nil) - lazy val reporters: Project = Project("Extra reporters", file("reporters"), delegates = parent :: Nil) aggregate(jfreechart) dependsOn(jfreechart) - lazy val jfreechart: Project = Project("JFreeChart reporters", file("jfreechart")/*, delegates = reporters :: Nil*/) dependsOn(core) + lazy val core: Project = Project("Flowmodel-core", file("core"), delegates = parent :: Nil) + lazy val reporters: Project = Project("Extra-reporters", file("reporters"), delegates = parent :: Nil) aggregate(jfreechart) dependsOn(jfreechart) + lazy val jfreechart: Project = Project("JFreeChart-reporters", file("jfreechart")/*, delegates = reporters :: Nil*/) dependsOn(core) } diff --git a/sbt/src/sbt-test/dependency-management/pom-advanced/project/PomRepoTest.scala b/sbt/src/sbt-test/dependency-management/pom-advanced/project/PomRepoTest.scala index 9bb920406..7f70d4007 100644 --- a/sbt/src/sbt-test/dependency-management/pom-advanced/project/PomRepoTest.scala +++ b/sbt/src/sbt-test/dependency-management/pom-advanced/project/PomRepoTest.scala @@ -5,7 +5,7 @@ object PomRepoTest extends Build { lazy val root = Project("root", file(".")) settings( - resolvers ++= Seq(local, ScalaToolsSnapshots), + resolvers ++= Seq(local, ScalaToolsReleases, ScalaToolsSnapshots), InputKey[Unit]("check-pom") <<= InputTask(_ => spaceDelimited("")) { result => (makePom, result, streams) map checkPomRepositories }, makePomConfiguration <<= (makePomConfiguration, baseDirectory) { (conf, base) => conf.copy(filterRepositories = pomIncludeRepository(base, conf.filterRepositories) ) diff --git a/sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala b/sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala index aa4d3a351..065d6fef6 100644 --- a/sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala +++ b/sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala @@ -2,15 +2,23 @@ import sbt._ import Keys._ object P extends Build { - override def settings = super.settings ++ Seq( scalaVersion in update := "2.9.0" ) + override def settings = super.settings ++ Seq( + scalaBinaryVersion in update := "2.9.0", + resolvers += ScalaToolsReleases + ) + + def configIvyScala = + ivyScala ~= { _.map(_.copy(checkExplicit = false)) } val declared = SettingKey[Boolean]("declared") lazy val a = Project("A", file("a")) settings( - libraryDependencies += "org.scala-tools.sbinary" %% "sbinary" % "0.4.0" % "provided" + libraryDependencies += "org.scala-tools.sbinary" %% "sbinary" % "0.4.0" % "provided", + configIvyScala ) lazy val b = Project("B", file("b")) dependsOn(a) settings( libraryDependencies <<= declared(d => if(d) Seq("org.scala-tools.sbinary" %% "sbinary" % "0.4.0" % "provided") else Nil), - declared <<= baseDirectory(_ / "declare.lib" exists) + declared <<= baseDirectory(_ / "declare.lib" exists), + configIvyScala ) -} \ No newline at end of file +} \ No newline at end of file diff --git a/sbt/src/sbt-test/project/transitive-plugins/project/Build.scala b/sbt/src/sbt-test/project/transitive-plugins/project/Build.scala index 5b0cf40e4..1c5482930 100644 --- a/sbt/src/sbt-test/project/transitive-plugins/project/Build.scala +++ b/sbt/src/sbt-test/project/transitive-plugins/project/Build.scala @@ -3,6 +3,10 @@ import Keys._ object Build extends Build { + override def settings = super.settings ++ Seq( + sbtBinaryVersion <<= sbtVersion + ) + lazy val root = Project("root", file(".")) aggregate(a,b,c) lazy val a = Project("a", file("a")) lazy val b = Project("b", file("b"))