use lm-coursier-shaded

This uses lm-coursier-shaded, and follows along the changes in https://github.com/coursier/sbt-coursier/pull/58.
This commit is contained in:
Eugene Yokota 2019-04-26 17:33:14 -04:00
parent 258a8930a5
commit f354a626c7
12 changed files with 570 additions and 460 deletions

View File

@ -594,7 +594,7 @@ lazy val mainProj = (project in file("main"))
scalaXml.value ++
Seq(launcherInterface) ++
log4jDependencies ++
Seq(scalaCacheCaffeine, lmCousier)
Seq(scalaCacheCaffeine, lmCoursierShaded)
},
Compile / scalacOptions -= "-Xfatal-warnings",
managedSourceDirectories in Compile +=

View File

@ -12,7 +12,7 @@ import java.net.{ URI, URL, URLClassLoader }
import java.util.Optional
import java.util.concurrent.{ Callable, TimeUnit }
import coursier.core.{ Configuration => CConfiguration }
import lmcoursier.definitions.{ 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 }
@ -230,7 +230,7 @@ object Defaults extends BuildCommon {
// coursier settings
csrExtraCredentials :== Nil,
csrLogger :== None,
csrCachePath :== coursier.cache.CacheDefaults.location,
csrCachePath :== LMCoursier.defaultCacheLocation,
csrMavenProfiles :== Set.empty,
)
@ -2136,7 +2136,7 @@ object Classpaths {
val old = csrCachePath.value
val ip = ivyPaths.value
val defaultIvyCache = bootIvyHome(appConfiguration.value)
if (old != coursier.cache.CacheDefaults.location) old
if (old != LMCoursier.defaultCacheLocation) old
else if (ip.ivyHome == defaultIvyCache) old
else
ip.ivyHome match {
@ -2406,13 +2406,13 @@ object Classpaths {
} tag (Tags.Update, Tags.Network)).value,
)
) ++ Seq(
csrProject := LMCoursier.coursierProjectTask.value,
csrProject := CoursierInputsTasks.coursierProjectTask.value,
csrConfiguration := LMCoursier.coursierConfigurationTask(false, false).value,
csrResolvers := LMCoursier.coursierResolversTask.value,
csrRecursiveResolvers := LMCoursier.coursierRecursiveResolversTask.value,
csrResolvers := CoursierRepositoriesTasks.coursierResolversTask.value,
csrRecursiveResolvers := CoursierRepositoriesTasks.coursierRecursiveResolversTask.value,
csrSbtResolvers := LMCoursier.coursierSbtResolversTask.value,
csrInterProjectDependencies := LMCoursier.coursierInterProjectDependenciesTask.value,
csrFallbackDependencies := LMCoursier.coursierFallbackDependenciesTask.value,
csrInterProjectDependencies := CoursierInputsTasks.coursierInterProjectDependenciesTask.value,
csrFallbackDependencies := CoursierInputsTasks.coursierFallbackDependenciesTask.value,
) ++
IvyXml.generateIvyXmlSettings() ++
LMCoursier.publicationsSetting(Seq(Compile, Test).map(c => c -> CConfiguration(c.name)))

View File

@ -32,8 +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 lmcoursier.definitions.CacheLogger
import lmcoursier.{ CoursierConfiguration, FallbackDependency }
import scala.concurrent.duration.{ Duration, FiniteDuration }
import scala.xml.{ NodeSeq, Node => XNode }
@ -357,15 +357,15 @@ object Keys {
val csrCachePath = settingKey[File]("Coursier cache path").withRank(CSetting)
val csrMavenProfiles = settingKey[Set[String]]("").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 csrProject = taskKey[lmcoursier.definitions.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 csrInterProjectDependencies = taskKey[Seq[lmcoursier.definitions.Project]]("Projects the current project depends on, possibly transitively")
private[sbt] val csrFallbackDependencies = taskKey[Seq[FallbackDependency]]("")
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)]]("")
private[sbt] val csrExtraCredentials = taskKey[Seq[lmcoursier.credentials.Credentials]]("")
private[sbt] val csrPublications = taskKey[Seq[(lmcoursier.definitions.Configuration, lmcoursier.definitions.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)

View File

@ -758,6 +758,28 @@ object Project extends ProjectExtra {
def updateExtraBuilds(s: State, f: List[URI] => List[URI]): State =
setExtraBuilds(s, f(extraBuilds(s)))
// used by Coursier integration
private[sbt] def transitiveInterDependencies(
state: State,
projectRef: ProjectRef
): Seq[ProjectRef] = {
def dependencies(map: Map[ProjectRef, Seq[ProjectRef]], id: ProjectRef): Set[ProjectRef] = {
def helper(map: Map[ProjectRef, Seq[ProjectRef]], acc: Set[ProjectRef]): Set[ProjectRef] =
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: Map[ProjectRef, Seq[ProjectRef]] =
(for {
(p, ref) <- Project.structure(state).allProjectPairs
} yield ref -> p.dependencies.map(_.project)).toMap
val deps = dependencies(allProjectsDeps.toMap, projectRef)
Project.structure(state).allProjectRefs.filter(p => deps(p))
}
object LoadAction extends Enumeration {
val Return, Current, Plugins = Value
}

View File

@ -38,6 +38,12 @@ final class BuildStructure(
case (build, unit) => refs(build, unit.defined.values.toSeq)
}
def allProjectRefs(build: URI): Seq[ProjectRef] = refs(build, allProjects(build))
def allProjectPairs: Seq[(ResolvedProject, ProjectRef)] =
for {
(build, unit) <- units.toSeq
p: ResolvedProject <- unit.defined.values.toSeq
} yield (p, ProjectRef(build, p.id))
val extra: BuildUtil[ResolvedProject] = BuildUtil(root, units, index.keyIndex, data)
private[this] def refs(build: URI, projects: Seq[ResolvedProject]): Seq[ProjectRef] =
projects.map { p =>

View File

@ -8,54 +8,15 @@
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.io.IO
import java.io.File
import lmcoursier.definitions.{ Classifier, Configuration => CConfiguration }
import lmcoursier._
import sbt.librarymanagement._
import Keys._
import sbt.librarymanagement.ivy.{
FileCredentials,
Credentials,
DirectCredentials => IvyDirectCredentials
}
import sbt.ScopeFilter.Make._
import scala.collection.JavaConverters._
import sbt.internal.librarymanagement.{ CoursierArtifactsTasks, CoursierInputsTasks }
private[sbt] object LMCoursier {
def coursierProjectTask: Def.Initialize[sbt.Task[CProject]] =
Def.task {
val auOpt = apiURL.value
val proj = Inputs.coursierProject(
projectID.value,
allDependencies.value,
excludeDependencies.value,
ivyConfigurations.value,
scalaVersion.value,
scalaBinaryVersion.value,
streams.value.log
)
auOpt match {
case Some(au) =>
val props = proj.properties :+ ("info.apiURL" -> au.toString)
proj.copy(properties = props)
case _ => proj
}
}
def defaultCacheLocation: File = CoursierDependencyResolution.defaultCacheLocation
def coursierConfigurationTask(
withClassifiers: Boolean,
@ -90,7 +51,7 @@ private[sbt] object LMCoursier {
_.overrideScalaVersion
)
val profiles = csrMavenProfiles.value
val credentials = credentialsTask.value
val credentials = CoursierInputsTasks.credentialsTask.value
val createLogger = csrLogger.value
@ -107,11 +68,10 @@ private[sbt] object LMCoursier {
.withInterProjectDependencies(interProjectDependencies.toVector)
.withFallbackDependencies(fallbackDeps.toVector)
.withExcludeDependencies(
excludeDeps.toVector.sorted
.map {
case (o, n) =>
(o.value, n.value)
}
excludeDeps.toVector.map {
case (o, n) =>
(o.value, n.value)
}.sorted
)
.withAutoScalaLibrary(autoScalaLib)
.withSbtScalaJars(sbtBootJars.toVector)
@ -129,80 +89,6 @@ private[sbt] object LMCoursier {
}
}
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 result0 = resultTask(bootResOpt, overrideFlag).value
val reorderResolvers = true // coursierReorderResolvers.value
val keepPreloaded = false // coursierKeepPreloaded.value
val paths = ivyPaths.value
val result1 =
if (reorderResolvers) ResolutionParams.reorderResolvers(result0)
else result0
val result2 =
paths.ivyHome match {
case Some(ivyHome) =>
val ivyHomeUri = IO.toURI(ivyHome).getSchemeSpecificPart
result1 map {
case r: FileRepository =>
val ivyPatterns = r.patterns.ivyPatterns map {
_.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri)
}
val artifactPatterns = r.patterns.artifactPatterns map {
_.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri)
}
val p =
r.patterns.withIvyPatterns(ivyPatterns).withArtifactPatterns(artifactPatterns)
r.withPatterns(p)
case r => r
}
case _ => result1
}
if (keepPreloaded) result2
else
result2.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 {
@ -234,314 +120,7 @@ private[sbt] object LMCoursier {
}
}
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))
csrPublications := CoursierArtifactsTasks.coursierPublicationsTask(packageConfigs: _*).value
}
}

View File

@ -8,7 +8,7 @@
package sbt
package internal
import coursier.lmcoursier.CoursierDependencyResolution
import lmcoursier.CoursierDependencyResolution
import java.io.File
import sbt.internal.librarymanagement._
import sbt.internal.util.{ ConsoleAppender, LogOption }

View File

@ -0,0 +1,157 @@
/*
* 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 lmcoursier.definitions.{
Classifier,
Configuration => CConfiguration,
Extension => CExtension,
Publication => CPublication,
Type => CType
}
import sbt.librarymanagement._
import sbt.Keys._
object CoursierArtifactsTasks {
def coursierPublicationsTask(
configsMap: (sbt.librarymanagement.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 = CrossVersion(projId.crossVersion, sv, sbv)
.fold(artifact.name)(_(artifact.name))
CPublication(
name,
CType(artifact.`type`),
CExtension(artifact.extension),
artifact.classifier.fold(Classifier(""))(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
}
}

View File

@ -0,0 +1,235 @@
/*
* 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 sbt.librarymanagement._
import sbt.util.Logger
import sbt.Keys._
import lmcoursier.definitions.{
Attributes => CAttributes,
Classifier,
Configuration => CConfiguration,
Dependency => CDependency,
// Extension => CExtension,
Info => CInfo,
Module,
ModuleName,
Organization => COrganization,
Project => CProject,
// Publication => CPublication,
Type => CType
}
import lmcoursier.credentials.DirectCredentials
import lmcoursier.{ FallbackDependency, FromSbt, Inputs }
import sbt.librarymanagement.ivy.{
FileCredentials,
Credentials,
DirectCredentials => IvyDirectCredentials
}
import sbt.ScopeFilter.Make._
import scala.collection.JavaConverters._
private[sbt] object CoursierInputsTasks {
private def coursierProject0(
projId: ModuleID,
dependencies: Seq[ModuleID],
excludeDeps: Seq[InclExclRule],
configurations: Seq[sbt.librarymanagement.Configuration],
sv: String,
sbv: String,
log: Logger
): CProject = {
val exclusions0 = Inputs.exclusions(excludeDeps, sv, sbv, log)
val configMap = Inputs.configExtends(configurations)
val proj = FromSbt.project(
projId,
dependencies,
configMap,
sv,
sbv
)
proj.copy(
dependencies = proj.dependencies.map {
case (config, dep) =>
(config, dep.copy(exclusions = dep.exclusions ++ exclusions0))
}
)
}
private[sbt] def coursierProjectTask: Def.Initialize[sbt.Task[CProject]] =
Def.task {
val auOpt = apiURL.value
val proj = coursierProject0(
projectID.value,
allDependencies.value,
allExcludeDependencies.value,
// should projectID.configurations be used instead?
ivyConfigurations.value,
scalaVersion.value,
scalaBinaryVersion.value,
streams.value.log
)
auOpt match {
case Some(au) =>
val props = proj.properties :+ ("info.apiURL" -> au.toString)
proj.copy(properties = props)
case _ => proj
}
}
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(Inputs.ivyXmlMappings)
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(""))
art.getConfigurations.map(CConfiguration(_)).toVector.map { conf =>
conf -> attr
}
}.toMap
c => m.getOrElse(c, CAttributes(CType(""), Classifier("")))
}
configurations.map {
case (from, to) =>
from -> dependency(to, attributes(to))
}
}
private[sbt] def coursierInterProjectDependenciesTask: Def.Initialize[sbt.Task[Seq[CProject]]] =
Def.taskDyn {
val state = sbt.Keys.state.value
val projectRef = sbt.Keys.thisProjectRef.value
val projectRefs = Project.transitiveInterDependencies(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,
Nil,
None,
Nil,
CInfo("", "", Nil, Nil, None)
)
}
projects ++ extraProjects
}
}
private[sbt] def coursierFallbackDependenciesTask
: Def.Initialize[sbt.Task[Seq[FallbackDependency]]] =
Def.taskDyn {
val state = sbt.Keys.state.value
val projectRef = sbt.Keys.thisProjectRef.value
val projects = Project.transitiveInterDependencies(state, projectRef)
Def.task {
val allDeps =
allDependencies.all(ScopeFilter(inProjects(projectRef +: projects: _*))).value.flatten
FromSbt.fallbackDependencies(
allDeps,
scalaVersion.value,
scalaBinaryVersion.value
)
}
}
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))
.withHttpsOnly(false)
.withMatchHost(true)
}
creds ++ csrExtraCredentials.value
}
}

View File

@ -0,0 +1,111 @@
/*
* 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 sbt.librarymanagement._
import sbt.Keys._
import sbt.ScopeFilter.Make._
private[sbt] object CoursierRepositoriesTasks {
private object CResolvers {
private val slowReposBase = Seq(
"https://repo.typesafe.com/",
"https://repo.scala-sbt.org/",
"http://repo.typesafe.com/",
"http://repo.scala-sbt.org/"
)
private val fastReposBase = Seq(
"http://repo1.maven.org/",
"https://repo1.maven.org/"
)
private def url(res: Resolver): Option[String] =
res match {
case m: sbt.librarymanagement.MavenRepository =>
Some(m.root)
case u: URLRepository =>
u.patterns.artifactPatterns.headOption
.orElse(u.patterns.ivyPatterns.headOption)
case _ =>
None
}
private def fastRepo(res: Resolver): Boolean =
url(res).exists(u => fastReposBase.exists(u.startsWith))
private def slowRepo(res: Resolver): Boolean =
url(res).exists(u => slowReposBase.exists(u.startsWith))
def reorderResolvers(resolvers: Seq[Resolver]): Seq[Resolver] =
if (resolvers.exists(fastRepo) && resolvers.exists(slowRepo)) {
val (slow, other) = resolvers.partition(slowRepo)
other ++ slow
} else
resolvers
}
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 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 = true // coursierKeepPreloaded.value
val result0 =
if (reorderResolvers)
CResolvers.reorderResolvers(result)
else
result
if (keepPreloaded)
result0
else
result0.filter { r =>
!r.name.startsWith("local-preloaded")
}
}
}
def coursierRecursiveResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] =
Def.taskDyn {
val state = sbt.Keys.state.value
val projectRef = sbt.Keys.thisProjectRef.value
val projects = Project.transitiveInterDependencies(state, projectRef)
Def.task {
csrResolvers.all(ScopeFilter(inProjects(projectRef +: projects: _*))).value.flatten
}
}
}

View File

@ -12,7 +12,7 @@ package librarymanagement
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.Files
import coursier.core.{ Configuration, Project }
import lmcoursier.definitions.{ Configuration, Project }
import org.apache.ivy.core.module.id.ModuleRevisionId
import Def.Setting
import sbt.Keys.{
@ -29,7 +29,7 @@ import scala.xml.{ Node, PrefixedAttribute }
object IvyXml {
import sbt.Project._
def rawContent(
private def rawContent(
currentProject: Project,
shadedConfigOpt: Option[Configuration]
): String = {
@ -47,7 +47,7 @@ object IvyXml {
}
// These are required for publish to be fine, later on.
def writeFiles(
private def writeFiles(
currentProject: Project,
shadedConfigOpt: Option[Configuration],
ivySbt: IvySbt,
@ -77,12 +77,12 @@ object IvyXml {
()
}
def content(project0: Project, shadedConfigOpt: Option[Configuration]): Node = {
private def content(project0: Project, shadedConfigOpt: Option[Configuration]): Node = {
val filterOutDependencies =
shadedConfigOpt.toSet[Configuration].flatMap { shadedConfig =>
project0.dependencies
.collect { case (`shadedConfig`, dep) => dep }
.collect { case (conf, dep) if conf.value == shadedConfig.value => dep }
}
val project: Project = project0.copy(
@ -118,8 +118,8 @@ object IvyXml {
} % infoAttrs
val confElems = project.configurations.toVector.collect {
case (name, extends0) if !shadedConfigOpt.contains(name) =>
val extends1 = shadedConfigOpt.fold(extends0)(c => extends0.filter(_ != c))
case (name, extends0) if !shadedConfigOpt.exists(_.value == name.value) =>
val extends1 = shadedConfigOpt.fold(extends0)(c => extends0.filter(_.value != c.value))
val n = <conf name={name.value} visibility="public" description="" />
if (extends1.nonEmpty)
n % <x extends={extends1.map(_.value).mkString(",")} />.attributes
@ -138,7 +138,7 @@ object IvyXml {
configs.map(_.value).mkString(",")
} />
if (pub.classifier.nonEmpty)
if (pub.classifier.value.nonEmpty)
n % <x e:classifier={pub.classifier.value} />.attributes
else
n
@ -174,7 +174,7 @@ object IvyXml {
</ivy-module>
}
def makeIvyXmlBefore[T](
private def makeIvyXmlBefore[T](
task: TaskKey[T],
shadedConfigOpt: Option[Configuration]
): Setting[Task[T]] =
@ -220,6 +220,6 @@ object IvyXml {
def generateIvyXmlSettings(
shadedConfigOpt: Option[Configuration] = None
): Seq[Setting[_]] =
(needsIvyXml ++ needsIvyXmlLocal).map(IvyXml.makeIvyXmlBefore(_, shadedConfigOpt))
(needsIvyXml ++ needsIvyXmlLocal).map(makeIvyXmlBefore(_, shadedConfigOpt))
}

View File

@ -100,8 +100,8 @@ 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 lmCoursierVersion = "1.1.0-M14-1"
val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % lmCoursierVersion
val sjsonNewScalaJson = Def.setting {
"com.eed3si9n" %% "sjson-new-scalajson" % contrabandSjsonNewVersion.value