Merge remote-tracking branch 'upstream/0.13' into 0.13

This commit is contained in:
Brian Topping 2014-09-15 11:14:13 -04:00
commit ef3eccf95f
14 changed files with 205 additions and 8 deletions

View File

@ -84,6 +84,22 @@ Whether implementing a new feature, fixing a bug, or modifying documentation, pl
Binary compatible changes will be backported to a previous series (currently, 0.12.x) at the time of the next stable release. Binary compatible changes will be backported to a previous series (currently, 0.12.x) at the time of the next stable release.
See below for instructions on building sbt from source. See below for instructions on building sbt from source.
All pull requests are required to include a "Notes" file which documents the change. This file should reside in the
directory:
<sbt root>
notes/
<target release>/
<your-change-name>.md
Notes files should have the following contents:
* Bullet item description under one of the following sections:
- `### Bug fixes`
- `### Improvements`
- `### Fixes with compatibility implications`
* Complete section describing new features.
Documentation Documentation
------------- -------------

View File

@ -0,0 +1,113 @@
package org.apache.ivy.plugins.parser.m2
import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
/**
* It turns out there was a very subtle, and evil, issue sitting the Ivy/maven configuration, and it
* related to dependency mapping. A mapping of `foo->bar(*)` means that the local configuration
* `foo` depends on the remote configuration `bar`, if it exists, or *ALL CONFIGURATIONS* if `bar`
* does not exist. Since the default Ivy configuration mapping was using the random `master`
* configuration, which AFAICT is NEVER specified, just an assumed default, this would cause leaks
* between maven + ivy projects.
*
* i.e. if a maven POM depends on a module denoted by an ivy.xml file, then you'd wind up accidentally
* bleeding ALL the ivy module's configurations into the maven module's configurations.
*
* This fix works around the issue, by assuming that if there is no `master` configuration, than the
* maven default of `compile` is intended. As sbt forces generated `ivy.xml` files to abide by
* maven conventions, this works in all of our test cases. The only scenario where it wouldn't work
* is those who have custom ivy.xml files *and* have pom.xml files which rely on those custom ivy.xml files,
* a very unlikely situation where the workaround is: "define a master configuration".
*
* Also see: http://ant.apache.org/ivy/history/2.3.0/ivyfile/dependency.html
* and: http://svn.apache.org/repos/asf/ant/ivy/core/tags/2.3.0/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorBuilder.java
*
*
*/
object ReplaceMavenConfigurationMappings {
val REPLACEMENT_MAVEN_MAPPINGS = {
// Here we copy paste from Ivy
val REPLACEMENT_MAPPINGS = new java.util.HashMap[String, PomModuleDescriptorBuilder.ConfMapper]
// NOTE - This code is copied from org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder
// except with altered default configurations...
REPLACEMENT_MAPPINGS.put("compile", new PomModuleDescriptorBuilder.ConfMapper {
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean) {
if (isOptional) {
dd.addDependencyConfiguration("optional", "compile(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("optional", "master(compile)")
} else {
dd.addDependencyConfiguration("compile", "compile(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("compile", "master(compile)")
dd.addDependencyConfiguration("runtime", "runtime(*)")
}
}
})
REPLACEMENT_MAPPINGS.put("provided", new PomModuleDescriptorBuilder.ConfMapper {
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean) {
if (isOptional) {
dd.addDependencyConfiguration("optional", "compile(*)")
dd.addDependencyConfiguration("optional", "provided(*)")
dd.addDependencyConfiguration("optional", "runtime(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("optional", "master(compile)")
} else {
dd.addDependencyConfiguration("provided", "compile(*)")
dd.addDependencyConfiguration("provided", "provided(*)")
dd.addDependencyConfiguration("provided", "runtime(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("provided", "master(compile)")
}
}
})
REPLACEMENT_MAPPINGS.put("runtime", new PomModuleDescriptorBuilder.ConfMapper {
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean) {
if (isOptional) {
dd.addDependencyConfiguration("optional", "compile(*)")
dd.addDependencyConfiguration("optional", "provided(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("optional", "master(compile)")
} else {
dd.addDependencyConfiguration("runtime", "compile(*)")
dd.addDependencyConfiguration("runtime", "runtime(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("runtime", "master(compile)")
}
}
})
REPLACEMENT_MAPPINGS.put("test", new PomModuleDescriptorBuilder.ConfMapper {
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean) {
dd.addDependencyConfiguration("test", "runtime(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("test", "master(compile)")
}
})
REPLACEMENT_MAPPINGS.put("system", new PomModuleDescriptorBuilder.ConfMapper {
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean) {
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("system", "master(compile)")
}
})
REPLACEMENT_MAPPINGS
}
def init(): Unit = {
// Here we mutate a static final field, because we have to AND because it's evil.
try {
val map = PomModuleDescriptorBuilder.MAVEN2_CONF_MAPPING.asInstanceOf[java.util.Map[String, PomModuleDescriptorBuilder.ConfMapper]]
map.clear()
map.putAll(REPLACEMENT_MAVEN_MAPPINGS)
} catch {
case e: Exception =>
// TODO - Log that Ivy may not be configured correctly and you could have maven/ivy issues.
throw new RuntimeException("FAILURE to install Ivy maven hooks. Your ivy-maven interaction may suffer resolution errors", e)
}
}
}

View File

@ -4,7 +4,7 @@ import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.ivy.core.module.descriptor.{ DefaultArtifact, DefaultExtendsDescriptor, DefaultModuleDescriptor, ModuleDescriptor } import org.apache.ivy.core.module.descriptor.{ DefaultArtifact, DefaultExtendsDescriptor, DefaultModuleDescriptor, ModuleDescriptor }
import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DependencyDescriptor } import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DependencyDescriptor }
import org.apache.ivy.plugins.parser.{ ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings } import org.apache.ivy.plugins.parser.{ ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings }
import org.apache.ivy.plugins.parser.m2.{ PomModuleDescriptorBuilder, PomModuleDescriptorParser } import org.apache.ivy.plugins.parser.m2.{ ReplaceMavenConfigurationMappings, PomModuleDescriptorBuilder, PomModuleDescriptorParser }
import org.apache.ivy.plugins.repository.Resource import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.namespace.NamespaceTransformer import org.apache.ivy.plugins.namespace.NamespaceTransformer
import org.apache.ivy.util.extendable.ExtendableItem import org.apache.ivy.util.extendable.ExtendableItem
@ -27,6 +27,10 @@ final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (Module
override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) = delegate.getMetadataArtifact(mrid, res) override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) = delegate.getMetadataArtifact(mrid, res)
} }
object CustomPomParser { object CustomPomParser {
// Evil hackery to override the default maven pom mappings.
ReplaceMavenConfigurationMappings.init()
/** The key prefix that indicates that this is used only to store extra information and is not intended for dependency resolution.*/ /** The key prefix that indicates that this is used only to store extra information and is not intended for dependency resolution.*/
val InfoKeyPrefix = "info." val InfoKeyPrefix = "info."
val ApiURLKey = "info.apiURL" val ApiURLKey = "info.apiURL"

View File

@ -27,7 +27,7 @@ private[sbt] object SettingCompletions {
{ {
import extracted._ import extracted._
val r = relation(extracted.structure, true) val r = relation(extracted.structure, true)
val allDefs = r._1s.toSeq val allDefs = Def.flattenLocals(Def.compiled(extracted.structure.settings, true)(structure.delegates, structure.scopeLocal, implicitly[Show[ScopedKey[_]]])).map(_._1)
val projectScope = Load.projectScope(currentRef) val projectScope = Load.projectScope(currentRef)
def resolve(s: Setting[_]): Seq[Setting[_]] = Load.transformSettings(projectScope, currentRef.build, rootProject, s :: Nil) def resolve(s: Setting[_]): Seq[Setting[_]] = Load.transformSettings(projectScope, currentRef.build, rootProject, s :: Nil)
def rescope[T](setting: Setting[T]): Seq[Setting[_]] = def rescope[T](setting: Setting[T]): Seq[Setting[_]] =
@ -353,4 +353,4 @@ private[sbt] object SettingCompletions {
classOf[Long], classOf[Long],
classOf[String] classOf[String]
) )
} }

View File

@ -0,0 +1,8 @@
[1586]: https://github.com/sbt/sbt/pull/1586
[@jsuereth]: https://github.com/jsuereth
### Fixes with compatibility implications
* Maven artifact dependencies now limit their transitive dependencies to "compile" rather than "every configuration"
if no `master` configuration is found. [#1586][1586] by [@jsuereth][@jsuereth]

View File

@ -17,7 +17,7 @@ object Sbt extends Build {
s"all control/$task collections/$task io/$task completion/$task" s"all control/$task collections/$task io/$task completion/$task"
def buildSettings = Seq( def buildSettings = Seq(
organization := "org.scala-sbt", organization := "org.scala-sbt",
version := "0.13.6-SNAPSHOT", version := "0.13.7-SNAPSHOT",
publishArtifact in packageDoc := false, publishArtifact in packageDoc := false,
scalaVersion := "2.10.4", scalaVersion := "2.10.4",
publishMavenStyle := false, publishMavenStyle := false,

View File

@ -0,0 +1,15 @@
val repoFile = file("mvn-repo")
resolvers += "bad-mvn-repo" at repoFile.toURI.toURL.toString
libraryDependencies += "bad" % "mvn" % "1.0"
TaskKey[Unit]("check") := {
val cp = (fullClasspath in Compile).value
def isTestJar(n: String): Boolean =
(n contains "scalacheck") ||
(n contains "specs2")
val testLibs = cp map (_.data.getName) filter isTestJar
assert(testLibs.isEmpty, s"Compile Classpath has test libs:\n * ${testLibs.mkString("\n * ")}")
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>bad</groupId>
<artifactId>mvn</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>org.scala-sbt</groupId>
<artifactId>completion</artifactId>
<version>0.13.5</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1 @@
> check

View File

@ -16,9 +16,14 @@ object TestProject extends Build
private def check(transitive: Boolean) = private def check(transitive: Boolean) =
(dependencyClasspath in Compile) map { downloaded => (dependencyClasspath in Compile) map { downloaded =>
val jars = downloaded.size val jars = downloaded.size
if(transitive) if(transitive) {
if(jars <= 2) error("Transitive dependencies not downloaded") else () if (jars <= 2)
else sys.error(s"Transitive dependencies not downloaded, found:\n * ${downloaded.mkString("\n * ")}")
if(jars > 2) error("Transitive dependencies downloaded (" + downloaded.files.mkString(", ") + ")") else () else ()
} else {
if (jars > 2)
sys.error(s"Transitive dependencies not downloaded, found:\n * ${downloaded.mkString("\n * ")}")
else ()
}
} }
} }

View File

@ -1,3 +1,4 @@
> debug
# load the project definition with transitive dependencies enabled # load the project definition with transitive dependencies enabled
# and check that they are not downloaded # and check that they are not downloaded
#$ pause #$ pause

View File

@ -0,0 +1,16 @@
val a = project.settings(version := "2.8.1")
val trySetEvery = taskKey[Unit]("Tests \"set every\"")
trySetEvery := {
val s = state.value
val extracted = Project.extract(s)
import extracted._
val allProjs = structure.allProjectRefs
val Some(aProj) = allProjs.find(_.project == "a")
val aVer = (version in aProj get structure.data).get
if (aVer != "1.0") {
println("Version of project a: " + aVer + ", expected: 1.0")
error("\"set every\" did not change the version of all projects.")
}
}

View File

@ -0,0 +1,3 @@
> set every version := '"1.0"'
> trySetEvery