diff --git a/compile/src/main/scala/sbt/compiler/CompilerArguments.scala b/compile/src/main/scala/sbt/compiler/CompilerArguments.scala index f7445dfef..7b2eab94f 100644 --- a/compile/src/main/scala/sbt/compiler/CompilerArguments.scala +++ b/compile/src/main/scala/sbt/compiler/CompilerArguments.scala @@ -36,7 +36,7 @@ final class CompilerArguments(scalaInstance: xsbti.compile.ScalaInstance, cp: xs val scalaHome = System.getProperty("scala.home") assert((scalaHome eq null) || scalaHome.isEmpty, "'scala.home' should not be set (was " + scalaHome + ")") } - def createBootClasspathFor(classpath: Seq[File]) = createBootClasspath(hasLibrary(classpath)) + def createBootClasspathFor(classpath: Seq[File]) = createBootClasspath(hasLibrary(classpath) || cp.compiler || cp.extra) /** Add the correct Scala library jar to the boot classpath if `addLibrary` is true.*/ def createBootClasspath(addLibrary: Boolean) = diff --git a/ivy/src/main/scala/sbt/Ivy.scala b/ivy/src/main/scala/sbt/Ivy.scala index 6f8ce9a64..ce985c95c 100644 --- a/ivy/src/main/scala/sbt/Ivy.scala +++ b/ivy/src/main/scala/sbt/Ivy.scala @@ -168,12 +168,13 @@ final class IvySbt(val configuration: IvyConfiguration) val md = PomModuleDescriptorParser.getInstance.parseDescriptor(settings, toURL(pc.file), pc.validate) val dmd = IvySbt.toDefaultModuleDescriptor(md) IvySbt.addConfigurations(dmd, Configurations.defaultInternal) - for( is <- pc.ivyScala) { - val confParser = new CustomXmlParser.CustomParser(settings, Some(Configurations.DefaultMavenConfiguration.name)) + val defaultConf = Configurations.DefaultMavenConfiguration.name + for( is <- pc.ivyScala) if(pc.autoScalaTools) { + val confParser = new CustomXmlParser.CustomParser(settings, Some(defaultConf)) confParser.setMd(dmd) addScalaToolDependencies(dmd, confParser, is) } - (dmd, "compile") + (dmd, defaultConf) } /** Parses the Ivy file 'ivyFile' from the given `IvyFileConfiguration`.*/ private def configureIvyFile(ifc: IvyFileConfiguration) = @@ -183,7 +184,7 @@ final class IvySbt(val configuration: IvyConfiguration) parser.setSource(toURL(ifc.file)) parser.parse() val dmd = IvySbt.toDefaultModuleDescriptor(parser.getModuleDescriptor()) - for( is <- ifc.ivyScala ) + for( is <- ifc.ivyScala ) if(ifc.autoScalaTools) addScalaToolDependencies(dmd, parser, is) (dmd, parser.getDefaultConf) } diff --git a/ivy/src/main/scala/sbt/IvyConfigurations.scala b/ivy/src/main/scala/sbt/IvyConfigurations.scala index 734c56b91..f46d24dbd 100644 --- a/ivy/src/main/scala/sbt/IvyConfigurations.scala +++ b/ivy/src/main/scala/sbt/IvyConfigurations.scala @@ -66,11 +66,11 @@ sealed trait ModuleSettings def ivyScala: Option[IvyScala] def noScala: ModuleSettings } -final case class IvyFileConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean) extends ModuleSettings +final case class IvyFileConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings { def noScala = copy(ivyScala = None) } -final case class PomConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean) extends ModuleSettings +final case class PomConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings { def noScala = copy(ivyScala = None) } @@ -107,12 +107,12 @@ object ModuleSettings log.debug("Autodetecting dependencies.") val defaultPOMFile = IvySbt.defaultPOM(baseDirectory) if(defaultPOMFile.canRead) - new PomConfiguration(defaultPOMFile, ivyScala, validate) + new PomConfiguration(defaultPOMFile, ivyScala, validate, true) else { val defaultIvy = IvySbt.defaultIvyFile(baseDirectory) if(defaultIvy.canRead) - new IvyFileConfiguration(defaultIvy, ivyScala, validate) + new IvyFileConfiguration(defaultIvy, ivyScala, validate, true) else { log.warn("No dependency configuration found, using defaults.") diff --git a/ivy/src/main/scala/sbt/IvyInterface.scala b/ivy/src/main/scala/sbt/IvyInterface.scala index 4496f3cae..6a7381831 100644 --- a/ivy/src/main/scala/sbt/IvyInterface.scala +++ b/ivy/src/main/scala/sbt/IvyInterface.scala @@ -347,7 +347,7 @@ object Configurations def default: Seq[Configuration] = defaultMavenConfigurations def defaultMavenConfigurations: Seq[Configuration] = Seq(Compile, Runtime, Test, Provided, Optional) def defaultInternal: Seq[Configuration] = Seq(CompileInternal, RuntimeInternal, TestInternal) - def auxiliary: Seq[Configuration] = Seq(Sources, Docs, Pom, ScalaTool) + def auxiliary: Seq[Configuration] = Seq(Sources, Docs, Pom) def names(cs: Seq[Configuration]) = cs.map(_.name) lazy val RuntimeInternal = optionalInternal(Runtime) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 34326b1f0..be54f2771 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -72,6 +72,7 @@ object Defaults extends BuildCommon cancelable :== false, sourcesInBase :== true, autoScalaLibrary :== true, + managedScalaInstance :== true, onLoad <<= onLoad ?? idFun[State], onUnload <<= (onUnload ?? idFun[State]), onUnload := { s => try onUnload.value(s) finally IO.delete(taskTemporaryDirectory.value) }, @@ -284,8 +285,20 @@ object Defaults extends BuildCommon scalaInstanceFromUpdate } } + private[this] def noToolConfiguration(autoInstance: Boolean): String = + { + val pre = "Missing Scala tool configuration from the 'update' report. " + val post = + if(autoInstance) + "'scala-tool' is normally added automatically, so this may indicate a bug in sbt or you may be removing it from ivyConfigurations, for example." + else + "Explicitly define scalaInstance or scalaHome or include Scala dependencies in the 'scala-tool' configuration." + pre + post + } + def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = Def.task { - val toolReport = update.value.configuration(Configurations.ScalaTool.name) getOrElse error("Missing Scala tool configuration.") + val toolReport = update.value.configuration(Configurations.ScalaTool.name) getOrElse + error(noToolConfiguration(managedScalaInstance.value)) def files(id: String) = for { m <- toolReport.modules if m.module.name == id; (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType } @@ -730,7 +743,7 @@ object Defaults extends BuildCommon lazy val baseClasspaths: Seq[Setting[_]] = Classpaths.publishSettings ++ Classpaths.baseSettings lazy val configSettings: Seq[Setting[_]] = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++ Classpaths.compilerPluginConfig - lazy val compileSettings: Seq[Setting[_]] = configSettings ++ (mainRunMainTask +: mainRunTask +: addBaseSources) + lazy val compileSettings: Seq[Setting[_]] = configSettings ++ (mainRunMainTask +: mainRunTask +: addBaseSources) ++ Classpaths.addUnmanagedLibrary lazy val testSettings: Seq[Setting[_]] = configSettings ++ testTasks lazy val itSettings: Seq[Setting[_]] = inConfig(IntegrationTest)(testSettings) @@ -846,11 +859,11 @@ object Classpaths projectDependencies <<= projectDependenciesTask, dependencyOverrides in GlobalScope :== Set.empty, libraryDependencies in GlobalScope :== Nil, - libraryDependencies ++= autoLibraryDependency(autoScalaLibrary.value, sbtPlugin.value, scalaOrganization.value, scalaVersion.value), + libraryDependencies ++= autoLibraryDependency(autoScalaLibrary.value && !scalaHome.value.isDefined && managedScalaInstance.value, sbtPlugin.value, scalaOrganization.value, scalaVersion.value), allDependencies := { val base = projectDependencies.value ++ libraryDependencies.value val pluginAdjust = if(sbtPlugin.value) sbtDependency.value.copy(configurations = Some(Provided.name)) +: base else base - if(scalaHome.value.isDefined || ivyScala.value.isEmpty) + if(scalaHome.value.isDefined || ivyScala.value.isEmpty || !managedScalaInstance.value) pluginAdjust else ScalaArtifacts.toolDependencies(scalaOrganization.value, scalaVersion.value) ++ pluginAdjust @@ -879,6 +892,7 @@ object Classpaths (confs ++ confs.map(internalConfigurationMap.value) ++ (if(autoCompilerPlugins.value) CompilerPlugin :: Nil else Nil)).distinct }, ivyConfigurations ++= Configurations.auxiliary, + ivyConfigurations ++= { if(managedScalaInstance.value && !scalaHome.value.isDefined) Configurations.ScalaTool :: Nil else Nil }, moduleSettings <<= moduleSettings0, makePomConfiguration := new MakePomConfiguration(artifactPath in makePom value, projectInfo.value, None, pomExtra.value, pomPostProcess.value, pomIncludeRepository.value, pomAllRepositories.value), deliverLocalConfiguration := deliverConfig(crossTarget.value, status = if (isSnapshot.value) "integration" else "release", logging = ivyLoggingLevel.value ), @@ -927,10 +941,9 @@ object Classpaths Credentials.register(creds, s.log) new IvySbt(conf) } - def moduleSettings0: Initialize[Task[ModuleSettings]] = - (projectID, allDependencies, dependencyOverrides, ivyXML, ivyConfigurations, defaultConfiguration, ivyScala, ivyValidate, projectInfo) map { - (pid, deps, over, ivyXML, confs, defaultConf, ivyS, validate, pinfo) => new InlineConfiguration(pid, pinfo, deps, over, ivyXML, confs, defaultConf, ivyS, validate) - } + def moduleSettings0: Initialize[Task[ModuleSettings]] = Def.task { + new InlineConfiguration(projectID.value, projectInfo.value, allDependencies.value, dependencyOverrides.value, ivyXML.value, ivyConfigurations.value, defaultConfiguration.value, ivyScala.value, ivyValidate.value) + } def sbtClassifiersTasks = inTask(updateSbtClassifiers)(Seq( transitiveClassifiers in GlobalScope in updateSbtClassifiers ~= ( _.filter(_ != DocClassifier) ), @@ -1201,6 +1214,16 @@ object Classpaths modifyForPlugin(plugin, ModuleID(org, ScalaArtifacts.LibraryID, version)) :: Nil else Nil + def addUnmanagedLibrary: Seq[Setting[_]] = Seq( + unmanagedJars in Compile <++= unmanagedScalaLibrary + ) + def unmanagedScalaLibrary: Initialize[Task[Seq[File]]] = + Def.taskDyn { + if(autoScalaLibrary.value && scalaHome.value.isDefined) + Def.task { scalaInstance.value.libraryJar :: Nil } + else + Def.task { Nil } + } import DependencyFilter._ def managedJars(config: Configuration, jarTypes: Set[String], up: UpdateReport): Classpath = @@ -1339,12 +1362,9 @@ trait BuildExtra extends BuildCommon } } def externalIvyFile(file: Initialize[File] = baseDirectory / "ivy.xml", iScala: Initialize[Option[IvyScala]] = ivyScala): Setting[Task[ModuleSettings]] = - external(file, iScala)( (f, is, v) => new IvyFileConfiguration(f, is, v) ) + moduleSettings := new IvyFileConfiguration(file.value, iScala.value, ivyValidate.value, managedScalaInstance.value) def externalPom(file: Initialize[File] = baseDirectory / "pom.xml", iScala: Initialize[Option[IvyScala]] = ivyScala): Setting[Task[ModuleSettings]] = - external(file, iScala)( (f, is, v) => new PomConfiguration(f, is, v) ) - - private[this] def external(file: Initialize[File], iScala: Initialize[Option[IvyScala]])(make: (File, Option[IvyScala], Boolean) => ModuleSettings): Setting[Task[ModuleSettings]] = - moduleSettings <<= ((file zip iScala) zipWith ivyValidate) { case ((f, is), v) => task { make(f, is, v) } } + moduleSettings := new PomConfiguration(file.value, ivyScala.value, ivyValidate.value, managedScalaInstance.value) def runInputTask(config: Configuration, mainClass: String, baseArguments: String*): Initialize[InputTask[Unit]] = inputTask { result => diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 7a3d7a09b..3fa491f18 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -309,6 +309,7 @@ object Keys val classifiersModule = TaskKey[GetClassifiersModule]("classifiers-module", rank = CTask) val conflictWarning = SettingKey[ConflictWarning]("conflict-warning", "Configures warnings for conflicts in dependency management.", CSetting) val autoScalaLibrary = SettingKey[Boolean]("auto-scala-library", "Adds a dependency on scala-library if true.", ASetting) + val managedScalaInstance = SettingKey[Boolean]("managed-scala-instance", "Automatically obtains Scala tools as managed dependencies if true.", BSetting) val sbtResolver = SettingKey[Resolver]("sbt-resolver", "Provides a resolver for obtaining sbt as a dependency.", BMinusSetting) val sbtDependency = SettingKey[ModuleID]("sbt-dependency", "Provides a definition for declaring the current version of sbt.", BMinusSetting) val sbtVersion = SettingKey[String]("sbt-version", "Provides the version of sbt. This setting should be not be modified.", AMinusSetting) diff --git a/sbt/src/sbt-test/dependency-management/ivy-settings-a/auto-instance.sbt b/sbt/src/sbt-test/dependency-management/ivy-settings-a/auto-instance.sbt new file mode 100644 index 000000000..dff729e11 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/ivy-settings-a/auto-instance.sbt @@ -0,0 +1 @@ +managedScalaInstance := false \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/ivy-settings-a/build.sbt b/sbt/src/sbt-test/dependency-management/ivy-settings-a/build.sbt index daa21c77d..7d398a91d 100644 --- a/sbt/src/sbt-test/dependency-management/ivy-settings-a/build.sbt +++ b/sbt/src/sbt-test/dependency-management/ivy-settings-a/build.sbt @@ -1,6 +1,6 @@ seq(externalIvySettings(), externalIvyFile()) -TaskKey[Unit]("check") <<= (baseDirectory, update) map { (base, report) => - val files = report.matching( moduleFilter(organization = "org.scalacheck", name = "scalacheck*", revision = "1.9") ) +TaskKey[Unit]("check") := { + val files = update.value.matching( moduleFilter(organization = "org.scalacheck", name = "scalacheck*", revision = "1.9") ) assert(!files.isEmpty, "ScalaCheck module not found in update report") } \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/ivy-settings-a/test b/sbt/src/sbt-test/dependency-management/ivy-settings-a/test index 87213b2d4..d7b5b2289 100644 --- a/sbt/src/sbt-test/dependency-management/ivy-settings-a/test +++ b/sbt/src/sbt-test/dependency-management/ivy-settings-a/test @@ -1,8 +1,11 @@ > update +# works because scalaVersion is the same as sbtScalaVersion +> compile +$ delete auto-instance.sbt $ copy-file changes/scalacheck-ivy.xml ivy.xml -> update $ copy-file changes/scala-tools-ivysettings.xml ivysettings.xml > check -> test:compile \ No newline at end of file +> test:compile diff --git a/sbt/src/sbt-test/dependency-management/sources/project/Test.scala b/sbt/src/sbt-test/dependency-management/sources/project/Test.scala index ce02ff1d6..d59a21d25 100644 --- a/sbt/src/sbt-test/dependency-management/sources/project/Test.scala +++ b/sbt/src/sbt-test/dependency-management/sources/project/Test.scala @@ -7,6 +7,7 @@ object Test extends Build libraryDependencies += "net.liftweb" % "lift-webkit" % "1.0" intransitive(), libraryDependencies += "org.scalacheck" % "scalacheck" % "1.5" intransitive(), autoScalaLibrary := false, + managedScalaInstance := false, transitiveClassifiers := Seq("sources"), TaskKey[Unit]("check-sources") <<= updateClassifiers map checkSources, TaskKey[Unit]("check-binaries") <<= update map checkBinaries diff --git a/sbt/src/sbt-test/java/no-scala-tool/A.java b/sbt/src/sbt-test/java/no-scala-tool/A.java new file mode 100644 index 000000000..c7167d0da --- /dev/null +++ b/sbt/src/sbt-test/java/no-scala-tool/A.java @@ -0,0 +1,3 @@ +public class A { + public static final int x = 3; +} diff --git a/sbt/src/sbt-test/java/no-scala-tool/build.sbt b/sbt/src/sbt-test/java/no-scala-tool/build.sbt new file mode 100644 index 000000000..eac0f36ca --- /dev/null +++ b/sbt/src/sbt-test/java/no-scala-tool/build.sbt @@ -0,0 +1,5 @@ +managedScalaInstance := false + +externalResolvers := Nil + +initialCommands := "println(A.x)" diff --git a/sbt/src/sbt-test/java/no-scala-tool/changes/explicitInstance.sbt b/sbt/src/sbt-test/java/no-scala-tool/changes/explicitInstance.sbt new file mode 100644 index 000000000..212ee0b6c --- /dev/null +++ b/sbt/src/sbt-test/java/no-scala-tool/changes/explicitInstance.sbt @@ -0,0 +1,3 @@ +scalaInstance := ScalaInstance(scalaVersion.value, appConfiguration.value.provider.scalaProvider) + +scalaVersion := "invalid" diff --git a/sbt/src/sbt-test/java/no-scala-tool/test b/sbt/src/sbt-test/java/no-scala-tool/test new file mode 100644 index 000000000..a05fa2c40 --- /dev/null +++ b/sbt/src/sbt-test/java/no-scala-tool/test @@ -0,0 +1,14 @@ +# test that a pure Java project can be compiled without a dependency on Scala library +> compile + +# It can use the Scala REPL for the version of Scala that sbt runs with +> console + +# A different version of Scala needs to be resolved, but we don't have any resolvers configured +> ++2.8.2 +-> console + +# With an explicit scalaInstance, the Scala tools configuration won't be resolved +$ copy-file changes/explicitInstance.sbt explicitInstance.sbt +> reload +> console diff --git a/sbt/src/sbt-test/project/lib/build.sbt b/sbt/src/sbt-test/project/lib/build.sbt index 4eeaba63c..440c8dbd8 100644 --- a/sbt/src/sbt-test/project/lib/build.sbt +++ b/sbt/src/sbt-test/project/lib/build.sbt @@ -1,6 +1,5 @@ crossPaths := false -// the two spaces following this definition test that sbt handles extra whitespace on a line name := "definition-lib-test" version := "1.0" \ No newline at end of file diff --git a/sbt/src/sbt-test/project/lib/test b/sbt/src/sbt-test/project/lib/test index 6872a9c22..334c74207 100644 --- a/sbt/src/sbt-test/project/lib/test +++ b/sbt/src/sbt-test/project/lib/test @@ -2,13 +2,13 @@ > package $ delete build.sbt -$ copy-file target/definition-lib-test-1.0.jar project/plugins/lib/test.jar +$ copy-file target/definition-lib-test-1.0.jar project/lib/test.jar $ copy-file changes/build2.sbt build.sbt # the copied project definition depends on the Test module in test.jar and will -# fail to compile if sbt did not put the jar in project/plugins/lib/ on the compile classpath +# fail to compile if sbt did not put the jar in project/lib/ on the compile classpath > reload # The project definition uses the class in test.jar and will fail here if sbt did not put the -# jar in project/plugins/lib on the runtime classpath +# jar in project/lib on the runtime classpath > use-jar