diff --git a/src/main/scala/sbt/BasicProjectTypes.scala b/src/main/scala/sbt/BasicProjectTypes.scala index b512e70d1..793951d69 100644 --- a/src/main/scala/sbt/BasicProjectTypes.scala +++ b/src/main/scala/sbt/BasicProjectTypes.scala @@ -279,13 +279,14 @@ trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject w /** The options provided to the 'update' action. This is by default the options in 'baseUpdateOptions'. * If 'manager' has any dependencies, resolvers, or inline Ivy XML (which by default happens when inline * dependency management is used), it is passed as the dependency manager.*/ - def updateOptions: Seq[ManagedOption] = + def updateOptions: Seq[ManagedOption] = baseUpdateOptions ++ managerOption + def managerOption: Seq[ManagedOption] = { val m = manager if(m.dependencies.isEmpty && m.resolvers.isEmpty && ivyXML.isEmpty && m.artifacts.isEmpty && m.configurations.isEmpty) - baseUpdateOptions + Nil else - LibraryManager(m) :: baseUpdateOptions + LibraryManager(m) :: Nil } def deliverOptions: Seq[ManagedOption] = updateOptions.filter { case _: CheckScalaVersion => false; case _ => true } def publishOptions: Seq[ManagedOption] = deliverOptions @@ -347,11 +348,20 @@ trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject w protected def deliverProjectDependencies: Iterable[ModuleID] = { val interDependencies = new scala.collection.mutable.ListBuffer[ModuleID] - dependencies.foreach(dep => dep match { case mp: ManagedProject => interDependencies += mp.projectID; case _ => () }) + dependencies.foreach(dep => dep match { case mp: ManagedProject => interDependencies += projectModuleID(mp); case _ => () }) if(filterScalaJars) interDependencies ++= deliverScalaDependencies interDependencies.readOnly } + protected def projectModuleID(mp: ManagedProject) = + { + val base = mp.projectID + val as = mp.artifacts.toSeq.toArray + if(as.size == 1) + base artifacts(as : _*) + else + base artifacts(as.filter(_.`type` != "pom") : _*) + } protected def deliverScalaDependencies: Iterable[ModuleID] = Nil protected def makePomAction = makePomTask(pomPath, deliverProjectDependencies, None, updateOptions) protected def deliverLocalAction = deliverTask(publishLocalConfiguration, deliverOptions) @@ -542,6 +552,7 @@ trait ReflectiveProject extends ReflectiveModules with ReflectiveTasks with Refl /** This Project subclass is used to contain other projects as dependencies.*/ class ParentProject(val info: ProjectInfo) extends BasicDependencyProject { + override def managerOption: Seq[ManagedOption] = LibraryManager(new AutoDetectManager(projectID, false)) :: Nil def dependencies: Iterable[Project] = info.dependencies ++ subProjects.values.toList /** The directories to which a project writes are listed here and is used * to check a project and its dependencies for collisions.*/ diff --git a/src/main/scala/sbt/ManageDependencies.scala b/src/main/scala/sbt/ManageDependencies.scala index e136e64b7..adb70191c 100644 --- a/src/main/scala/sbt/ManageDependencies.scala +++ b/src/main/scala/sbt/ManageDependencies.scala @@ -138,7 +138,7 @@ object ManageDependencies /** Called to determine dependencies when the dependency manager is SbtManager and no inline dependencies (Scala or XML) are defined * or if the manager is AutodetectManager. It will try to read from pom.xml first and then ivy.xml if pom.xml is not found. If neither is found, * Ivy is configured with defaults unless IvyFlags.errorIfNoConfiguration is true, in which case an error is generated.*/ - def autodetectDependencies(module: ModuleRevisionId) = + def autodetectDependencies(module: ModuleRevisionId, defaultArtifact: Boolean) = { log.debug("Autodetecting dependencies.") val defaultPOMFile = defaultPOM(paths.projectDirectory).asFile @@ -157,7 +157,8 @@ object ManageDependencies log.warn("No readable dependency configuration found, using defaults.") val moduleID = DefaultModuleDescriptor.newDefaultInstance(module) addMainArtifact(moduleID) - addDefaultArtifact(defaultConf, moduleID) + if(defaultArtifact) + addDefaultArtifact(defaultConf, moduleID) Right((moduleID, defaultConf)) } } @@ -183,7 +184,7 @@ object ManageDependencies { log.debug("No dependency manager explicitly specified.") autodetectConfiguration() - autodetectDependencies(toID(adm.module)) + autodetectDependencies(toID(adm.module), adm.defaultArtifact) } case sm: SbtManager => { @@ -196,7 +197,7 @@ object ManageDependencies configureDefaults(withDefaultResolvers(resolvers)) } if(autodetect) - autodetectDependencies(toID(module)) + autodetectDependencies(toID(module), true) else { val moduleID = @@ -280,7 +281,7 @@ object ManageDependencies } } private def addExtraNamespaces(md: DefaultModuleDescriptor): Unit = - md.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].put("m", "m") + md.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].put("e", "http://ant.apache.org/ivy/extra") /** 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]): Option[String] = @@ -538,7 +539,11 @@ object ManageDependencies } } private def extra(artifact: Artifact) = - artifact.classifier.map(c => wrap.Wrappers.javaMap("m:classifier" -> c)).getOrElse(null) + { + val ea = artifact.classifier match { case Some(c) => artifact.extra("e:classifier" -> c); case None => artifact } + javaMap(artifact.extraAttributes) + } + private def javaMap(map: Map[String,String]) = if(map.isEmpty) null else wrap.Wrappers.javaMap(map.toSeq : _*) private def toURL(file: File) = file.toURI.toURL /** Adds the ivy.xml main artifact. */ private def addMainArtifact(moduleID: DefaultModuleDescriptor) @@ -574,7 +579,7 @@ object ManageDependencies private def toID(m: ModuleID) = { import m._ - ModuleRevisionId.newInstance(organization, name, revision) + ModuleRevisionId.newInstance(organization, name, revision, javaMap(extraAttributes)) } private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, configurations: Iterable[String]): MDArtifact = { diff --git a/src/main/scala/sbt/ManagedInterface.scala b/src/main/scala/sbt/ManagedInterface.scala index c1e4e0611..f9f0e725b 100644 --- a/src/main/scala/sbt/ManagedInterface.scala +++ b/src/main/scala/sbt/ManagedInterface.scala @@ -12,7 +12,10 @@ import org.apache.ivy.util.url.CredentialsStore sealed abstract class Manager extends NotNull /** This explicitly requests auto detection as a dependency manager. It will first check for a 'pom.xml' file and if that does not exist, an 'ivy.xml' file. * Ivy is configured using the detected file or uses defaults.*/ -final class AutoDetectManager(val module: ModuleID) extends Manager +final class AutoDetectManager(val module: ModuleID, val defaultArtifact: Boolean) extends Manager +{ + def this(module: ModuleID) = this(module, true) +} /** This explicitly requests that the Maven pom 'pom' be used to determine dependencies. An Ivy configuration file to use may be specified in * 'configuration', since Ivy currently cannot extract Maven repositories from a pom file. Otherwise, defaults are used.*/ final class MavenManager(val configuration: Option[Path], val pom: Path) extends Manager @@ -52,16 +55,17 @@ final class SimpleManager private[sbt] (val dependenciesXML: NodeSeq, val autode explicitConfigurations } -final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact]) extends NotNull +final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact], extraAttributes: Map[String,String]) extends NotNull { override def toString = organization + ":" + name + ":" + revision // () required for chaining def notTransitive() = intransitive() - def intransitive() = ModuleID(organization, name, revision, configurations, isChanging, false, explicitArtifacts) - def changing() = ModuleID(organization, name, revision, configurations, true, isTransitive, explicitArtifacts) + def intransitive() = ModuleID(organization, name, revision, configurations, isChanging, false, explicitArtifacts, extraAttributes) + def changing() = ModuleID(organization, name, revision, configurations, true, isTransitive, explicitArtifacts, extraAttributes) def from(url: String) = artifacts(Artifact(name, new URL(url))) def classifier(c: String) = artifacts(Artifact(name, c)) - def artifacts(newArtifacts: Artifact*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, newArtifacts ++ explicitArtifacts) + def artifacts(newArtifacts: Artifact*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, newArtifacts ++ explicitArtifacts, extraAttributes) + def extra(attributes: (String,String)*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, explicitArtifacts, extraAttributes ++ attributes) } object ModuleID { @@ -70,6 +74,8 @@ object ModuleID ModuleID(organization, name, revision, configurations, false, true) def apply(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean): ModuleID = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, Nil) + def apply(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact]): ModuleID = + ModuleID(organization, name, revision, configurations, isChanging, isTransitive, explicitArtifacts, Map.empty) } sealed trait Resolver extends NotNull { @@ -334,13 +340,19 @@ final case class Configuration(name: String, description: String, isPublic: Bool override def toString = name } -final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]) extends NotNull +final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String,String]) extends NotNull +{ + def extra(attributes: (String,String)*) = Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes ++ attributes) +} object Artifact { def apply(name: String): Artifact = Artifact(name, defaultType, defaultExtension, None, Nil, None) + def apply(name: String, extra: Map[String,String]): Artifact = Artifact(name, defaultType, defaultExtension, None, Nil, None, extra) def apply(name: String, classifier: String): Artifact = Artifact(name, defaultType, defaultExtension, Some(classifier), Nil, None) def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Nil, None) def apply(name: String, url: URL): Artifact =Artifact(name, extract(url, defaultType), extract(url, defaultExtension), None, Nil, Some(url)) + def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]): Artifact = + Artifact(name, `type`, extension, classifier, configurations, url, Map.empty) val defaultExtension = "jar" val defaultType = "jar" private[this] def extract(url: URL, default: String) =