mirror of https://github.com/sbt/sbt.git
Coursier dependency resolution integration
This adds dependency to LM implemented using Coursier. I had to copy paste a bunch of code from sbt-coursier-shared to break the dependency to sbt. `Global / useCoursier := false` or `-Dsbt.coursier=false` be used to opt-out of using Coursier for the dependency resolution.
This commit is contained in:
parent
42bc2ea04d
commit
38f94a6e31
|
|
@ -590,7 +590,12 @@ lazy val mainProj = (project in file("main"))
|
|||
if (xs exists { s => s.contains(s""""$sv"""") }) ()
|
||||
else sys.error("PluginCross.scala does not match up with the scalaVersion " + sv)
|
||||
},
|
||||
libraryDependencies ++= scalaXml.value ++ Seq(launcherInterface) ++ log4jDependencies ++ Seq(scalaCacheCaffeine),
|
||||
libraryDependencies ++= {
|
||||
scalaXml.value ++
|
||||
Seq(launcherInterface) ++
|
||||
log4jDependencies ++
|
||||
Seq(scalaCacheCaffeine, lmCousier)
|
||||
},
|
||||
Compile / scalacOptions -= "-Xfatal-warnings",
|
||||
managedSourceDirectories in Compile +=
|
||||
baseDirectory.value / "src" / "main" / "contraband-scala",
|
||||
|
|
@ -650,6 +655,7 @@ lazy val sbtProj = (project in file("sbt"))
|
|||
)
|
||||
.configure(addSbtIO, addSbtCompilerBridge)
|
||||
|
||||
/*
|
||||
lazy val sbtBig = (project in file(".big"))
|
||||
.dependsOn(sbtProj)
|
||||
.settings(
|
||||
|
|
@ -685,6 +691,7 @@ lazy val sbtBig = (project in file(".big"))
|
|||
}).transform(node).head
|
||||
},
|
||||
)
|
||||
*/
|
||||
|
||||
lazy val sbtIgnoredProblems = {
|
||||
Vector(
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import java.net.{ URI, URL, URLClassLoader }
|
|||
import java.util.Optional
|
||||
import java.util.concurrent.{ Callable, TimeUnit }
|
||||
|
||||
import coursier.core.{ Configuration => CConfiguration }
|
||||
import org.apache.ivy.core.module.descriptor.ModuleDescriptor
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||
import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition }
|
||||
|
|
@ -200,6 +201,7 @@ object Defaults extends BuildCommon {
|
|||
exportJars :== false,
|
||||
trackInternalDependencies :== TrackLevel.TrackAlways,
|
||||
exportToInternal :== TrackLevel.TrackAlways,
|
||||
useCoursier :== LibraryManagement.defaultUseCoursier,
|
||||
retrieveManaged :== false,
|
||||
retrieveManagedSync :== false,
|
||||
configurationsToRetrieve :== None,
|
||||
|
|
@ -224,7 +226,12 @@ object Defaults extends BuildCommon {
|
|||
pomAllRepositories :== false,
|
||||
pomIncludeRepository :== Classpaths.defaultRepositoryFilter,
|
||||
updateOptions := UpdateOptions(),
|
||||
forceUpdatePeriod :== None
|
||||
forceUpdatePeriod :== None,
|
||||
// coursier settings
|
||||
csrExtraCredentials :== Nil,
|
||||
csrLogger :== None,
|
||||
csrCachePath :== coursier.cache.CacheDefaults.location,
|
||||
csrMavenProfiles :== Set.empty,
|
||||
)
|
||||
|
||||
/** Core non-plugin settings for sbt builds. These *must* be on every build or the sbt engine will fail to run at all. */
|
||||
|
|
@ -2125,6 +2132,14 @@ object Classpaths {
|
|||
}).value,
|
||||
moduleName := normalizedName.value,
|
||||
ivyPaths := IvyPaths(baseDirectory.value, bootIvyHome(appConfiguration.value)),
|
||||
csrCachePath := {
|
||||
val old = csrCachePath.value
|
||||
val ip = ivyPaths.value
|
||||
val defaultIvyCache = bootIvyHome(appConfiguration.value)
|
||||
if (old != coursier.cache.CacheDefaults.location) old
|
||||
else if (ip.ivyHome == defaultIvyCache) old
|
||||
else ip.ivyHome.getOrElse(old)
|
||||
},
|
||||
dependencyCacheDirectory := {
|
||||
val st = state.value
|
||||
BuildPaths.getDependencyDirectory(st, BuildPaths.getGlobalBase(st))
|
||||
|
|
@ -2181,10 +2196,7 @@ object Classpaths {
|
|||
)
|
||||
else None
|
||||
},
|
||||
dependencyResolution := IvyDependencyResolution(
|
||||
ivyConfiguration.value,
|
||||
CustomHttp.okhttpClient.value
|
||||
),
|
||||
dependencyResolution := LibraryManagement.dependencyResolutionTask.value,
|
||||
publisher := IvyPublisher(ivyConfiguration.value, CustomHttp.okhttpClient.value),
|
||||
ivyConfiguration := mkIvyConfiguration.value,
|
||||
ivyConfigurations := {
|
||||
|
|
@ -2198,6 +2210,44 @@ object Classpaths {
|
|||
if (managedScalaInstance.value && scalaHome.value.isEmpty) Configurations.ScalaTool :: Nil
|
||||
else Nil
|
||||
},
|
||||
// Coursier needs these
|
||||
ivyConfigurations := {
|
||||
val confs = ivyConfigurations.value
|
||||
val names = confs.map(_.name).toSet
|
||||
val extraSources =
|
||||
if (names("sources"))
|
||||
None
|
||||
else
|
||||
Some(
|
||||
Configuration.of(
|
||||
id = "Sources",
|
||||
name = "sources",
|
||||
description = "",
|
||||
isPublic = true,
|
||||
extendsConfigs = Vector.empty,
|
||||
transitive = false
|
||||
)
|
||||
)
|
||||
|
||||
val extraDocs =
|
||||
if (names("docs"))
|
||||
None
|
||||
else
|
||||
Some(
|
||||
Configuration.of(
|
||||
id = "Docs",
|
||||
name = "docs",
|
||||
description = "",
|
||||
isPublic = true,
|
||||
extendsConfigs = Vector.empty,
|
||||
transitive = false
|
||||
)
|
||||
)
|
||||
|
||||
val use = useCoursier.value
|
||||
if (use) confs ++ extraSources.toSeq ++ extraDocs.toSeq
|
||||
else confs
|
||||
},
|
||||
moduleSettings := moduleSettings0.value,
|
||||
makePomConfiguration := MakePomConfiguration()
|
||||
.withFile((artifactPath in makePom).value)
|
||||
|
|
@ -2342,8 +2392,17 @@ object Classpaths {
|
|||
case Right(ur) => ur
|
||||
}
|
||||
}
|
||||
} tag (Tags.Update, Tags.Network)).value
|
||||
)
|
||||
} tag (Tags.Update, Tags.Network)).value,
|
||||
csrProject := LMCoursier.coursierProjectTask.value,
|
||||
csrConfiguration := LMCoursier.coursierConfigurationTask(false, false).value,
|
||||
csrResolvers := LMCoursier.coursierResolversTask.value,
|
||||
csrRecursiveResolvers := LMCoursier.coursierRecursiveResolversTask.value,
|
||||
csrSbtResolvers := LMCoursier.coursierSbtResolversTask.value,
|
||||
csrInterProjectDependencies := LMCoursier.coursierInterProjectDependenciesTask.value,
|
||||
csrFallbackDependencies := LMCoursier.coursierFallbackDependenciesTask.value,
|
||||
) ++
|
||||
IvyXml.generateIvyXmlSettings() ++
|
||||
LMCoursier.publicationsSetting(Seq(Compile, Test).map(c => c -> CConfiguration(c.name)))
|
||||
|
||||
val jvmBaseSettings: Seq[Setting[_]] = Seq(
|
||||
libraryDependencies ++= autoLibraryDependency(
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import sbt.librarymanagement.ivy.{ Credentials, IvyConfiguration, IvyPaths, Upda
|
|||
import sbt.testing.Framework
|
||||
import sbt.util.{ Level, Logger }
|
||||
import xsbti.compile._
|
||||
import coursier.cache.CacheLogger
|
||||
import coursier.lmcoursier.{ CoursierConfiguration, FallbackDependency }
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
import scala.xml.{ NodeSeq, Node => XNode }
|
||||
|
|
@ -351,6 +353,20 @@ object Keys {
|
|||
val fullClasspathAsJars = taskKey[Classpath]("The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies, all as JARs.")
|
||||
val internalDependencyConfigurations = settingKey[Seq[(ProjectRef, Set[String])]]("The project configurations that this configuration depends on")
|
||||
|
||||
val useCoursier = settingKey[Boolean]("Use Coursier for dependency resolution.").withRank(BSetting)
|
||||
val csrCachePath = settingKey[File]("Coursier cache path").withRank(CSetting)
|
||||
private[sbt] val csrConfiguration = taskKey[CoursierConfiguration]("General dependency management (Coursier) settings, such as the resolvers and options to use.").withRank(DTask)
|
||||
private[sbt] val csrProject = taskKey[coursier.core.Project]("")
|
||||
private[sbt] val csrResolvers = taskKey[Seq[Resolver]]("")
|
||||
private[sbt] val csrRecursiveResolvers = taskKey[Seq[Resolver]]("Resolvers of the current project, plus those of all from its inter-dependency projects")
|
||||
private[sbt] val csrSbtResolvers = taskKey[Seq[Resolver]]("Resolvers used for sbt artifacts.")
|
||||
private[sbt] val csrInterProjectDependencies = taskKey[Seq[coursier.core.Project]]("Projects the current project depends on, possibly transitively")
|
||||
private[sbt] val csrFallbackDependencies = taskKey[Seq[FallbackDependency]]("")
|
||||
private[sbt] val csrMavenProfiles = settingKey[Set[String]]("")
|
||||
private[sbt] val csrLogger = taskKey[Option[CacheLogger]]("")
|
||||
private[sbt] val csrExtraCredentials = taskKey[Seq[coursier.credentials.Credentials]]("")
|
||||
private[sbt] val csrPublications = taskKey[Seq[(coursier.core.Configuration, coursier.core.Publication)]]("")
|
||||
|
||||
val internalConfigurationMap = settingKey[Configuration => Configuration]("Maps configurations to the actual configuration used to define the classpath.").withRank(CSetting)
|
||||
val classpathConfiguration = taskKey[Configuration]("The configuration used to define the classpath.").withRank(CTask)
|
||||
val ivyConfiguration = taskKey[IvyConfiguration]("General dependency management (Ivy) settings, such as the resolvers and paths to use.").withRank(DTask)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,524 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
package internal
|
||||
|
||||
import coursier.core.{
|
||||
Attributes => CAttributes,
|
||||
Classifier,
|
||||
Configuration => CConfiguration,
|
||||
Dependency => CDependency,
|
||||
Extension => CExtension,
|
||||
Info => CInfo,
|
||||
Module,
|
||||
ModuleName,
|
||||
Organization => COrganization,
|
||||
Project => CProject,
|
||||
Publication => CPublication,
|
||||
Type => CType
|
||||
}
|
||||
import coursier.credentials.DirectCredentials
|
||||
import coursier.lmcoursier._
|
||||
import sbt.librarymanagement._
|
||||
import Keys._
|
||||
import sbt.librarymanagement.ivy.{
|
||||
FileCredentials,
|
||||
Credentials,
|
||||
DirectCredentials => IvyDirectCredentials
|
||||
}
|
||||
import sbt.ScopeFilter.Make._
|
||||
import scala.collection.JavaConverters._
|
||||
|
||||
private[sbt] object LMCoursier {
|
||||
|
||||
def coursierProjectTask: Def.Initialize[sbt.Task[CProject]] =
|
||||
Def.task {
|
||||
Inputs.coursierProject(
|
||||
projectID.value,
|
||||
allDependencies.value,
|
||||
excludeDependencies.value,
|
||||
// should projectID.configurations be used instead?
|
||||
ivyConfigurations.value,
|
||||
scalaVersion.value,
|
||||
scalaBinaryVersion.value,
|
||||
streams.value.log
|
||||
)
|
||||
}
|
||||
|
||||
def coursierConfigurationTask(
|
||||
withClassifiers: Boolean,
|
||||
sbtClassifiers: Boolean
|
||||
): Def.Initialize[Task[CoursierConfiguration]] =
|
||||
Def.taskDyn {
|
||||
val resolversTask =
|
||||
if (sbtClassifiers)
|
||||
csrSbtResolvers
|
||||
else
|
||||
csrRecursiveResolvers
|
||||
val classifiersTask: sbt.Def.Initialize[sbt.Task[Option[Seq[Classifier]]]] =
|
||||
if (withClassifiers && !sbtClassifiers)
|
||||
Def.task(Some(sbt.Keys.transitiveClassifiers.value.map(Classifier(_))))
|
||||
else
|
||||
Def.task(None)
|
||||
Def.task {
|
||||
val rs = resolversTask.value
|
||||
val scalaOrg = scalaOrganization.value
|
||||
val scalaVer = scalaVersion.value
|
||||
val interProjectDependencies = csrInterProjectDependencies.value
|
||||
val excludeDeps = Inputs.exclusions(
|
||||
excludeDependencies.value,
|
||||
scalaVer,
|
||||
scalaBinaryVersion.value,
|
||||
streams.value.log
|
||||
)
|
||||
val fallbackDeps = csrFallbackDependencies.value
|
||||
val autoScalaLib = autoScalaLibrary.value && scalaModuleInfo.value.forall(
|
||||
_.overrideScalaVersion
|
||||
)
|
||||
val profiles = csrMavenProfiles.value
|
||||
val credentials = credentialsTask.value
|
||||
|
||||
val createLogger = csrLogger.value
|
||||
|
||||
val cache = csrCachePath.value
|
||||
|
||||
val internalSbtScalaProvider = appConfiguration.value.provider.scalaProvider
|
||||
val sbtBootJars = internalSbtScalaProvider.jars()
|
||||
val sbtScalaVersion = internalSbtScalaProvider.version()
|
||||
val sbtScalaOrganization = "org.scala-lang" // always assuming sbt uses mainline scala
|
||||
val classifiers = classifiersTask.value
|
||||
val s = streams.value
|
||||
Classpaths.warnResolversConflict(rs, s.log)
|
||||
CoursierConfiguration()
|
||||
.withResolvers(rs.toVector)
|
||||
.withInterProjectDependencies(interProjectDependencies.toVector)
|
||||
.withFallbackDependencies(fallbackDeps.toVector)
|
||||
.withExcludeDependencies(
|
||||
excludeDeps.toVector.sorted
|
||||
.map {
|
||||
case (o, n) =>
|
||||
(o.value, n.value)
|
||||
}
|
||||
)
|
||||
.withAutoScalaLibrary(autoScalaLib)
|
||||
.withSbtScalaJars(sbtBootJars.toVector)
|
||||
.withSbtScalaVersion(sbtScalaVersion)
|
||||
.withSbtScalaOrganization(sbtScalaOrganization)
|
||||
.withClassifiers(classifiers.toVector.flatten.map(_.value))
|
||||
.withHasClassifiers(classifiers.nonEmpty)
|
||||
.withMavenProfiles(profiles.toVector.sorted)
|
||||
.withScalaOrganization(scalaOrg)
|
||||
.withScalaVersion(scalaVer)
|
||||
.withCredentials(credentials)
|
||||
.withLogger(createLogger)
|
||||
.withCache(cache)
|
||||
.withLog(s.log)
|
||||
}
|
||||
}
|
||||
|
||||
val credentialsTask = Def.task {
|
||||
val log = streams.value.log
|
||||
|
||||
val creds = sbt.Keys.credentials.value
|
||||
.flatMap {
|
||||
case dc: IvyDirectCredentials => List(dc)
|
||||
case fc: FileCredentials =>
|
||||
Credentials.loadCredentials(fc.path) match {
|
||||
case Left(err) =>
|
||||
log.warn(s"$err, ignoring it")
|
||||
Nil
|
||||
case Right(dc) => List(dc)
|
||||
}
|
||||
}
|
||||
.map { c =>
|
||||
DirectCredentials()
|
||||
.withHost(c.host)
|
||||
.withUsername(c.userName)
|
||||
.withPassword(c.passwd)
|
||||
.withRealm(Some(c.realm).filter(_.nonEmpty))
|
||||
}
|
||||
creds ++ csrExtraCredentials.value
|
||||
}
|
||||
|
||||
def coursierRecursiveResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] =
|
||||
Def.taskDyn {
|
||||
val state = sbt.Keys.state.value
|
||||
val projectRef = sbt.Keys.thisProjectRef.value
|
||||
|
||||
val projects = allRecursiveInterDependencies(state, projectRef)
|
||||
Def.task {
|
||||
csrResolvers.all(ScopeFilter(inProjects(projectRef +: projects: _*))).value.flatten
|
||||
}
|
||||
}
|
||||
|
||||
def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] =
|
||||
Def.taskDyn {
|
||||
val bootResOpt = bootResolvers.value
|
||||
val overrideFlag = overrideBuildResolvers.value
|
||||
Def.task {
|
||||
val result = resultTask(bootResOpt, overrideFlag).value
|
||||
val reorderResolvers = true // coursierReorderResolvers.value
|
||||
val keepPreloaded = false // coursierKeepPreloaded.value
|
||||
|
||||
val result0 =
|
||||
if (reorderResolvers)
|
||||
ResolutionParams.reorderResolvers(result)
|
||||
else
|
||||
result
|
||||
|
||||
if (keepPreloaded)
|
||||
result0
|
||||
else
|
||||
result0.filter { r =>
|
||||
!r.name.startsWith("local-preloaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val pluginIvySnapshotsBase = Resolver.SbtRepositoryRoot.stripSuffix("/") + "/ivy-snapshots"
|
||||
|
||||
def coursierSbtResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.task {
|
||||
val resolvers =
|
||||
sbt.Classpaths
|
||||
.bootRepositories(appConfiguration.value)
|
||||
.toSeq
|
||||
.flatten ++ // required because of the hack above it seems
|
||||
externalResolvers.in(updateSbtClassifiers).value
|
||||
|
||||
val pluginIvySnapshotsFound = resolvers.exists {
|
||||
case repo: URLRepository =>
|
||||
repo.patterns.artifactPatterns.headOption
|
||||
.exists(_.startsWith(pluginIvySnapshotsBase))
|
||||
case _ => false
|
||||
}
|
||||
|
||||
val resolvers0 =
|
||||
if (pluginIvySnapshotsFound && !resolvers.contains(Classpaths.sbtPluginReleases))
|
||||
resolvers :+ Classpaths.sbtPluginReleases
|
||||
else
|
||||
resolvers
|
||||
val keepPreloaded = true // coursierKeepPreloaded.value
|
||||
if (keepPreloaded)
|
||||
resolvers0
|
||||
else
|
||||
resolvers0.filter { r =>
|
||||
!r.name.startsWith("local-preloaded")
|
||||
}
|
||||
}
|
||||
|
||||
def coursierInterProjectDependenciesTask: Def.Initialize[sbt.Task[Seq[CProject]]] =
|
||||
Def.taskDyn {
|
||||
|
||||
val state = sbt.Keys.state.value
|
||||
val projectRef = sbt.Keys.thisProjectRef.value
|
||||
|
||||
val projectRefs = allRecursiveInterDependencies(state, projectRef)
|
||||
|
||||
Def.task {
|
||||
val projects = csrProject.all(ScopeFilter(inProjects(projectRefs: _*))).value
|
||||
val projectModules = projects.map(_.module).toSet
|
||||
|
||||
// this includes org.scala-sbt:global-plugins referenced from meta-builds in particular
|
||||
val extraProjects = sbt.Keys.projectDescriptors.value
|
||||
.map {
|
||||
case (k, v) =>
|
||||
moduleFromIvy(k) -> v
|
||||
}
|
||||
.filter {
|
||||
case (module, _) =>
|
||||
!projectModules(module)
|
||||
}
|
||||
.toVector
|
||||
.map {
|
||||
case (module, v) =>
|
||||
val configurations = v.getConfigurations.map { c =>
|
||||
CConfiguration(c.getName) -> c.getExtends.map(CConfiguration(_)).toSeq
|
||||
}.toMap
|
||||
val deps = v.getDependencies.flatMap(dependencyFromIvy)
|
||||
CProject(
|
||||
module,
|
||||
v.getModuleRevisionId.getRevision,
|
||||
deps,
|
||||
configurations,
|
||||
None,
|
||||
Nil,
|
||||
Nil,
|
||||
Nil,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
relocated = false,
|
||||
None,
|
||||
Nil,
|
||||
CInfo.empty
|
||||
)
|
||||
}
|
||||
|
||||
projects ++ extraProjects
|
||||
}
|
||||
}
|
||||
|
||||
def coursierFallbackDependenciesTask: Def.Initialize[sbt.Task[Seq[FallbackDependency]]] =
|
||||
Def.taskDyn {
|
||||
val s = state.value
|
||||
val projectRef = sbt.Keys.thisProjectRef.value
|
||||
|
||||
val projects = allRecursiveInterDependencies(s, projectRef)
|
||||
Def.task {
|
||||
val allDeps =
|
||||
allDependencies.all(ScopeFilter(inProjects(projectRef +: projects: _*))).value.flatten
|
||||
|
||||
FromSbt.fallbackDependencies(
|
||||
allDeps,
|
||||
scalaVersion.in(projectRef).value,
|
||||
scalaBinaryVersion.in(projectRef).value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def publicationsSetting(packageConfigs: Seq[(Configuration, CConfiguration)]): Def.Setting[_] = {
|
||||
csrPublications := coursierPublicationsTask(packageConfigs: _*).value
|
||||
}
|
||||
|
||||
def coursierPublicationsTask(
|
||||
configsMap: (Configuration, CConfiguration)*
|
||||
): Def.Initialize[sbt.Task[Seq[(CConfiguration, CPublication)]]] =
|
||||
Def.task {
|
||||
val s = sbt.Keys.state.value
|
||||
val projectRef = sbt.Keys.thisProjectRef.value
|
||||
val projId = sbt.Keys.projectID.value
|
||||
val sv = sbt.Keys.scalaVersion.value
|
||||
val sbv = sbt.Keys.scalaBinaryVersion.value
|
||||
val ivyConfs = sbt.Keys.ivyConfigurations.value
|
||||
val extracted = Project.extract(s)
|
||||
import extracted._
|
||||
|
||||
val sourcesConfigOpt =
|
||||
if (ivyConfigurations.value.exists(_.name == "sources"))
|
||||
Some(CConfiguration("sources"))
|
||||
else
|
||||
None
|
||||
|
||||
val docsConfigOpt =
|
||||
if (ivyConfigurations.value.exists(_.name == "docs"))
|
||||
Some(CConfiguration("docs"))
|
||||
else
|
||||
None
|
||||
|
||||
val sbtBinArtifacts =
|
||||
for ((config, targetConfig) <- configsMap) yield {
|
||||
|
||||
val publish = getOpt(
|
||||
publishArtifact
|
||||
.in(projectRef)
|
||||
.in(packageBin)
|
||||
.in(config)
|
||||
).getOrElse(false)
|
||||
|
||||
if (publish)
|
||||
getOpt(
|
||||
artifact
|
||||
.in(projectRef)
|
||||
.in(packageBin)
|
||||
.in(config)
|
||||
).map(targetConfig -> _)
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
val sbtSourceArtifacts =
|
||||
for ((config, targetConfig) <- configsMap) yield {
|
||||
|
||||
val publish = getOpt(
|
||||
publishArtifact
|
||||
.in(projectRef)
|
||||
.in(packageSrc)
|
||||
.in(config)
|
||||
).getOrElse(false)
|
||||
|
||||
if (publish)
|
||||
getOpt(
|
||||
artifact
|
||||
.in(projectRef)
|
||||
.in(packageSrc)
|
||||
.in(config)
|
||||
).map(sourcesConfigOpt.getOrElse(targetConfig) -> _)
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
val sbtDocArtifacts =
|
||||
for ((config, targetConfig) <- configsMap) yield {
|
||||
|
||||
val publish =
|
||||
getOpt(
|
||||
publishArtifact
|
||||
.in(projectRef)
|
||||
.in(packageDoc)
|
||||
.in(config)
|
||||
).getOrElse(false)
|
||||
|
||||
if (publish)
|
||||
getOpt(
|
||||
artifact
|
||||
.in(projectRef)
|
||||
.in(packageDoc)
|
||||
.in(config)
|
||||
).map(docsConfigOpt.getOrElse(targetConfig) -> _)
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
val sbtArtifacts = sbtBinArtifacts ++ sbtSourceArtifacts ++ sbtDocArtifacts
|
||||
|
||||
def artifactPublication(artifact: Artifact) = {
|
||||
|
||||
val name = FromSbt.sbtCrossVersionName(
|
||||
artifact.name,
|
||||
projId.crossVersion,
|
||||
sv,
|
||||
sbv
|
||||
)
|
||||
|
||||
CPublication(
|
||||
name,
|
||||
CType(artifact.`type`),
|
||||
CExtension(artifact.extension),
|
||||
artifact.classifier.fold(Classifier.empty)(Classifier(_))
|
||||
)
|
||||
}
|
||||
|
||||
val sbtArtifactsPublication = sbtArtifacts.collect {
|
||||
case Some((config, artifact)) =>
|
||||
config -> artifactPublication(artifact)
|
||||
}
|
||||
|
||||
val stdArtifactsSet = sbtArtifacts.flatMap(_.map { case (_, a) => a }.toSeq).toSet
|
||||
|
||||
// Second-way of getting artifacts from SBT
|
||||
// No obvious way of getting the corresponding publishArtifact value for the ones
|
||||
// only here, it seems.
|
||||
val extraSbtArtifacts = getOpt(
|
||||
sbt.Keys.artifacts
|
||||
.in(projectRef)
|
||||
).getOrElse(Nil)
|
||||
.filterNot(stdArtifactsSet)
|
||||
|
||||
// Seems that SBT does that - if an artifact has no configs,
|
||||
// it puts it in all of them. See for example what happens to
|
||||
// the standalone JAR artifact of the coursier cli module.
|
||||
def allConfigsIfEmpty(configs: Iterable[ConfigRef]): Iterable[ConfigRef] =
|
||||
if (configs.isEmpty) ivyConfs.filter(_.isPublic).map(c => ConfigRef(c.name)) else configs
|
||||
|
||||
val extraSbtArtifactsPublication = for {
|
||||
artifact <- extraSbtArtifacts
|
||||
config <- allConfigsIfEmpty(artifact.configurations.map(x => ConfigRef(x.name)))
|
||||
// FIXME If some configurations from artifact.configurations are not public, they may leak here :\
|
||||
} yield CConfiguration(config.name) -> artifactPublication(artifact)
|
||||
|
||||
sbtArtifactsPublication ++ extraSbtArtifactsPublication
|
||||
}
|
||||
|
||||
private def moduleFromIvy(id: org.apache.ivy.core.module.id.ModuleRevisionId): Module =
|
||||
Module(
|
||||
COrganization(id.getOrganisation),
|
||||
ModuleName(id.getName),
|
||||
id.getExtraAttributes.asScala.map {
|
||||
case (k0, v0) => k0.asInstanceOf[String] -> v0.asInstanceOf[String]
|
||||
}.toMap
|
||||
)
|
||||
|
||||
private def dependencyFromIvy(
|
||||
desc: org.apache.ivy.core.module.descriptor.DependencyDescriptor
|
||||
): Seq[(CConfiguration, CDependency)] = {
|
||||
|
||||
val id = desc.getDependencyRevisionId
|
||||
val module = moduleFromIvy(id)
|
||||
val exclusions = desc.getAllExcludeRules.map { rule =>
|
||||
// we're ignoring rule.getConfigurations and rule.getMatcher here
|
||||
val modId = rule.getId.getModuleId
|
||||
// we're ignoring modId.getAttributes here
|
||||
(COrganization(modId.getOrganisation), ModuleName(modId.getName))
|
||||
}.toSet
|
||||
|
||||
val configurations = desc.getModuleConfigurations.toVector
|
||||
.flatMap(s => coursier.ivy.IvyXml.mappings(s))
|
||||
|
||||
def dependency(conf: CConfiguration, attr: CAttributes) = CDependency(
|
||||
module,
|
||||
id.getRevision,
|
||||
conf,
|
||||
exclusions,
|
||||
attr,
|
||||
optional = false,
|
||||
desc.isTransitive
|
||||
)
|
||||
|
||||
val attributes: CConfiguration => CAttributes = {
|
||||
|
||||
val artifacts = desc.getAllDependencyArtifacts
|
||||
|
||||
val m = artifacts.toVector.flatMap { art =>
|
||||
val attr = CAttributes(CType(art.getType), Classifier.empty)
|
||||
art.getConfigurations.map(CConfiguration(_)).toVector.map { conf =>
|
||||
conf -> attr
|
||||
}
|
||||
}.toMap
|
||||
|
||||
c => m.getOrElse(c, CAttributes.empty)
|
||||
}
|
||||
|
||||
configurations.map {
|
||||
case (from, to) =>
|
||||
from -> dependency(to, attributes(to))
|
||||
}
|
||||
}
|
||||
|
||||
private def resultTask(
|
||||
bootResOpt: Option[Seq[Resolver]],
|
||||
overrideFlag: Boolean
|
||||
): Def.Initialize[sbt.Task[Seq[Resolver]]] =
|
||||
bootResOpt.filter(_ => overrideFlag) match {
|
||||
case Some(r) => Def.task(r)
|
||||
case None =>
|
||||
Def.taskDyn {
|
||||
val extRes = externalResolvers.value
|
||||
val isSbtPlugin = sbtPlugin.value
|
||||
if (isSbtPlugin)
|
||||
Def.task {
|
||||
Seq(
|
||||
sbtResolver.value,
|
||||
Classpaths.sbtPluginReleases
|
||||
) ++ extRes
|
||||
} else
|
||||
Def.task(extRes)
|
||||
}
|
||||
}
|
||||
|
||||
def allRecursiveInterDependencies(state: sbt.State, projectRef: sbt.ProjectRef) = {
|
||||
def dependencies(map: Map[String, Seq[String]], id: String): Set[String] = {
|
||||
|
||||
def helper(map: Map[String, Seq[String]], acc: Set[String]): Set[String] =
|
||||
if (acc.exists(map.contains)) {
|
||||
val (kept, rem) = map.partition { case (k, _) => acc(k) }
|
||||
helper(rem, acc ++ kept.valuesIterator.flatten)
|
||||
} else
|
||||
acc
|
||||
|
||||
helper(map - id, map.getOrElse(id, Nil).toSet)
|
||||
}
|
||||
|
||||
val allProjectsDeps =
|
||||
for (p <- Project.structure(state).allProjects)
|
||||
yield p.id -> p.dependencies.map(_.project.project)
|
||||
|
||||
val deps = dependencies(allProjectsDeps.toMap, projectRef.project)
|
||||
|
||||
Project.structure(state).allProjectRefs.filter(p => deps(p.project))
|
||||
}
|
||||
}
|
||||
|
|
@ -5,12 +5,15 @@
|
|||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal
|
||||
package sbt
|
||||
package internal
|
||||
|
||||
import coursier.lmcoursier.CoursierDependencyResolution
|
||||
import java.io.File
|
||||
|
||||
import sbt.internal.librarymanagement._
|
||||
import sbt.internal.util.{ ConsoleAppender, LogOption }
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.ivy.IvyDependencyResolution
|
||||
import sbt.librarymanagement.syntax._
|
||||
import sbt.util.{ CacheStore, CacheStoreFactory, Logger, Tracked }
|
||||
import sbt.io.IO
|
||||
|
|
@ -19,6 +22,43 @@ private[sbt] object LibraryManagement {
|
|||
|
||||
private type UpdateInputs = (Long, ModuleSettings, UpdateConfiguration)
|
||||
|
||||
def defaultUseCoursier: Boolean = {
|
||||
val coursierOpt = sys.props
|
||||
.get("sbt.coursier")
|
||||
.flatMap(
|
||||
str =>
|
||||
ConsoleAppender.parseLogOption(str) match {
|
||||
case LogOption.Always => Some(true)
|
||||
case LogOption.Never => Some(false)
|
||||
case _ => None
|
||||
}
|
||||
)
|
||||
val ivyOpt = sys.props
|
||||
.get("sbt.ivy")
|
||||
.flatMap(
|
||||
str =>
|
||||
ConsoleAppender.parseLogOption(str) match {
|
||||
case LogOption.Always => Some(true)
|
||||
case LogOption.Never => Some(false)
|
||||
case _ => None
|
||||
}
|
||||
)
|
||||
val notIvyOpt = ivyOpt map { !_ }
|
||||
coursierOpt.orElse(notIvyOpt).getOrElse(true)
|
||||
}
|
||||
|
||||
def dependencyResolutionTask: Def.Initialize[Task[DependencyResolution]] = Def.taskDyn {
|
||||
if (Keys.useCoursier.value) {
|
||||
Def.task { CoursierDependencyResolution(Keys.csrConfiguration.value) }
|
||||
} else
|
||||
Def.task {
|
||||
IvyDependencyResolution(
|
||||
Keys.ivyConfiguration.value,
|
||||
CustomHttp.okhttpClient.value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def cachedUpdate(
|
||||
lm: DependencyResolution,
|
||||
module: ModuleDescriptor,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
package internal
|
||||
package librarymanagement
|
||||
|
||||
import java.nio.charset.StandardCharsets.UTF_8
|
||||
import java.nio.file.Files
|
||||
|
||||
import coursier.core.{ Configuration, Project }
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||
import Def.Setting
|
||||
import sbt.Keys.{
|
||||
csrProject,
|
||||
csrPublications,
|
||||
publishLocalConfiguration,
|
||||
publishConfiguration,
|
||||
useCoursier
|
||||
}
|
||||
import sbt.librarymanagement.PublishConfiguration
|
||||
import scala.collection.JavaConverters._
|
||||
import scala.xml.{ Node, PrefixedAttribute }
|
||||
|
||||
object IvyXml {
|
||||
import sbt.Project._
|
||||
|
||||
def rawContent(
|
||||
currentProject: Project,
|
||||
shadedConfigOpt: Option[Configuration]
|
||||
): String = {
|
||||
|
||||
// Important: width = Int.MaxValue, so that no tag gets truncated.
|
||||
// In particular, that prevents things like <foo /> to be split to
|
||||
// <foo>
|
||||
// </foo>
|
||||
// by the pretty-printer.
|
||||
// See https://github.com/sbt/sbt/issues/3412.
|
||||
val printer = new scala.xml.PrettyPrinter(Int.MaxValue, 2)
|
||||
|
||||
"""<?xml version="1.0" encoding="UTF-8"?>""" + '\n' +
|
||||
printer.format(content(currentProject, shadedConfigOpt))
|
||||
}
|
||||
|
||||
// These are required for publish to be fine, later on.
|
||||
def writeFiles(
|
||||
currentProject: Project,
|
||||
shadedConfigOpt: Option[Configuration],
|
||||
ivySbt: IvySbt,
|
||||
log: sbt.util.Logger
|
||||
): Unit = {
|
||||
|
||||
val ivyCacheManager = ivySbt.withIvy(log)(ivy => ivy.getResolutionCacheManager)
|
||||
|
||||
val ivyModule = ModuleRevisionId.newInstance(
|
||||
currentProject.module.organization.value,
|
||||
currentProject.module.name.value,
|
||||
currentProject.version,
|
||||
currentProject.module.attributes.asJava
|
||||
)
|
||||
|
||||
val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule)
|
||||
val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule)
|
||||
|
||||
val content0 = rawContent(currentProject, shadedConfigOpt)
|
||||
cacheIvyFile.getParentFile.mkdirs()
|
||||
log.info(s"Writing Ivy file $cacheIvyFile")
|
||||
Files.write(cacheIvyFile.toPath, content0.getBytes(UTF_8))
|
||||
|
||||
// Just writing an empty file here... Are these only used?
|
||||
cacheIvyPropertiesFile.getParentFile.mkdirs()
|
||||
Files.write(cacheIvyPropertiesFile.toPath, Array.emptyByteArray)
|
||||
()
|
||||
}
|
||||
|
||||
def content(project0: Project, shadedConfigOpt: Option[Configuration]): Node = {
|
||||
|
||||
val filterOutDependencies =
|
||||
shadedConfigOpt.toSet[Configuration].flatMap { shadedConfig =>
|
||||
project0.dependencies
|
||||
.collect { case (`shadedConfig`, dep) => dep }
|
||||
}
|
||||
|
||||
val project: Project = project0.copy(
|
||||
dependencies = project0.dependencies.collect {
|
||||
case p @ (_, dep) if !filterOutDependencies(dep) => p
|
||||
}
|
||||
)
|
||||
|
||||
val infoAttrs = project.module.attributes.foldLeft[xml.MetaData](xml.Null) {
|
||||
case (acc, (k, v)) =>
|
||||
new PrefixedAttribute("e", k, v, acc)
|
||||
}
|
||||
|
||||
val licenseElems = project.info.licenses.map {
|
||||
case (name, urlOpt) =>
|
||||
val n = <license name={name} />
|
||||
|
||||
urlOpt.fold(n) { url =>
|
||||
n % <x url={url} />.attributes
|
||||
}
|
||||
}
|
||||
|
||||
val infoElem = {
|
||||
<info
|
||||
organisation={project.module.organization.value}
|
||||
module={project.module.name.value}
|
||||
revision={project.version}
|
||||
>
|
||||
{licenseElems}
|
||||
<description>{project.info.description}</description>
|
||||
</info>
|
||||
} % infoAttrs
|
||||
|
||||
val confElems = project.configurations.toVector.collect {
|
||||
case (name, extends0) if !shadedConfigOpt.contains(name) =>
|
||||
val extends1 = shadedConfigOpt.fold(extends0)(c => extends0.filter(_ != c))
|
||||
val n = <conf name={name.value} visibility="public" description="" />
|
||||
if (extends1.nonEmpty)
|
||||
n % <x extends={extends1.map(_.value).mkString(",")} />.attributes
|
||||
else
|
||||
n
|
||||
}
|
||||
|
||||
val publications = project.publications
|
||||
.groupBy { case (_, p) => p }
|
||||
.mapValues { _.map { case (cfg, _) => cfg } }
|
||||
|
||||
val publicationElems = publications.map {
|
||||
case (pub, configs) =>
|
||||
val n =
|
||||
<artifact name={pub.name} type={pub.`type`.value} ext={pub.ext.value} conf={
|
||||
configs.map(_.value).mkString(",")
|
||||
} />
|
||||
|
||||
if (pub.classifier.nonEmpty)
|
||||
n % <x e:classifier={pub.classifier.value} />.attributes
|
||||
else
|
||||
n
|
||||
}
|
||||
|
||||
val dependencyElems = project.dependencies.toVector.map {
|
||||
case (conf, dep) =>
|
||||
val excludes = dep.exclusions.toSeq.map {
|
||||
case (org, name) =>
|
||||
<exclude org={org.value} module={name.value} name="*" type="*" ext="*" conf="" matcher="exact"/>
|
||||
}
|
||||
|
||||
val n =
|
||||
<dependency org={dep.module.organization.value} name={dep.module.name.value} rev={
|
||||
dep.version
|
||||
} conf={s"${conf.value}->${dep.configuration.value}"}>
|
||||
{excludes}
|
||||
</dependency>
|
||||
|
||||
val moduleAttrs = dep.module.attributes.foldLeft[xml.MetaData](xml.Null) {
|
||||
case (acc, (k, v)) =>
|
||||
new PrefixedAttribute("e", k, v, acc)
|
||||
}
|
||||
|
||||
n % moduleAttrs
|
||||
}
|
||||
|
||||
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
|
||||
{infoElem}
|
||||
<configurations>{confElems}</configurations>
|
||||
<publications>{publicationElems}</publications>
|
||||
<dependencies>{dependencyElems}</dependencies>
|
||||
</ivy-module>
|
||||
}
|
||||
|
||||
def makeIvyXmlBefore[T](
|
||||
task: TaskKey[T],
|
||||
shadedConfigOpt: Option[Configuration]
|
||||
): Setting[Task[T]] =
|
||||
task := task.dependsOn {
|
||||
Def.taskDyn {
|
||||
val doGen = useCoursier.value
|
||||
if (doGen)
|
||||
Def.task {
|
||||
val currentProject = {
|
||||
val proj = csrProject.value
|
||||
val publications = csrPublications.value
|
||||
proj.copy(publications = publications)
|
||||
}
|
||||
IvyXml.writeFiles(
|
||||
currentProject,
|
||||
shadedConfigOpt,
|
||||
sbt.Keys.ivySbt.value,
|
||||
sbt.Keys.streams.value.log
|
||||
)
|
||||
} else
|
||||
Def.task(())
|
||||
}
|
||||
}.value
|
||||
|
||||
private lazy val needsIvyXmlLocal = Seq(publishLocalConfiguration) ++ getPubConf(
|
||||
"makeIvyXmlLocalConfiguration"
|
||||
)
|
||||
private lazy val needsIvyXml = Seq(publishConfiguration) ++ getPubConf(
|
||||
"makeIvyXmlConfiguration"
|
||||
)
|
||||
|
||||
private[this] def getPubConf(method: String): List[TaskKey[PublishConfiguration]] =
|
||||
try {
|
||||
val cls = sbt.Keys.getClass
|
||||
val m = cls.getMethod(method)
|
||||
val task = m.invoke(sbt.Keys).asInstanceOf[TaskKey[PublishConfiguration]]
|
||||
List(task)
|
||||
} catch {
|
||||
case _: Throwable => // FIXME Too wide
|
||||
Nil
|
||||
}
|
||||
|
||||
def generateIvyXmlSettings(
|
||||
shadedConfigOpt: Option[Configuration] = None
|
||||
): Seq[Setting[_]] =
|
||||
(needsIvyXml ++ needsIvyXmlLocal).map(IvyXml.makeIvyXmlBefore(_, shadedConfigOpt))
|
||||
|
||||
}
|
||||
|
|
@ -29,22 +29,7 @@ object Dependencies {
|
|||
private val utilScripted = "org.scala-sbt" %% "util-scripted" % utilVersion
|
||||
|
||||
private val libraryManagementCore = "org.scala-sbt" %% "librarymanagement-core" % lmVersion
|
||||
|
||||
private val libraryManagementImpl = {
|
||||
val lmOrganization =
|
||||
sys.props.get("sbt.build.lm.organization") match {
|
||||
case Some(impl) => impl
|
||||
case _ => "org.scala-sbt"
|
||||
}
|
||||
|
||||
val lmModuleName =
|
||||
sys.props.get("sbt.build.lm.moduleName") match {
|
||||
case Some(impl) => impl
|
||||
case _ => "librarymanagement-ivy"
|
||||
}
|
||||
|
||||
lmOrganization %% lmModuleName % lmVersion
|
||||
}
|
||||
private val libraryManagementImpl = "org.scala-sbt" %% "librarymanagement-ivy" % lmVersion
|
||||
|
||||
val launcherVersion = "1.0.4"
|
||||
val launcherInterface = "org.scala-sbt" % "launcher-interface" % launcherVersion
|
||||
|
|
@ -115,6 +100,9 @@ object Dependencies {
|
|||
def addSbtZincCompile(p: Project): Project =
|
||||
addSbtModule(p, sbtZincPath, "zincCompile", zincCompile)
|
||||
|
||||
val lmCousierVersion = "1.1.0-M14"
|
||||
val lmCousier = "io.get-coursier" %% "lm-coursier" % lmCousierVersion
|
||||
|
||||
val sjsonNewScalaJson = Def.setting {
|
||||
"com.eed3si9n" %% "sjson-new-scalajson" % contrabandSjsonNewVersion.value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ def retrieveID = org % "test-retrieve" % "2.0"
|
|||
|
||||
// check that the test class is on the compile classpath, either because it was compiled or because it was properly retrieved
|
||||
def checkTask(classpath: TaskKey[Classpath]) = Def task {
|
||||
val loader = ClasspathUtilities.toLoader((classpath in Compile).value.files, scalaInstance.value.loader)
|
||||
val deps = libraryDependencies.value
|
||||
val cp = (classpath in Compile).value.files
|
||||
val loader = ClasspathUtilities.toLoader(cp, scalaInstance.value.loader)
|
||||
try { Class.forName("test.Test", false, loader); () }
|
||||
catch { case _: ClassNotFoundException | _: NoClassDefFoundError => sys.error("Dependency not retrieved properly") }
|
||||
catch { case _: ClassNotFoundException | _: NoClassDefFoundError => sys.error(s"Dependency not retrieved properly: $deps, $cp") }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue