mirror of https://github.com/sbt/sbt.git
Manually merged #25
This commit is contained in:
commit
7edd4a954a
|
|
@ -140,6 +140,7 @@ final class IvySbt(val configuration: IvyConfiguration) {
|
|||
|
||||
/**
|
||||
* Cleans cached resolution cache.
|
||||
*
|
||||
* @param md - module descriptor of the original Ivy graph.
|
||||
*/
|
||||
private[sbt] def cleanCachedResolutionCache(md: ModuleDescriptor, log: Logger): Unit =
|
||||
|
|
@ -621,6 +622,12 @@ private[sbt] object IvySbt {
|
|||
dependencyDescriptor.addExcludeRule(conf, IvyScala.excludeRule(excls.organization, excls.name, excls.configurations, excls.artifact))
|
||||
}
|
||||
}
|
||||
for (incls <- dependency.inclusions) {
|
||||
for (conf <- dependencyDescriptor.getModuleConfigurations) {
|
||||
dependencyDescriptor.addIncludeRule(conf, IvyScala.includeRule(incls.organization, incls.name, incls.configurations, incls.artifact))
|
||||
}
|
||||
}
|
||||
|
||||
dependencyDescriptor
|
||||
}
|
||||
def copyConfigurations(artifact: Artifact, addConfiguration: String => Unit): Unit =
|
||||
|
|
|
|||
|
|
@ -29,21 +29,27 @@ final class PublishConfiguration(val ivyFile: Option[File], val resolverName: St
|
|||
this(ivyFile, resolverName, artifacts, checksums, logging, false)
|
||||
}
|
||||
|
||||
final class UpdateConfiguration(val retrieve: Option[RetrieveConfiguration], val missingOk: Boolean, val logging: UpdateLogging.Value) {
|
||||
final class UpdateConfiguration(val retrieve: Option[RetrieveConfiguration], val missingOk: Boolean, val logging: UpdateLogging.Value, val artifactFilter: ArtifactTypeFilter) {
|
||||
@deprecated("You should use the constructor that provides an artifactFilter", "1.0.x")
|
||||
def this(retrieve: Option[RetrieveConfiguration], missingOk: Boolean, logging: UpdateLogging.Value) {
|
||||
this(retrieve, missingOk, logging, ArtifactTypeFilter.forbid(Set("src", "doc"))) // allow everything but "src", "doc" by default
|
||||
}
|
||||
|
||||
private[sbt] def copy(
|
||||
retrieve: Option[RetrieveConfiguration] = this.retrieve,
|
||||
missingOk: Boolean = this.missingOk,
|
||||
logging: UpdateLogging.Value = this.logging
|
||||
logging: UpdateLogging.Value = this.logging,
|
||||
artifactFilter: ArtifactTypeFilter = this.artifactFilter
|
||||
): UpdateConfiguration =
|
||||
new UpdateConfiguration(retrieve, missingOk, logging)
|
||||
new UpdateConfiguration(retrieve, missingOk, logging, artifactFilter)
|
||||
}
|
||||
final class RetrieveConfiguration(val retrieveDirectory: File, val outputPattern: String, val sync: Boolean, val configurationsToRetrieve: Option[Set[Configuration]]) {
|
||||
def this(retrieveDirectory: File, outputPattern: String) = this(retrieveDirectory, outputPattern, false, None)
|
||||
def this(retrieveDirectory: File, outputPattern: String, sync: Boolean) = this(retrieveDirectory, outputPattern, sync, None)
|
||||
}
|
||||
final case class MakePomConfiguration(file: File, moduleInfo: ModuleInfo, configurations: Option[Seq[Configuration]] = None, extra: NodeSeq = NodeSeq.Empty, process: XNode => XNode = n => n, filterRepositories: MavenRepository => Boolean = _ => true, allRepositories: Boolean, includeTypes: Set[String] = Set(Artifact.DefaultType, Artifact.PomType))
|
||||
// exclude is a map on a restricted ModuleID
|
||||
final case class GetClassifiersConfiguration(module: GetClassifiersModule, exclude: Map[ModuleID, Set[String]], configuration: UpdateConfiguration, ivyScala: Option[IvyScala])
|
||||
/** @param exclude is a map from ModuleID to classifiers that were previously tried and failed, so should now be excluded */
|
||||
final case class GetClassifiersConfiguration(module: GetClassifiersModule, exclude: Map[ModuleID, Set[String]], configuration: UpdateConfiguration, ivyScala: Option[IvyScala], sourceArtifactTypes: Set[String], docArtifactTypes: Set[String])
|
||||
final case class GetClassifiersModule(id: ModuleID, modules: Seq[ModuleID], configurations: Seq[Configuration], classifiers: Seq[String])
|
||||
|
||||
final class UnresolvedWarningConfiguration private[sbt] (
|
||||
|
|
@ -180,6 +186,7 @@ object IvyActions {
|
|||
val resolveOptions = new ResolveOptions
|
||||
val resolveId = ResolveOptions.getDefaultResolveId(md)
|
||||
resolveOptions.setResolveId(resolveId)
|
||||
resolveOptions.setArtifactFilter(configuration.artifactFilter)
|
||||
resolveOptions.setLog(ivyLogLevel(configuration.logging))
|
||||
x.customResolve(md, configuration.missingOk, logicalClock, resolveOptions, depDir getOrElse { sys.error("dependency base directory is not specified") }, log) match {
|
||||
case Left(x) =>
|
||||
|
|
@ -194,7 +201,7 @@ object IvyActions {
|
|||
case (ivy, md, default) =>
|
||||
val iw = IvySbt.inconsistentDuplicateWarning(md)
|
||||
iw foreach { log.warn(_) }
|
||||
val (report, err) = resolve(configuration.logging)(ivy, md, default)
|
||||
val (report, err) = resolve(configuration.logging)(ivy, md, default, configuration.artifactFilter)
|
||||
err match {
|
||||
case Some(x) if !configuration.missingOk =>
|
||||
Left(UnresolvedWarning(x, uwconfig))
|
||||
|
|
@ -243,7 +250,15 @@ object IvyActions {
|
|||
def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration, log: Logger): UpdateReport =
|
||||
updateClassifiers(ivySbt, config, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log)
|
||||
|
||||
// artifacts can be obtained from calling toSeq on UpdateReport
|
||||
/**
|
||||
* Creates explicit artifacts for each classifier in `config.module`, and then attempts to resolve them directly. This
|
||||
* is for Maven compatibility, where these artifacts are not "published" in the POM, so they don't end up in the Ivy
|
||||
* that sbt generates for them either.<br>
|
||||
* Artifacts can be obtained from calling toSeq on UpdateReport.<br>
|
||||
* In addition, retrieves specific Ivy artifacts if they have one of the requested `config.configuration.types`.
|
||||
* @param config important to set `config.configuration.types` to only allow artifact types that can correspond to
|
||||
* "classified" artifacts (sources and javadocs).
|
||||
*/
|
||||
private[sbt] def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration, logicalClock: LogicalClock, depDir: Option[File],
|
||||
artifacts: Vector[(String, ModuleID, Artifact, File)],
|
||||
|
|
@ -252,14 +267,28 @@ object IvyActions {
|
|||
import config.{ configuration => c, module => mod, _ }
|
||||
import mod.{ configurations => confs, _ }
|
||||
assert(classifiers.nonEmpty, "classifiers cannot be empty")
|
||||
assert(c.artifactFilter.types.nonEmpty, "UpdateConfiguration must filter on some types")
|
||||
val baseModules = modules map { m => restrictedCopy(m, true) }
|
||||
// Adding list of explicit artifacts here.
|
||||
val deps = baseModules.distinct flatMap classifiedArtifacts(classifiers, exclude, artifacts)
|
||||
val base = restrictedCopy(id, true).copy(name = id.name + classifiers.mkString("$", "_", ""))
|
||||
val module = new ivySbt.Module(InlineConfigurationWithExcludes(base, ModuleInfo(base.name), deps).copy(ivyScala = ivyScala, configurations = confs))
|
||||
val upConf = new UpdateConfiguration(c.retrieve, true, c.logging)
|
||||
// c.copy ensures c.types is preserved too
|
||||
val upConf = c.copy(missingOk = true)
|
||||
updateEither(module, upConf, uwconfig, logicalClock, depDir, log) match {
|
||||
case Right(r) => r
|
||||
case Right(r) =>
|
||||
// The artifacts that came from Ivy don't have their classifier set, let's set it according to
|
||||
// FIXME: this is only done because IDE plugins depend on `classifier` to determine type. They
|
||||
val typeClassifierMap: Map[String, String] =
|
||||
((sourceArtifactTypes.toIterable map (_ -> Artifact.SourceClassifier))
|
||||
:: (docArtifactTypes.toIterable map (_ -> Artifact.DocClassifier)) :: Nil).flatten.toMap
|
||||
r.substitute { (conf, mid, artFileSeq) =>
|
||||
artFileSeq map {
|
||||
case (art, f) =>
|
||||
// Deduce the classifier from the type if no classifier is present already
|
||||
art.copy(classifier = art.classifier orElse typeClassifierMap.get(art.`type`)) -> f
|
||||
}
|
||||
}
|
||||
case Left(w) =>
|
||||
throw w.resolveException
|
||||
}
|
||||
|
|
@ -275,7 +304,7 @@ object IvyActions {
|
|||
{
|
||||
val arts = (artifacts collect { case (_, x, art, _) if sameModule(m, x) && art.classifier.isDefined => art }).distinct
|
||||
if (arts.isEmpty) None
|
||||
else Some(m.copy(isTransitive = false, explicitArtifacts = arts))
|
||||
else Some(intransitiveModuleWithExplicitArts(m, arts))
|
||||
}
|
||||
def hardcodedArtifacts = classifiedArtifacts(classifiers, exclude)(m)
|
||||
explicitArtifacts orElse hardcodedArtifacts
|
||||
|
|
@ -284,8 +313,27 @@ object IvyActions {
|
|||
{
|
||||
val excluded = exclude getOrElse (restrictedCopy(m, false), Set.empty)
|
||||
val included = classifiers filterNot excluded
|
||||
if (included.isEmpty) None else Some(m.copy(isTransitive = false, explicitArtifacts = classifiedArtifacts(m.name, included)))
|
||||
if (included.isEmpty) None else {
|
||||
Some(intransitiveModuleWithExplicitArts(module = m, arts = classifiedArtifacts(m.name, included)))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set an "include all" rule (the default) because otherwise, if we declare ANY explicitArtifacts,
|
||||
* [[org.apache.ivy.core.resolve.IvyNode#getArtifacts]] (in Ivy 2.3.0-rc1) will not merge in the descriptor's
|
||||
* artifacts and will only keep the explicitArtifacts.
|
||||
* <br>
|
||||
* Look for the comment saying {{{
|
||||
* // and now we filter according to include rules
|
||||
* }}}
|
||||
* in `IvyNode`, which iterates on `includes`, which will ordinarily be empty because higher up, in {{{
|
||||
* addAllIfNotNull(includes, usage.getDependencyIncludesSet(rootModuleConf));
|
||||
* }}}
|
||||
* `usage.getDependencyIncludesSet` returns null if there are no (explicit) include rules.
|
||||
*/
|
||||
private def intransitiveModuleWithExplicitArts(module: ModuleID, arts: Seq[Artifact]): ModuleID =
|
||||
module.copy(isTransitive = false, explicitArtifacts = arts, inclusions = InclExclRule.everything :: Nil)
|
||||
|
||||
def addExcluded(report: UpdateReport, classifiers: Seq[String], exclude: Map[ModuleID, Set[String]]): UpdateReport =
|
||||
report.addMissing { id => classifiedArtifacts(id.name, classifiers filter getExcluded(id, exclude)) }
|
||||
def classifiedArtifacts(name: String, classifiers: Seq[String]): Seq[Artifact] =
|
||||
|
|
@ -300,11 +348,12 @@ object IvyActions {
|
|||
ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, extraAttributes = m.extraAttributes, configurations = if (confs) m.configurations else None)
|
||||
.branch(m.branchName)
|
||||
|
||||
private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): (ResolveReport, Option[ResolveException]) =
|
||||
private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String, filter: ArtifactTypeFilter): (ResolveReport, Option[ResolveException]) =
|
||||
{
|
||||
val resolveOptions = new ResolveOptions
|
||||
val resolveId = ResolveOptions.getDefaultResolveId(module)
|
||||
resolveOptions.setResolveId(resolveId)
|
||||
resolveOptions.setArtifactFilter(filter)
|
||||
resolveOptions.setLog(ivyLogLevel(logging))
|
||||
ResolutionCache.cleanModule(module.getModuleRevisionId, resolveId, ivy.getSettings.getResolutionCacheManager)
|
||||
val resolveReport = ivy.resolve(module, resolveOptions)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ final class RichUpdateReport(report: UpdateReport) {
|
|||
moduleReportMap { (configuration, modReport) =>
|
||||
val newArtifacts = f(configuration, modReport.module, modReport.artifacts)
|
||||
modReport.copy(
|
||||
artifacts = f(configuration, modReport.module, modReport.artifacts),
|
||||
missingArtifacts = Nil
|
||||
artifacts = newArtifacts,
|
||||
missingArtifacts = modReport.missingArtifacts
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ import java.net.URL
|
|||
import sbt.serialization._
|
||||
|
||||
final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String, String]) {
|
||||
def extra(attributes: (String, String)*) = Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes ++ ModuleID.checkE(attributes))
|
||||
def extra(attributes: (String, String)*) = copy(extraAttributes = extraAttributes ++ ModuleID.checkE(attributes))
|
||||
}
|
||||
|
||||
import Configurations.{ config, Docs, Optional, Pom, Sources, Test }
|
||||
import Configurations.{ config, Optional, Pom, Test }
|
||||
|
||||
object Artifact {
|
||||
def apply(name: String): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Nil, None)
|
||||
|
|
@ -30,12 +30,23 @@ object Artifact {
|
|||
def javadoc(name: String) = classified(name, DocClassifier)
|
||||
def pom(name: String) = Artifact(name, PomType, PomType, None, Pom :: Nil, None)
|
||||
|
||||
// Possible ivy artifact types such that sbt will treat those artifacts at sources / docs
|
||||
val DefaultSourceTypes = Set("src", "source", "sources")
|
||||
val DefaultDocTypes = Set("doc", "docs", "javadoc", "javadocs")
|
||||
|
||||
val DocClassifier = "javadoc"
|
||||
val SourceClassifier = "sources"
|
||||
|
||||
val TestsClassifier = "tests"
|
||||
// Artifact types used when:
|
||||
// * artifacts are explicitly created for Maven dependency resolution (see updateClassifiers)
|
||||
// * declaring artifacts as part of creating Ivy files.
|
||||
val DocType = "doc"
|
||||
val SourceType = "src"
|
||||
val PomType = "pom"
|
||||
val TestsClassifier = "tests"
|
||||
|
||||
assert(DefaultDocTypes contains DocType)
|
||||
assert(DefaultSourceTypes contains SourceType)
|
||||
|
||||
def extract(url: URL, default: String): String = extract(url.toString, default)
|
||||
def extract(name: String, default: String): String =
|
||||
|
|
@ -62,16 +73,22 @@ object Artifact {
|
|||
base + "-" + module.revision + classifierStr + "." + artifact.extension
|
||||
}
|
||||
|
||||
val classifierConfMap = Map(SourceClassifier -> Sources, DocClassifier -> Docs)
|
||||
val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
|
||||
@deprecated("Configuration should not be decided from the classifier.", "1.0")
|
||||
def classifierConf(classifier: String): Configuration =
|
||||
if (classifier.startsWith(TestsClassifier))
|
||||
Test
|
||||
else
|
||||
classifierConfMap.getOrElse(classifier, Optional)
|
||||
Optional
|
||||
def classifierType(classifier: String): String = classifierTypeMap.getOrElse(classifier.stripPrefix(TestsClassifier + "-"), DefaultType)
|
||||
|
||||
/**
|
||||
* Create a classified explicit artifact, to be used when trying to resolve sources|javadocs from Maven. This is
|
||||
* necessary because those artifacts are not published in the Ivy generated from the Pom of the module in question.
|
||||
* The artifact is created under the default configuration.
|
||||
*/
|
||||
def classified(name: String, classifier: String): Artifact =
|
||||
Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), classifierConf(classifier) :: Nil, None)
|
||||
Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), Nil, None)
|
||||
|
||||
private val optStringPickler = implicitly[Pickler[Option[String]]]
|
||||
private val optStringUnpickler = implicitly[Unpickler[Option[String]]]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,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)
|
||||
def auxiliary: Seq[Configuration] = Seq(Pom)
|
||||
def names(cs: Seq[Configuration]) = cs.map(_.name)
|
||||
|
||||
lazy val RuntimeInternal = optionalInternal(Runtime)
|
||||
|
|
@ -34,10 +34,8 @@ object Configurations {
|
|||
lazy val Compile = config("compile")
|
||||
lazy val IntegrationTest = config("it") extend (Runtime)
|
||||
lazy val Provided = config("provided")
|
||||
lazy val Docs = config("docs")
|
||||
lazy val Runtime = config("runtime") extend (Compile)
|
||||
lazy val Test = config("test") extend (Runtime)
|
||||
lazy val Sources = config("sources")
|
||||
lazy val System = config("system")
|
||||
lazy val Optional = config("optional")
|
||||
lazy val Pom = config("pom")
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import java.net.{ URI, URL }
|
|||
import scala.xml.NodeSeq
|
||||
import org.apache.ivy.plugins.resolver.{ DependencyResolver, IBiblioResolver }
|
||||
import org.apache.ivy.util.url.CredentialsStore
|
||||
import org.apache.ivy.core.module.descriptor
|
||||
import org.apache.ivy.util.filter.{ Filter => IvyFilter }
|
||||
import sbt.serialization._
|
||||
|
||||
/** Additional information about a project module */
|
||||
|
|
@ -25,10 +27,40 @@ final case class ScmInfo(browseUrl: URL, connection: String, devConnection: Opti
|
|||
|
||||
final case class Developer(id: String, name: String, email: String, url: URL)
|
||||
|
||||
/** Rule to exclude unwanted dependencies pulled in transitively by a module. */
|
||||
final case class ExclusionRule(organization: String = "*", name: String = "*", artifact: String = "*", configurations: Seq[String] = Nil)
|
||||
object ExclusionRule {
|
||||
implicit val pickler: Pickler[ExclusionRule] with Unpickler[ExclusionRule] = PicklerUnpickler.generate[ExclusionRule]
|
||||
/**
|
||||
* Rule to either:
|
||||
* <ul>
|
||||
* <li> exclude unwanted dependencies pulled in transitively by a module, or to</li>
|
||||
* <li> include and merge artifacts coming from the ModuleDescriptor if "dependencyArtifacts" are also provided.</li>
|
||||
* </ul>
|
||||
* Which one depends on the parameter name which it is passed to, but the filter has the same fields in both cases.
|
||||
*/
|
||||
final case class InclExclRule(organization: String = "*", name: String = "*", artifact: String = "*", configurations: Seq[String] = Nil)
|
||||
object InclExclRule {
|
||||
def everything = InclExclRule("*", "*", "*", Nil)
|
||||
|
||||
implicit val pickler: Pickler[InclExclRule] with Unpickler[InclExclRule] = PicklerUnpickler.generate[InclExclRule]
|
||||
}
|
||||
|
||||
/**
|
||||
* Work around the inadequacy of Ivy's ArtifactTypeFilter (that it cannot reverse a filter)
|
||||
* @param types represents the artifact types that we should try to resolve for (as in the allowed values of
|
||||
* `artifact[type]` from a dependency `<publications>` section). One can use this to filter
|
||||
* source / doc artifacts.
|
||||
* @param inverted whether to invert the types filter (i.e. allow only types NOT in the set)
|
||||
*/
|
||||
case class ArtifactTypeFilter(types: Set[String], inverted: Boolean) {
|
||||
def invert = copy(inverted = !inverted)
|
||||
def apply(a: descriptor.Artifact): Boolean = (types contains a.getType) ^ inverted
|
||||
}
|
||||
|
||||
object ArtifactTypeFilter {
|
||||
def allow(types: Set[String]) = ArtifactTypeFilter(types, false)
|
||||
def forbid(types: Set[String]) = ArtifactTypeFilter(types, true)
|
||||
|
||||
implicit def toIvyFilter(f: ArtifactTypeFilter): IvyFilter = new IvyFilter {
|
||||
override def accept(o: Object): Boolean = Option(o) exists { case a: descriptor.Artifact => f.apply(a) }
|
||||
}
|
||||
}
|
||||
|
||||
final case class ModuleConfiguration(organization: String, name: String, revision: String, resolver: Resolver)
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ package sbt.librarymanagement
|
|||
import java.util.Collections.emptyMap
|
||||
import scala.collection.mutable.HashSet
|
||||
|
||||
import org.apache.ivy.core.module.descriptor.{ DefaultExcludeRule, ExcludeRule }
|
||||
import org.apache.ivy.core.module.descriptor.{ DependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor, OverrideDependencyDescriptorMediator }
|
||||
import org.apache.ivy.core.module.descriptor._
|
||||
import org.apache.ivy.core.module.id.{ ArtifactId, ModuleId, ModuleRevisionId }
|
||||
import org.apache.ivy.plugins.matcher.ExactPatternMatcher
|
||||
import sbt.util.Logger
|
||||
|
|
@ -125,4 +124,16 @@ private[sbt] object IvyScala {
|
|||
configurationNames.foreach(rule.addConfiguration)
|
||||
rule
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IncludeRule that includes artifacts with the given module organization and name for
|
||||
* the given configurations.
|
||||
*/
|
||||
private[sbt] def includeRule(organization: String, name: String, configurationNames: Iterable[String], includeTypePattern: String): IncludeRule =
|
||||
{
|
||||
val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", includeTypePattern, "*")
|
||||
val rule = new DefaultIncludeRule(artifact, ExactPatternMatcher.INSTANCE, emptyMap[AnyRef, AnyRef])
|
||||
configurationNames.foreach(rule.addConfiguration)
|
||||
rule
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import java.net.URL
|
|||
import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties
|
||||
import sbt.serialization._
|
||||
|
||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String, String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled, branchName: Option[String] = None) {
|
||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, inclusions: Seq[InclusionRule] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String, String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled, branchName: Option[String] = None) {
|
||||
override def toString: String =
|
||||
organization + ":" + name + ":" + revision +
|
||||
(configurations match { case Some(s) => ":" + s; case None => "" }) +
|
||||
|
|
@ -70,10 +70,10 @@ final case class ModuleID(organization: String, name: String, revision: String,
|
|||
* Applies the provided exclusions to dependencies of this module. Note that only exclusions that specify
|
||||
* both the exact organization and name and nothing else will be included in a pom.xml.
|
||||
*/
|
||||
def excludeAll(rules: ExclusionRule*) = copy(exclusions = this.exclusions ++ rules)
|
||||
def excludeAll(rules: InclExclRule*) = copy(exclusions = this.exclusions ++ rules)
|
||||
|
||||
/** Excludes the dependency with organization `org` and `name` from being introduced by this dependency during resolution. */
|
||||
def exclude(org: String, name: String) = excludeAll(ExclusionRule(org, name))
|
||||
def exclude(org: String, name: String) = excludeAll(InclExclRule(org, name))
|
||||
|
||||
/**
|
||||
* Adds extra attributes for this module. All keys are prefixed with `e:` if they are not already so prefixed.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package sbt
|
||||
|
||||
package object librarymanagement {
|
||||
type ExclusionRule = InclExclRule
|
||||
val ExclusionRule = InclExclRule
|
||||
|
||||
type InclusionRule = InclExclRule
|
||||
val InclusionRule = InclExclRule
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
|
||||
<info organisation="com.test" module="module-with-srcs" revision="0.1.00" status="release" publication="20160107130136">
|
||||
<description>
|
||||
Just a test module that publishes both a binary jar and a src jar in the 'compile' configuration.
|
||||
</description>
|
||||
</info>
|
||||
<configurations>
|
||||
<conf name="compile" visibility="public" description=""/>
|
||||
<conf name="runtime" visibility="public" description="" extends="compile"/>
|
||||
<conf name="test" visibility="public" description="" extends="runtime"/>
|
||||
<conf name="provided" visibility="public" description=""/>
|
||||
<conf name="optional" visibility="public" description=""/>
|
||||
<conf name="default" visibility="public" description="" extends="runtime"/>
|
||||
<conf name="pom" visibility="public" description=""/>
|
||||
</configurations>
|
||||
<publications>
|
||||
<artifact name="libmodule" type="jar" ext="jar" conf="compile"/>
|
||||
<artifact name="libmodule-source" type="src" ext="jar" conf="compile"/>
|
||||
</publications>
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
</ivy-module>
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -58,10 +58,14 @@ trait BaseIvySpecification extends UnitSpec {
|
|||
new InlineIvyConfiguration(paths, resolvers, other, moduleConfs, off, None, check, Some(resCacheDir), uo, log)
|
||||
}
|
||||
|
||||
def makeUpdateConfiguration: UpdateConfiguration = {
|
||||
val retrieveConfig = new RetrieveConfiguration(currentManaged, Resolver.defaultRetrievePattern, false)
|
||||
new UpdateConfiguration(Some(retrieveConfig), false, UpdateLogging.Full, ArtifactTypeFilter.forbid(Set("src", "doc")))
|
||||
}
|
||||
|
||||
def ivyUpdateEither(module: IvySbt#Module): Either[UnresolvedWarning, UpdateReport] = {
|
||||
// IO.delete(currentTarget)
|
||||
val retrieveConfig = new RetrieveConfiguration(currentManaged, Resolver.defaultRetrievePattern, false)
|
||||
val config = new UpdateConfiguration(Some(retrieveConfig), false, UpdateLogging.Full)
|
||||
val config = makeUpdateConfiguration
|
||||
IvyActions.updateEither(module, config, UnresolvedWarningConfiguration(), LogicalClock.unknown, Some(currentDependency), log)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
package sbt.internal.librarymanagement
|
||||
|
||||
import org.scalatest.Inside
|
||||
import sbt.internal.librarymanagement.impl.DependencyBuilders
|
||||
import sbt.librarymanagement._
|
||||
|
||||
class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders {
|
||||
|
||||
val ourModuleID = ModuleID("com.example", "foo", "0.1.0", Some("compile"))
|
||||
|
||||
def makeModuleForDepWithSources = {
|
||||
// By default a module seems to only have [compile, test, runtime], yet deps automatically map to
|
||||
// default->compile(default) ... so I guess we have to explicitly use e.g. "compile"
|
||||
val dep = "com.test" % "module-with-srcs" % "0.1.00" % "compile"
|
||||
|
||||
module(
|
||||
ourModuleID,
|
||||
Seq(dep), None //, UpdateOptions().withCachedResolution(true)
|
||||
)
|
||||
}
|
||||
|
||||
"ivyUpdate from ivy repository" should "resolve only binary artifact from module which also contains a sources artifact under the same configuration." in {
|
||||
cleanIvyCache()
|
||||
|
||||
val m = makeModuleForDepWithSources
|
||||
|
||||
val report = ivyUpdate(m)
|
||||
|
||||
import Inside._
|
||||
inside(report.configuration("compile").map(_.modules)) {
|
||||
case Some(Seq(mr)) =>
|
||||
inside(mr.artifacts) {
|
||||
case Seq((ar, _)) =>
|
||||
ar.`type` shouldBe "jar"
|
||||
ar.extension shouldBe "jar"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "resolve only sources artifact of an acceptable artifact type, \"src\", when calling updateClassifiers." in {
|
||||
cleanIvyCache()
|
||||
|
||||
val m = makeModuleForDepWithSources
|
||||
|
||||
// the "default" configuration used in updateEither.
|
||||
val c = makeUpdateConfiguration
|
||||
|
||||
val ivyScala = m.moduleSettings.ivyScala
|
||||
val srcTypes = Set("src")
|
||||
val docTypes = Set("javadoc")
|
||||
// These will be the default classifiers that SBT should try, in case a dependency is Maven.
|
||||
// In this case though, they will be tried and should fail gracefully - only the
|
||||
val attemptedClassifiers = Seq("sources", "javadoc")
|
||||
|
||||
// The dep that we want to get the "classifiers" (i.e. sources / docs) for.
|
||||
// We know it has only one source artifact in the "compile" configuration.
|
||||
val dep = "com.test" % "module-with-srcs" % "0.1.00" % "compile"
|
||||
|
||||
val clMod = {
|
||||
import language.implicitConversions
|
||||
implicit val key = (m: ModuleID) => (m.organization, m.name, m.revision)
|
||||
val externalModules = Seq(dep)
|
||||
// Note: need to extract ourModuleID so we can plug it in here, can't fish it back out of the IvySbt#Module (`m`)
|
||||
GetClassifiersModule(ourModuleID, externalModules, Seq(Configurations.Compile), attemptedClassifiers)
|
||||
}
|
||||
|
||||
val gcm = GetClassifiersConfiguration(clMod, Map.empty, c.copy(artifactFilter = c.artifactFilter.invert), ivyScala, srcTypes, docTypes)
|
||||
|
||||
val report2 = IvyActions.updateClassifiers(m.owner, gcm, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log)
|
||||
|
||||
import Inside._
|
||||
inside(report2.configuration("compile").map(_.modules)) {
|
||||
case Some(Seq(mr)) =>
|
||||
inside(mr.artifacts) {
|
||||
case Seq((ar, _)) =>
|
||||
ar.name shouldBe "libmodule-source"
|
||||
ar.`type` shouldBe "src"
|
||||
ar.extension shouldBe "jar"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override lazy val resolvers: Seq[Resolver] = Seq(testIvy)
|
||||
|
||||
lazy val testIvy = {
|
||||
val repoUrl = getClass.getResource("/test-ivy-repo")
|
||||
Resolver.url("Test Repo", repoUrl)(Resolver.ivyStylePatterns)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue