mirror of https://github.com/sbt/sbt.git
[2.x] refactor: Extract lm-ivy to separate sbt-ivy plugin module (#8873)
Step 5 of #7640 — removes the compile-time dependency on lm-ivy from main/ by creating a standalone sbt-ivy plugin module. - Create new sbt-ivy/ subproject with IvyDependencyPlugin AutoPlugin that provides all Ivy-specific functionality (ivySbt, ivyModule, ivyConfiguration, publisher, projectDescriptors, deliver/makeIvyXml) - Move IvyXml.scala from main/ to sbt-ivy/
This commit is contained in:
parent
4f4bc374f6
commit
d71fe5b7a3
|
|
@ -156,6 +156,7 @@ jobs:
|
||||||
./sbt -v --client "scripted dependency-management/* project-load/* project-matrix/* java/* run/*"
|
./sbt -v --client "scripted dependency-management/* project-load/* project-matrix/* java/* run/*"
|
||||||
./sbt -v --client "scripted plugins/*"
|
./sbt -v --client "scripted plugins/*"
|
||||||
./sbt -v --client "scripted nio/*"
|
./sbt -v --client "scripted nio/*"
|
||||||
|
./sbt -v --client "scripted ivy/*"
|
||||||
- name: Build and test (4)
|
- name: Build and test (4)
|
||||||
if: ${{ matrix.jobtype == 4 }}
|
if: ${{ matrix.jobtype == 4 }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
|
||||||
24
build.sbt
24
build.sbt
|
|
@ -690,7 +690,7 @@ lazy val buildFileProj = (project in file("buildfile"))
|
||||||
libraryDependencies ++= Seq(scalaCompiler),
|
libraryDependencies ++= Seq(scalaCompiler),
|
||||||
mimaSettings,
|
mimaSettings,
|
||||||
)
|
)
|
||||||
.dependsOn(lmCore, lmIvy)
|
.dependsOn(lmCore)
|
||||||
.configure(addSbtIO, addSbtCompilerInterface, addSbtZincCompileCore)
|
.configure(addSbtIO, addSbtCompilerInterface, addSbtZincCompileCore)
|
||||||
|
|
||||||
// The main integration project for sbt. It brings all of the projects together, configures them, and provides for overriding conventions.
|
// The main integration project for sbt. It brings all of the projects together, configures them, and provides for overriding conventions.
|
||||||
|
|
@ -734,11 +734,30 @@ lazy val mainProj = (project in file("main"))
|
||||||
Compile / doc / sources := Nil,
|
Compile / doc / sources := Nil,
|
||||||
mimaSettings,
|
mimaSettings,
|
||||||
mimaBinaryIssueFilters ++= Vector(
|
mimaBinaryIssueFilters ++= Vector(
|
||||||
|
// Moved to sbt-ivy module (Step 5 of sbt#7640)
|
||||||
|
exclude[DirectMissingMethodProblem]("sbt.Classpaths.depMap"),
|
||||||
|
exclude[DirectMissingMethodProblem]("sbt.Classpaths.ivySbt0"),
|
||||||
|
exclude[DirectMissingMethodProblem]("sbt.Classpaths.mkIvyConfiguration"),
|
||||||
|
exclude[MissingClassProblem]("sbt.internal.librarymanagement.IvyXml"),
|
||||||
|
exclude[MissingClassProblem]("sbt.internal.librarymanagement.IvyXml$"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.dependsOn(lmCore, lmIvy, lmCoursierShadedPublishing)
|
.dependsOn(lmCore, lmCoursierShadedPublishing)
|
||||||
.configure(addSbtIO, addSbtCompilerInterface, addSbtZincCompileCore)
|
.configure(addSbtIO, addSbtCompilerInterface, addSbtZincCompileCore)
|
||||||
|
|
||||||
|
lazy val sbtIvyProj = (project in file("sbt-ivy"))
|
||||||
|
.dependsOn(sbtProj, lmIvy)
|
||||||
|
.settings(
|
||||||
|
testedBaseSettings,
|
||||||
|
name := "sbt-ivy",
|
||||||
|
sbtPlugin := true,
|
||||||
|
pluginCrossBuild / sbtVersion := version.value,
|
||||||
|
// TODO: Fix doc
|
||||||
|
Compile / doc / sources := Nil,
|
||||||
|
mimaPreviousArtifacts := Set.empty, // new module, no previous artifacts
|
||||||
|
)
|
||||||
|
.configure(addSbtIO)
|
||||||
|
|
||||||
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
|
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
|
||||||
// technically, we need a dependency on all of mainProj's dependencies, but we don't do that since this is strictly an integration project
|
// technically, we need a dependency on all of mainProj's dependencies, but we don't do that since this is strictly an integration project
|
||||||
// with the sole purpose of providing certain identifiers without qualification (with a package object)
|
// with the sole purpose of providing certain identifiers without qualification (with a package object)
|
||||||
|
|
@ -993,6 +1012,7 @@ def allProjects =
|
||||||
mainSettingsProj,
|
mainSettingsProj,
|
||||||
zincLmIntegrationProj,
|
zincLmIntegrationProj,
|
||||||
mainProj,
|
mainProj,
|
||||||
|
sbtIvyProj,
|
||||||
sbtProj,
|
sbtProj,
|
||||||
bundledLauncherProj,
|
bundledLauncherProj,
|
||||||
sbtClientProj,
|
sbtClientProj,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package sbt.internal.librarymanagement
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import sbt.librarymanagement.*
|
import sbt.librarymanagement.*
|
||||||
|
import sbt.librarymanagement.syntax.*
|
||||||
|
|
||||||
object UpdateClassifiersUtil {
|
object UpdateClassifiersUtil {
|
||||||
|
|
||||||
|
|
@ -76,4 +77,26 @@ object UpdateClassifiersUtil {
|
||||||
.withExplicitArtifacts(arts)
|
.withExplicitArtifacts(arts)
|
||||||
.withInclusions(Vector(InclExclRule.everything))
|
.withInclusions(Vector(InclExclRule.everything))
|
||||||
|
|
||||||
|
def extractExcludes(report: UpdateReport): Map[ModuleID, Set[String]] =
|
||||||
|
report.allMissing
|
||||||
|
.flatMap { case (_, mod, art) =>
|
||||||
|
art.classifier.map { c =>
|
||||||
|
(restrictedCopy(mod, false), c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.groupBy(_._1)
|
||||||
|
.map { (mod, pairs) => (mod, pairs.map(_._2).toSet) }
|
||||||
|
|
||||||
|
def addExcluded(
|
||||||
|
report: UpdateReport,
|
||||||
|
classifiers: Vector[String],
|
||||||
|
exclude: Map[ModuleID, Set[String]]
|
||||||
|
): UpdateReport =
|
||||||
|
report.addMissing { id =>
|
||||||
|
classifiedArtifacts(id.name, classifiers.filter(getExcluded(id, exclude)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def getExcluded(id: ModuleID, exclude: Map[ModuleID, Set[String]]): Set[String] =
|
||||||
|
exclude.getOrElse(restrictedCopy(id, false), Set.empty[String])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2023, Scala center
|
||||||
|
* Copyright 2011 - 2022, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sbt
|
||||||
|
package librarymanagement
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import sbt.io.IO
|
||||||
|
|
||||||
|
/** Credential-loading utilities that work with sbt.librarymanagement.Credentials without Ivy. */
|
||||||
|
object CredentialUtils:
|
||||||
|
|
||||||
|
def forHost(sc: Seq[Credentials], host: String): Option[Credentials.DirectCredentials] =
|
||||||
|
allDirect(sc).find(_.host == host)
|
||||||
|
|
||||||
|
def allDirect(sc: Seq[Credentials]): Seq[Credentials.DirectCredentials] =
|
||||||
|
sc.map(toDirect)
|
||||||
|
|
||||||
|
def toDirect(c: Credentials): Credentials.DirectCredentials = c match
|
||||||
|
case dc: Credentials.DirectCredentials => dc
|
||||||
|
case fc: Credentials.FileCredentials =>
|
||||||
|
loadCredentials(fc.path) match
|
||||||
|
case Left(err) => sys.error(err)
|
||||||
|
case Right(dc) => dc
|
||||||
|
|
||||||
|
def loadCredentials(path: File): Either[String, Credentials.DirectCredentials] =
|
||||||
|
if !path.exists then Left("Credentials file " + path + " does not exist")
|
||||||
|
else
|
||||||
|
val props = read(path)
|
||||||
|
for
|
||||||
|
host <- lookup(props, HostKeys, path)
|
||||||
|
user <- lookup(props, UserKeys, path)
|
||||||
|
pass <- lookup(props, PasswordKeys, path)
|
||||||
|
yield
|
||||||
|
val realm = props.keysIterator.find(RealmKeys.contains).flatMap(props.get).orNull
|
||||||
|
new Credentials.DirectCredentials(realm, host, user, pass)
|
||||||
|
|
||||||
|
private val RealmKeys = Set("realm")
|
||||||
|
private val HostKeys = List("host", "hostname")
|
||||||
|
private val UserKeys = List("user", "user.name", "username")
|
||||||
|
private val PasswordKeys = List("password", "pwd", "pass", "passwd")
|
||||||
|
|
||||||
|
private def lookup(
|
||||||
|
props: Map[String, String],
|
||||||
|
keys: List[String],
|
||||||
|
path: File
|
||||||
|
): Either[String, String] =
|
||||||
|
keys
|
||||||
|
.flatMap(props.get)
|
||||||
|
.headOption
|
||||||
|
.toRight(s"${keys.head} not specified in credentials file: $path")
|
||||||
|
|
||||||
|
import scala.jdk.CollectionConverters.*
|
||||||
|
private def read(from: File): Map[String, String] =
|
||||||
|
val properties = new java.util.Properties
|
||||||
|
IO.load(properties, from)
|
||||||
|
properties.asScala.map((k, v) => (k, v.trim)).toMap
|
||||||
|
end CredentialUtils
|
||||||
|
|
@ -14,8 +14,6 @@ import java.util.{ Optional, UUID }
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import lmcoursier.CoursierDependencyResolution
|
import lmcoursier.CoursierDependencyResolution
|
||||||
import lmcoursier.definitions.{ Configuration as CConfiguration }
|
import lmcoursier.definitions.{ Configuration as CConfiguration }
|
||||||
import org.apache.ivy.core.module.descriptor.ModuleDescriptor
|
|
||||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
|
||||||
import org.scalasbt.ipcsocket.Win32SecurityLevel
|
import org.scalasbt.ipcsocket.Win32SecurityLevel
|
||||||
import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition, parsed }
|
import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition, parsed }
|
||||||
import sbt.Keys.*
|
import sbt.Keys.*
|
||||||
|
|
@ -33,7 +31,6 @@ import sbt.internal.classpath.AlternativeZincUtil
|
||||||
import sbt.internal.inc.JavaInterfaceUtil.*
|
import sbt.internal.inc.JavaInterfaceUtil.*
|
||||||
import sbt.internal.inc.classpath.ClasspathFilter
|
import sbt.internal.inc.classpath.ClasspathFilter
|
||||||
import sbt.internal.inc.{ CompileOutput, MappedFileConverter, Stamps, ZincLmUtil, ZincUtil }
|
import sbt.internal.inc.{ CompileOutput, MappedFileConverter, Stamps, ZincLmUtil, ZincUtil }
|
||||||
import sbt.internal.librarymanagement.ivy.*
|
|
||||||
import sbt.internal.librarymanagement.mavenint.{
|
import sbt.internal.librarymanagement.mavenint.{
|
||||||
PomExtraDependencyAttributes,
|
PomExtraDependencyAttributes,
|
||||||
SbtPomExtraProperties
|
SbtPomExtraProperties
|
||||||
|
|
@ -281,7 +278,7 @@ object Defaults extends BuildCommon {
|
||||||
pomPostProcess :== idFun,
|
pomPostProcess :== idFun,
|
||||||
pomAllRepositories :== false,
|
pomAllRepositories :== false,
|
||||||
pomIncludeRepository :== Classpaths.defaultRepositoryFilter,
|
pomIncludeRepository :== Classpaths.defaultRepositoryFilter,
|
||||||
updateOptions := UpdateOptions(),
|
updateOptions := None, // overridden by IvyDependencyPlugin with UpdateOptions()
|
||||||
forceUpdatePeriod :== None,
|
forceUpdatePeriod :== None,
|
||||||
platform :== Platform.jvm,
|
platform :== Platform.jvm,
|
||||||
// coursier settings
|
// coursier settings
|
||||||
|
|
@ -2851,10 +2848,10 @@ object Classpaths {
|
||||||
val nameWithCross = crossVersion(artifact.value.name)
|
val nameWithCross = crossVersion(artifact.value.name)
|
||||||
val version = Keys.version.value
|
val version = Keys.version.value
|
||||||
val pomFile = config.file.get.getParentFile / s"$nameWithCross-$version.pom"
|
val pomFile = config.file.get.getParentFile / s"$nameWithCross-$version.pom"
|
||||||
val publisher = Keys.publisher.value
|
val pub = Keys.publisher.value
|
||||||
val ivySbt = Keys.ivySbt.value
|
val module =
|
||||||
val module = new ivySbt.Module(moduleSettings.value, appendSbtCrossVersion = true)
|
pub.moduleDescriptor(moduleSettings.value.asInstanceOf[ModuleDescriptorConfiguration])
|
||||||
publisher.makePomFile(module, config.withFile(pomFile), streams.value.log)
|
pub.makePomFile(module, config.withFile(pomFile), streams.value.log)
|
||||||
converter.toVirtualFile(pomFile.toPath)
|
converter.toVirtualFile(pomFile.toPath)
|
||||||
|
|
||||||
def ivyPublishSettings: Seq[Setting[?]] = publishGlobalDefaults ++ Seq(
|
def ivyPublishSettings: Seq[Setting[?]] = publishGlobalDefaults ++ Seq(
|
||||||
|
|
@ -2863,8 +2860,10 @@ object Classpaths {
|
||||||
makePom := Def.uncached {
|
makePom := Def.uncached {
|
||||||
val converter = fileConverter.value
|
val converter = fileConverter.value
|
||||||
val config = makePomConfiguration.value
|
val config = makePomConfiguration.value
|
||||||
val publisher = Keys.publisher.value
|
val pub = Keys.publisher.value
|
||||||
publisher.makePomFile(ivyModule.value, config, streams.value.log)
|
val module =
|
||||||
|
pub.moduleDescriptor(moduleSettings.value.asInstanceOf[ModuleDescriptorConfiguration])
|
||||||
|
pub.makePomFile(module, config, streams.value.log)
|
||||||
converter.toVirtualFile(config.file.get.toPath())
|
converter.toVirtualFile(config.file.get.toPath())
|
||||||
},
|
},
|
||||||
(makePom / packagedArtifact) := Def.uncached((makePom / artifact).value -> makePom.value),
|
(makePom / packagedArtifact) := Def.uncached((makePom / artifact).value -> makePom.value),
|
||||||
|
|
@ -3135,7 +3134,7 @@ object Classpaths {
|
||||||
makePom / artifact := Artifact.pom(moduleName.value),
|
makePom / artifact := Artifact.pom(moduleName.value),
|
||||||
projectID := defaultProjectID.value,
|
projectID := defaultProjectID.value,
|
||||||
projectID := pluginProjectID.value,
|
projectID := pluginProjectID.value,
|
||||||
projectDescriptors := Def.uncached(depMap.value),
|
projectDescriptors := Def.uncached(Map.empty[Any, Any]),
|
||||||
updateConfiguration := {
|
updateConfiguration := {
|
||||||
// Tell the UpdateConfiguration which artifact types are special (for sources and javadocs)
|
// Tell the UpdateConfiguration which artifact types are special (for sources and javadocs)
|
||||||
val specialArtifactTypes = sourceArtifactTypes.value.toSet union docArtifactTypes.value.toSet
|
val specialArtifactTypes = sourceArtifactTypes.value.toSet union docArtifactTypes.value.toSet
|
||||||
|
|
@ -3158,8 +3157,7 @@ object Classpaths {
|
||||||
else None
|
else None
|
||||||
},
|
},
|
||||||
dependencyResolution := Def.uncached(dependencyResolutionTask.value),
|
dependencyResolution := Def.uncached(dependencyResolutionTask.value),
|
||||||
publisher := Def.uncached(IvyPublisher(ivyConfiguration.value)),
|
ivyConfiguration := Def.uncached((): Any),
|
||||||
ivyConfiguration := Def.uncached(mkIvyConfiguration.value),
|
|
||||||
ivyConfigurations := {
|
ivyConfigurations := {
|
||||||
val confs = thisProject.value.configurations
|
val confs = thisProject.value.configurations
|
||||||
(confs ++ confs.map(internalConfigurationMap.value) ++ (if (autoCompilerPlugins.value)
|
(confs ++ confs.map(internalConfigurationMap.value) ++ (if (autoCompilerPlugins.value)
|
||||||
|
|
@ -3302,8 +3300,11 @@ object Classpaths {
|
||||||
overwrite = isSnapshot.value
|
overwrite = isSnapshot.value
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
ivySbt := Def.uncached(ivySbt0.value),
|
ivySbt := Def.uncached((): Any),
|
||||||
ivyModule := Def.uncached { val is = ivySbt.value; new is.Module(moduleSettings.value) },
|
ivyModule := Def.uncached((): Any),
|
||||||
|
publisher := Def.uncached(
|
||||||
|
Classpaths.defaultPublisher(dependencyResolution.value, fullResolvers.value.toVector)
|
||||||
|
),
|
||||||
allCredentials := Def.uncached(LMCoursier.allCredentialsTask.value),
|
allCredentials := Def.uncached(LMCoursier.allCredentialsTask.value),
|
||||||
transitiveUpdate := Def.uncached(transitiveUpdateTask.value),
|
transitiveUpdate := Def.uncached(transitiveUpdateTask.value),
|
||||||
updateCacheName := {
|
updateCacheName := {
|
||||||
|
|
@ -3380,7 +3381,6 @@ object Classpaths {
|
||||||
CoursierInputsTasks.coursierFallbackDependenciesTask.value
|
CoursierInputsTasks.coursierFallbackDependenciesTask.value
|
||||||
),
|
),
|
||||||
) ++
|
) ++
|
||||||
IvyXml.generateIvyXmlSettings() ++
|
|
||||||
LMCoursier.publicationsSetting(Seq(Compile, Test).map(c => c -> CConfiguration(c.name)))
|
LMCoursier.publicationsSetting(Seq(Compile, Test).map(c => c -> CConfiguration(c.name)))
|
||||||
|
|
||||||
def jvmBaseSettings: Seq[Setting[?]] = Seq(
|
def jvmBaseSettings: Seq[Setting[?]] = Seq(
|
||||||
|
|
@ -3496,11 +3496,6 @@ object Classpaths {
|
||||||
)
|
)
|
||||||
else projectID.value
|
else projectID.value
|
||||||
}
|
}
|
||||||
private[sbt] lazy val ivySbt0: Initialize[Task[IvySbt]] =
|
|
||||||
Def.task {
|
|
||||||
IvyCredentials.register(credentials.value, streams.value.log)
|
|
||||||
new IvySbt(ivyConfiguration.value)
|
|
||||||
}
|
|
||||||
def moduleSettings0: Initialize[Task[ModuleSettings]] = Def.task {
|
def moduleSettings0: Initialize[Task[ModuleSettings]] = Def.task {
|
||||||
val deps = allDependencies.value.toVector
|
val deps = allDependencies.value.toVector
|
||||||
errorInsecureProtocolInModules(deps, streams.value.log)
|
errorInsecureProtocolInModules(deps, streams.value.log)
|
||||||
|
|
@ -3536,21 +3531,6 @@ object Classpaths {
|
||||||
.resolvers
|
.resolvers
|
||||||
explicit orElse boot getOrElse externalResolvers.value
|
explicit orElse boot getOrElse externalResolvers.value
|
||||||
},
|
},
|
||||||
ivyConfiguration := Def.uncached(
|
|
||||||
InlineIvyConfiguration(
|
|
||||||
lock = Option(lock(appConfiguration.value)),
|
|
||||||
log = Option(streams.value.log),
|
|
||||||
updateOptions = UpdateOptions(),
|
|
||||||
paths = Option(ivyPaths.value),
|
|
||||||
resolvers = externalResolvers.value.toVector,
|
|
||||||
otherResolvers = Vector.empty,
|
|
||||||
moduleConfigurations = Vector.empty,
|
|
||||||
checksums = checksums.value.toVector,
|
|
||||||
managedChecksums = false,
|
|
||||||
resolutionCacheDir = Some(target.value / "resolution-cache"),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
ivySbt := Def.uncached(ivySbt0.value),
|
|
||||||
classifiersModule := Def.uncached(classifiersModuleTask.value),
|
classifiersModule := Def.uncached(classifiersModuleTask.value),
|
||||||
// Redefine scalaVersion and scalaBinaryVersion specifically for the dependency graph used for updateSbtClassifiers task.
|
// Redefine scalaVersion and scalaBinaryVersion specifically for the dependency graph used for updateSbtClassifiers task.
|
||||||
// to fix https://github.com/sbt/sbt/issues/2686
|
// to fix https://github.com/sbt/sbt/issues/2686
|
||||||
|
|
@ -3583,7 +3563,6 @@ object Classpaths {
|
||||||
.task {
|
.task {
|
||||||
val lm = dependencyResolution.value
|
val lm = dependencyResolution.value
|
||||||
val s = streams.value
|
val s = streams.value
|
||||||
val is = ivySbt.value
|
|
||||||
val mod = classifiersModule.value
|
val mod = classifiersModule.value
|
||||||
val updateConfig0 = updateConfiguration.value
|
val updateConfig0 = updateConfiguration.value
|
||||||
val updateConfig = updateConfig0
|
val updateConfig = updateConfig0
|
||||||
|
|
@ -3596,7 +3575,9 @@ object Classpaths {
|
||||||
val srcTypes = sourceArtifactTypes.value
|
val srcTypes = sourceArtifactTypes.value
|
||||||
val docTypes = docArtifactTypes.value
|
val docTypes = docArtifactTypes.value
|
||||||
val log = s.log
|
val log = s.log
|
||||||
val out = is.withIvy(log)(_.getSettings.getDefaultIvyUserDir)
|
val out = ivyPaths.value.ivyHome
|
||||||
|
.map(new File(_))
|
||||||
|
.getOrElse(new File(System.getProperty("user.home"), ".ivy2"))
|
||||||
val uwConfig = (update / unresolvedWarningConfiguration).value
|
val uwConfig = (update / unresolvedWarningConfiguration).value
|
||||||
withExcludes(out, mod.classifiers, lock(app)) { excludes =>
|
withExcludes(out, mod.classifiers, lock(app)) { excludes =>
|
||||||
// val noExplicitCheck = ivy.map(_.withCheckExplicit(false))
|
// val noExplicitCheck = ivy.map(_.withCheckExplicit(false))
|
||||||
|
|
@ -3703,9 +3684,9 @@ object Classpaths {
|
||||||
|
|
||||||
def deliverTask(config: TaskKey[PublishConfiguration]): Initialize[Task[File]] =
|
def deliverTask(config: TaskKey[PublishConfiguration]): Initialize[Task[File]] =
|
||||||
Def.task {
|
Def.task {
|
||||||
Def.unit(update.value)
|
sys.error(
|
||||||
if !useIvy.value then sys.error("deliver/makeIvyXml requires useIvy := true")
|
"deliver/makeIvyXml requires the sbt-ivy plugin. Add IvyDependencyPlugin to your project."
|
||||||
IvyActions.deliver(ivyModule.value, config.value, streams.value.log)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("Use variant without delivery key", "1.1.1")
|
@deprecated("Use variant without delivery key", "1.1.1")
|
||||||
|
|
@ -3736,16 +3717,10 @@ object Classpaths {
|
||||||
val log = streams.value.log
|
val log = streams.value.log
|
||||||
val ref = thisProjectRef.value
|
val ref = thisProjectRef.value
|
||||||
logSkipPublish(log, ref)
|
logSkipPublish(log, ref)
|
||||||
} else if (!useIvy.value) {
|
|
||||||
sys.error(
|
|
||||||
"publishOrSkip requires useIvy := true. Use publish/publishLocal for ivyless publishing."
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
val conf = config.value
|
sys.error(
|
||||||
val log = streams.value.log
|
"publishOrSkip requires the sbt-ivy plugin. Use publish/publishLocal for ivyless publishing."
|
||||||
val module = ivyModule.value
|
)
|
||||||
val publisherInterface = publisher.value
|
|
||||||
publisherInterface.publish(module, conf, log)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tag(Tags.Publish, Tags.Network)
|
.tag(Tags.Publish, Tags.Network)
|
||||||
|
|
@ -4062,17 +4037,6 @@ object Classpaths {
|
||||||
f(libraryDependencies.value)
|
f(libraryDependencies.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// can't cache deliver/publish easily since files involved are hidden behind patterns. publish will be difficult to verify target-side anyway
|
|
||||||
def cachedPublish(cacheFile: File)(g: (IvySbt#Module, PublishConfiguration) => Unit, module: IvySbt#Module, config: PublishConfiguration) => Unit =
|
|
||||||
{ case module :+: config :+: HNil =>
|
|
||||||
/* implicit val publishCache = publishIC
|
|
||||||
val f = cached(cacheFile) { (conf: IvyConfiguration, settings: ModuleSettings, config: PublishConfiguration) =>*/
|
|
||||||
g(module, config)
|
|
||||||
/*}
|
|
||||||
f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil)*/
|
|
||||||
}*/
|
|
||||||
|
|
||||||
def defaultRepositoryFilter: MavenRepository => Boolean = repo => !repo.root.startsWith("file:")
|
def defaultRepositoryFilter: MavenRepository => Boolean = repo => !repo.root.startsWith("file:")
|
||||||
|
|
||||||
def getPublishTo(repo: Option[Resolver]): Resolver =
|
def getPublishTo(repo: Option[Resolver]): Resolver =
|
||||||
|
|
@ -4195,31 +4159,62 @@ object Classpaths {
|
||||||
depProjId.withConfigurations(dep.configuration).withExplicitArtifacts(Vector.empty)
|
depProjId.withConfigurations(dep.configuration).withExplicitArtifacts(Vector.empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbt] def depMap: Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] =
|
|
||||||
import sbt.TupleSyntax.*
|
|
||||||
(buildDependencies.toTaskable, thisProjectRef.toTaskable, settingsData, streams)
|
|
||||||
.flatMapN { (bd, thisProj, data, s) =>
|
|
||||||
depMap(bd.classpathTransitiveRefs(thisProj), data, s.log)
|
|
||||||
}
|
|
||||||
|
|
||||||
private[sbt] def depMap(
|
|
||||||
projects: Seq[ProjectRef],
|
|
||||||
data: Def.Settings,
|
|
||||||
log: Logger
|
|
||||||
): Task[Map[ModuleRevisionId, ModuleDescriptor]] =
|
|
||||||
val ivyModules = projects.flatMap { proj =>
|
|
||||||
(proj / ivyModule).get(data)
|
|
||||||
}.join
|
|
||||||
ivyModules.mapN { mod =>
|
|
||||||
mod.map { _.dependencyMapping(log) }.toMap
|
|
||||||
}
|
|
||||||
|
|
||||||
def projectResolverTask: Initialize[Task[Resolver]] =
|
def projectResolverTask: Initialize[Task[Resolver]] =
|
||||||
projectDescriptors.map { m =>
|
Def.task {
|
||||||
val resolver = new ProjectResolver(ProjectResolver.InterProject, m)
|
// Stub resolver — Coursier handles inter-project deps via csrInterProjectDependencies.
|
||||||
new RawRepository(resolver, resolver.getName)
|
// Overridden by IvyDependencyPlugin with a real ProjectResolver.
|
||||||
|
new RawRepository(NoOpResolver, NoOpResolver.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object NoOpResolver:
|
||||||
|
val name = "inter-project"
|
||||||
|
override def toString: String = name
|
||||||
|
|
||||||
|
/** Default publisher that delegates moduleDescriptor to Coursier and generates POM without Ivy. */
|
||||||
|
private[sbt] def defaultPublisher(
|
||||||
|
lm: DependencyResolution,
|
||||||
|
resolvers: Vector[Resolver] = Vector.empty,
|
||||||
|
): Publisher =
|
||||||
|
Publisher(new PublisherInterface {
|
||||||
|
def moduleDescriptor(moduleSetting: ModuleDescriptorConfiguration): ModuleDescriptor =
|
||||||
|
lm.moduleDescriptor(moduleSetting)
|
||||||
|
def publish(
|
||||||
|
module: ModuleDescriptor,
|
||||||
|
configuration: PublishConfiguration,
|
||||||
|
log: Logger
|
||||||
|
): Unit =
|
||||||
|
sys.error("Ivy-based publish requires the sbt-ivy plugin or useIvy := true")
|
||||||
|
def makePomFile(
|
||||||
|
module: ModuleDescriptor,
|
||||||
|
configuration: MakePomConfiguration,
|
||||||
|
log: Logger
|
||||||
|
): java.io.File =
|
||||||
|
val file = configuration.file.getOrElse(sys.error("makePom file must be specified."))
|
||||||
|
val ms = module.moduleSettings.asInstanceOf[ModuleDescriptorConfiguration]
|
||||||
|
val mid = ms.module
|
||||||
|
val info = configuration.moduleInfo.orElse(Option(ms.moduleInfo))
|
||||||
|
val deps = module.directDependencies
|
||||||
|
val extra = configuration.extra.getOrElse(scala.xml.NodeSeq.Empty)
|
||||||
|
val confs = configuration.configurations
|
||||||
|
val scalaInfo = ms.scalaModuleInfo
|
||||||
|
val pomXml =
|
||||||
|
sbt.internal.PomGenerator.makePom(
|
||||||
|
mid,
|
||||||
|
info,
|
||||||
|
deps,
|
||||||
|
confs,
|
||||||
|
extra,
|
||||||
|
scalaInfo,
|
||||||
|
resolvers,
|
||||||
|
configuration.filterRepositories,
|
||||||
|
configuration.allRepositories,
|
||||||
|
)
|
||||||
|
val processed = configuration.process(pomXml)
|
||||||
|
scala.xml.XML.save(file.getAbsolutePath, processed, "UTF-8", xmlDecl = true)
|
||||||
|
log.info("Wrote " + file.getAbsolutePath)
|
||||||
|
file
|
||||||
|
})
|
||||||
|
|
||||||
def makeProducts: Initialize[Task[Seq[File]]] = Def.task {
|
def makeProducts: Initialize[Task[Seq[File]]] = Def.task {
|
||||||
val c = fileConverter.value
|
val c = fileConverter.value
|
||||||
val resourceDirs = resourceDirectories.value
|
val resourceDirs = resourceDirectories.value
|
||||||
|
|
@ -4247,23 +4242,6 @@ object Classpaths {
|
||||||
|
|
||||||
def internalDependencyJarsTask: Initialize[Task[Classpath]] =
|
def internalDependencyJarsTask: Initialize[Task[Classpath]] =
|
||||||
ClasspathImpl.internalDependencyJarsTask
|
ClasspathImpl.internalDependencyJarsTask
|
||||||
lazy val mkIvyConfiguration: Initialize[Task[InlineIvyConfiguration]] =
|
|
||||||
Def.task {
|
|
||||||
val (rs, other) = (fullResolvers.value.toVector, otherResolvers.value.toVector)
|
|
||||||
val s = streams.value
|
|
||||||
warnResolversConflict(rs ++: other, s.log)
|
|
||||||
errorInsecureProtocol(rs ++: other, s.log)
|
|
||||||
InlineIvyConfiguration()
|
|
||||||
.withPaths(ivyPaths.value)
|
|
||||||
.withResolvers(rs)
|
|
||||||
.withOtherResolvers(other)
|
|
||||||
.withModuleConfigurations(moduleConfigurations.value.toVector)
|
|
||||||
.withLock(lock(appConfiguration.value))
|
|
||||||
.withChecksums((update / checksums).value.toVector)
|
|
||||||
.withResolutionCacheDir(target.value / "resolution-cache")
|
|
||||||
.withUpdateOptions(updateOptions.value)
|
|
||||||
.withLog(s.log)
|
|
||||||
}
|
|
||||||
|
|
||||||
def interSort(
|
def interSort(
|
||||||
projectRef: ProjectRef,
|
projectRef: ProjectRef,
|
||||||
|
|
@ -4474,7 +4452,7 @@ object Classpaths {
|
||||||
try {
|
try {
|
||||||
app.provider.scalaProvider.launcher.checksums.toVector
|
app.provider.scalaProvider.launcher.checksums.toVector
|
||||||
} catch {
|
} catch {
|
||||||
case _: NoSuchMethodError => IvySbt.DefaultChecksums
|
case _: NoSuchMethodError => Vector("sha1", "md5")
|
||||||
}
|
}
|
||||||
|
|
||||||
def isOverrideRepositories(app: xsbti.AppConfiguration): Boolean =
|
def isOverrideRepositories(app: xsbti.AppConfiguration): Boolean =
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,13 @@ import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import lmcoursier.definitions.{ CacheLogger, ModuleMatchers, Reconciliation }
|
import lmcoursier.definitions.{ CacheLogger, ModuleMatchers, Reconciliation }
|
||||||
import lmcoursier.{ CoursierConfiguration, FallbackDependency }
|
import lmcoursier.{ CoursierConfiguration, FallbackDependency }
|
||||||
import org.apache.ivy.core.module.descriptor.ModuleDescriptor
|
|
||||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
|
||||||
import sbt.Def.*
|
import sbt.Def.*
|
||||||
import sbt.KeyRanks.*
|
import sbt.KeyRanks.*
|
||||||
import sbt.internal.InMemoryCacheStore.CacheStoreFactoryFactory
|
import sbt.internal.InMemoryCacheStore.CacheStoreFactoryFactory
|
||||||
import sbt.internal.*
|
import sbt.internal.*
|
||||||
import sbt.internal.bsp.*
|
import sbt.internal.bsp.*
|
||||||
import sbt.internal.inc.ScalaInstance
|
import sbt.internal.inc.ScalaInstance
|
||||||
import sbt.internal.librarymanagement.{ CompatibilityWarningOptions, IvySbt }
|
import sbt.internal.librarymanagement.CompatibilityWarningOptions
|
||||||
import sbt.internal.librarymanagement.ivy.{ IvyConfiguration, UpdateOptions }
|
|
||||||
import sbt.internal.server.BuildServerProtocol.BspFullWorkspace
|
import sbt.internal.server.BuildServerProtocol.BspFullWorkspace
|
||||||
import sbt.internal.server.{ BspCompileTask, BuildServerReporter, ServerHandler }
|
import sbt.internal.server.{ BspCompileTask, BuildServerReporter, ServerHandler }
|
||||||
import sbt.internal.util.{ AttributeKey, ProgressState, SourcePosition }
|
import sbt.internal.util.{ AttributeKey, ProgressState, SourcePosition }
|
||||||
|
|
@ -519,16 +516,16 @@ object Keys {
|
||||||
|
|
||||||
val internalConfigurationMap = settingKey[Configuration => Configuration]("Maps configurations to the actual configuration used to define the classpath.").withRank(CSetting)
|
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 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)
|
val ivyConfiguration = taskKey[Any]("General dependency management (Ivy) settings, such as the resolvers and paths to use.").withRank(DTask)
|
||||||
val ivyConfigurations = settingKey[Seq[Configuration]]("The defined configurations for dependency management. This may be different from the configurations for Project settings.").withRank(BSetting)
|
val ivyConfigurations = settingKey[Seq[Configuration]]("The defined configurations for dependency management. This may be different from the configurations for Project settings.").withRank(BSetting)
|
||||||
// This setting was created to work around the limitation of derived tasks not being able to use task-scoped task: ivyConfiguration in updateSbtClassifiers
|
// This setting was created to work around the limitation of derived tasks not being able to use task-scoped task: ivyConfiguration in updateSbtClassifiers
|
||||||
val bootIvyConfiguration = taskKey[IvyConfiguration]("General dependency management (Ivy) settings, configured to retrieve sbt's components.").withRank(DTask)
|
val bootIvyConfiguration = taskKey[Any]("General dependency management (Ivy) settings, configured to retrieve sbt's components.").withRank(DTask)
|
||||||
val bootDependencyResolution = taskKey[DependencyResolution]("Dependency resolution to retrieve sbt's components.").withRank(CTask)
|
val bootDependencyResolution = taskKey[DependencyResolution]("Dependency resolution to retrieve sbt's components.").withRank(CTask)
|
||||||
val scalaCompilerBridgeDependencyResolution = taskKey[DependencyResolution]("Dependency resolution to retrieve the compiler bridge.").withRank(CTask)
|
val scalaCompilerBridgeDependencyResolution = taskKey[DependencyResolution]("Dependency resolution to retrieve the compiler bridge.").withRank(CTask)
|
||||||
val moduleSettings = taskKey[ModuleSettings]("Module settings, which configure dependency management for a specific module, such as a project.").withRank(DTask)
|
val moduleSettings = taskKey[ModuleSettings]("Module settings, which configure dependency management for a specific module, such as a project.").withRank(DTask)
|
||||||
val unmanagedBase = settingKey[File]("The default directory for manually managed libraries.").withRank(ASetting)
|
val unmanagedBase = settingKey[File]("The default directory for manually managed libraries.").withRank(ASetting)
|
||||||
val updateConfiguration = settingKey[UpdateConfiguration]("Configuration for resolving and retrieving managed dependencies.").withRank(DSetting)
|
val updateConfiguration = settingKey[UpdateConfiguration]("Configuration for resolving and retrieving managed dependencies.").withRank(DSetting)
|
||||||
val updateOptions = settingKey[UpdateOptions]("Options for resolving managed dependencies.").withRank(DSetting)
|
val updateOptions = settingKey[Any]("Options for resolving managed dependencies.").withRank(DSetting)
|
||||||
|
|
||||||
@transient
|
@transient
|
||||||
val unresolvedWarningConfiguration = taskKey[UnresolvedWarningConfiguration]("Configuration for unresolved dependency warning.").withRank(DTask)
|
val unresolvedWarningConfiguration = taskKey[UnresolvedWarningConfiguration]("Configuration for unresolved dependency warning.").withRank(DTask)
|
||||||
|
|
@ -537,8 +534,8 @@ object Keys {
|
||||||
@transient
|
@transient
|
||||||
val dependencyResolution = taskKey[DependencyResolution]("Provides the sbt interface to dependency resolution.").withRank(CTask)
|
val dependencyResolution = taskKey[DependencyResolution]("Provides the sbt interface to dependency resolution.").withRank(CTask)
|
||||||
val publisher = taskKey[Publisher]("Provides the sbt interface to publisher")
|
val publisher = taskKey[Publisher]("Provides the sbt interface to publisher")
|
||||||
val ivySbt = taskKey[IvySbt]("Provides the sbt interface to Ivy.").withRank(CTask)
|
val ivySbt = taskKey[Any]("Provides the sbt interface to Ivy.").withRank(CTask)
|
||||||
val ivyModule = taskKey[IvySbt#Module]("Provides the sbt interface to a configured Ivy module.").withRank(CTask)
|
val ivyModule = taskKey[Any]("Provides the sbt interface to a configured Ivy module.").withRank(CTask)
|
||||||
val updateCacheName = taskKey[String]("Defines the directory name used to store the update cache files (inside the streams cacheDirectory).").withRank(DTask)
|
val updateCacheName = taskKey[String]("Defines the directory name used to store the update cache files (inside the streams cacheDirectory).").withRank(DTask)
|
||||||
val update = taskKey[UpdateReport]("Resolves and optionally retrieves dependencies, producing a report.").withRank(ATask)
|
val update = taskKey[UpdateReport]("Resolves and optionally retrieves dependencies, producing a report.").withRank(ATask)
|
||||||
val updateFull = taskKey[UpdateReport]("Resolves and optionally retrieves dependencies, producing a full report with callers.").withRank(CTask)
|
val updateFull = taskKey[UpdateReport]("Resolves and optionally retrieves dependencies, producing a full report with callers.").withRank(CTask)
|
||||||
|
|
@ -638,7 +635,7 @@ object Keys {
|
||||||
@transient
|
@transient
|
||||||
val publishTo = taskKey[Option[Resolver]]("The resolver to publish to.").withRank(ASetting)
|
val publishTo = taskKey[Option[Resolver]]("The resolver to publish to.").withRank(ASetting)
|
||||||
val artifacts = settingKey[Seq[Artifact]]("The artifact definitions for the current module. Must be consistent with " + packagedArtifacts.key.label + ".").withRank(BSetting)
|
val artifacts = settingKey[Seq[Artifact]]("The artifact definitions for the current module. Must be consistent with " + packagedArtifacts.key.label + ".").withRank(BSetting)
|
||||||
val projectDescriptors = taskKey[Map[ModuleRevisionId, ModuleDescriptor]]("Project dependency map for the inter-project resolver.").withRank(DTask)
|
val projectDescriptors = taskKey[Map[Any, Any]]("Project dependency map for the inter-project resolver.").withRank(DTask)
|
||||||
val autoUpdate = settingKey[Boolean]("<unimplemented>").withRank(Invisible)
|
val autoUpdate = settingKey[Boolean]("<unimplemented>").withRank(Invisible)
|
||||||
val retrieveManaged = settingKey[Boolean]("If true, enables retrieving dependencies to the current build. Otherwise, dependencies are used directly from the cache.").withRank(BSetting)
|
val retrieveManaged = settingKey[Boolean]("If true, enables retrieving dependencies to the current build. Otherwise, dependencies are used directly from the cache.").withRank(BSetting)
|
||||||
val retrieveManagedSync = settingKey[Boolean]("If true, enables synchronizing the dependencies retrieved to the current build by removed unneeded files.").withRank(BSetting)
|
val retrieveManagedSync = settingKey[Boolean]("If true, enables synchronizing the dependencies retrieved to the current build by removed unneeded files.").withRank(BSetting)
|
||||||
|
|
|
||||||
|
|
@ -13,26 +13,12 @@ import java.net.URI
|
||||||
import sbt.librarymanagement.{ Credentials as IvyCredentials, * }
|
import sbt.librarymanagement.{ Credentials as IvyCredentials, * }
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
import sbt.Keys.*
|
import sbt.Keys.*
|
||||||
import lmcoursier.definitions.{
|
import lmcoursier.definitions.{ Project as CProject, Strict as CStrict }
|
||||||
Classifier as CClassifier,
|
|
||||||
Configuration as CConfiguration,
|
|
||||||
Dependency as CDependency,
|
|
||||||
Extension as CExtension,
|
|
||||||
Info as CInfo,
|
|
||||||
Module as CModule,
|
|
||||||
ModuleName as CModuleName,
|
|
||||||
Organization as COrganization,
|
|
||||||
Project as CProject,
|
|
||||||
Publication as CPublication,
|
|
||||||
Type as CType,
|
|
||||||
Strict as CStrict,
|
|
||||||
}
|
|
||||||
import lmcoursier.credentials.DirectCredentials
|
import lmcoursier.credentials.DirectCredentials
|
||||||
import lmcoursier.{ FallbackDependency, FromSbt, Inputs }
|
import lmcoursier.{ FallbackDependency, FromSbt, Inputs }
|
||||||
import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties
|
import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties
|
||||||
import sbt.ProjectExtra.transitiveInterDependencies
|
import sbt.ProjectExtra.transitiveInterDependencies
|
||||||
import sbt.ScopeFilter.Make.*
|
import sbt.ScopeFilter.Make.*
|
||||||
import scala.jdk.CollectionConverters.*
|
|
||||||
|
|
||||||
object CoursierInputsTasks {
|
object CoursierInputsTasks {
|
||||||
private def coursierProject0(
|
private def coursierProject0(
|
||||||
|
|
@ -100,61 +86,6 @@ object CoursierInputsTasks {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def moduleFromIvy(id: org.apache.ivy.core.module.id.ModuleRevisionId): CModule =
|
|
||||||
CModule(
|
|
||||||
COrganization(id.getOrganisation),
|
|
||||||
CModuleName(id.getName),
|
|
||||||
id.getExtraAttributes.asScala.map { (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), CModuleName(modId.getName))
|
|
||||||
}.toSet
|
|
||||||
|
|
||||||
val configurations = desc.getModuleConfigurations.toVector
|
|
||||||
.flatMap(Inputs.ivyXmlMappings)
|
|
||||||
|
|
||||||
def dependency(conf: CConfiguration, pub: CPublication) = CDependency(
|
|
||||||
module,
|
|
||||||
id.getRevision,
|
|
||||||
conf,
|
|
||||||
exclusions,
|
|
||||||
pub,
|
|
||||||
optional = false,
|
|
||||||
desc.isTransitive
|
|
||||||
)
|
|
||||||
|
|
||||||
val publications: CConfiguration => CPublication = {
|
|
||||||
|
|
||||||
val artifacts = desc.getAllDependencyArtifacts
|
|
||||||
|
|
||||||
val m = artifacts.toVector.flatMap { art =>
|
|
||||||
val pub =
|
|
||||||
CPublication(art.getName, CType(art.getType), CExtension(art.getExt()), CClassifier(""))
|
|
||||||
art.getConfigurations.map(CConfiguration(_)).toVector.map { conf =>
|
|
||||||
conf -> pub
|
|
||||||
}
|
|
||||||
}.toMap
|
|
||||||
|
|
||||||
c => m.getOrElse(c, CPublication("", CType(""), CExtension(""), CClassifier("")))
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations.map { (from, to) =>
|
|
||||||
from -> dependency(to, publications(to))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private[sbt] def coursierInterProjectDependenciesTask: Def.Initialize[sbt.Task[Seq[CProject]]] =
|
private[sbt] def coursierInterProjectDependenciesTask: Def.Initialize[sbt.Task[Seq[CProject]]] =
|
||||||
(Def
|
(Def
|
||||||
.task {
|
.task {
|
||||||
|
|
@ -171,34 +102,9 @@ object CoursierInputsTasks {
|
||||||
|
|
||||||
private[sbt] def coursierExtraProjectsTask: Def.Initialize[sbt.Task[Seq[CProject]]] = {
|
private[sbt] def coursierExtraProjectsTask: Def.Initialize[sbt.Task[Seq[CProject]]] = {
|
||||||
Def.task {
|
Def.task {
|
||||||
val projects = csrInterProjectDependencies.value
|
// Coursier handles inter-project dependencies natively via csrInterProjectDependencies.
|
||||||
val projectModules = projects.map(_.module).toSet
|
// The Ivy-typed projectDescriptors are only populated when IvyDependencyPlugin is enabled.
|
||||||
|
Seq.empty[CProject]
|
||||||
// this includes org.scala-sbt:global-plugins referenced from meta-builds in particular
|
|
||||||
sbt.Keys.projectDescriptors.value
|
|
||||||
.map { (k, v) =>
|
|
||||||
moduleFromIvy(k) -> v
|
|
||||||
}
|
|
||||||
.filter { case (module, _) =>
|
|
||||||
!projectModules(module)
|
|
||||||
}
|
|
||||||
.toVector
|
|
||||||
.map { (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.toSeq,
|
|
||||||
configurations,
|
|
||||||
Nil,
|
|
||||||
None,
|
|
||||||
Nil,
|
|
||||||
CInfo("", "", Nil, Nil, None)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,7 +136,7 @@ object CoursierInputsTasks {
|
||||||
.flatMap {
|
.flatMap {
|
||||||
case dc: IvyCredentials.DirectCredentials => List(dc)
|
case dc: IvyCredentials.DirectCredentials => List(dc)
|
||||||
case fc: IvyCredentials.FileCredentials =>
|
case fc: IvyCredentials.FileCredentials =>
|
||||||
sbt.internal.librarymanagement.ivy.IvyCredentials.loadCredentials(fc.path) match {
|
sbt.librarymanagement.CredentialUtils.loadCredentials(fc.path) match {
|
||||||
case Left(err) =>
|
case Left(err) =>
|
||||||
log.warn(s"$err, ignoring it")
|
log.warn(s"$err, ignoring it")
|
||||||
Nil
|
Nil
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ object LMCoursier {
|
||||||
case dc: IvyCredentials.DirectCredentials =>
|
case dc: IvyCredentials.DirectCredentials =>
|
||||||
Right[String, IvyCredentials.DirectCredentials](dc)
|
Right[String, IvyCredentials.DirectCredentials](dc)
|
||||||
case fc: IvyCredentials.FileCredentials =>
|
case fc: IvyCredentials.FileCredentials =>
|
||||||
sbt.internal.librarymanagement.ivy.IvyCredentials.loadCredentials(fc.path)
|
sbt.librarymanagement.CredentialUtils.loadCredentials(fc.path)
|
||||||
}) match {
|
}) match {
|
||||||
case Left(err) => st.log.warn(err)
|
case Left(err) => st.log.warn(err)
|
||||||
case Right(d) =>
|
case Right(d) =>
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@ import sbt.ProjectExtra.{ extract, runUnloadHooks, setProject }
|
||||||
import sbt.SlashSyntax0.*
|
import sbt.SlashSyntax0.*
|
||||||
import sbt.librarymanagement.LibraryManagementCodec.given
|
import sbt.librarymanagement.LibraryManagementCodec.given
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import org.apache.ivy.core.module.{ descriptor, id }
|
|
||||||
import descriptor.ModuleDescriptor, id.ModuleRevisionId
|
|
||||||
|
|
||||||
object GlobalPlugin {
|
object GlobalPlugin {
|
||||||
// constructs a sequence of settings that may be appended to a project's settings to
|
// constructs a sequence of settings that may be appended to a project's settings to
|
||||||
|
|
@ -79,9 +77,7 @@ object GlobalPlugin {
|
||||||
val taskInit = Def.task {
|
val taskInit = Def.task {
|
||||||
val intcp = (Runtime / internalDependencyClasspath).value
|
val intcp = (Runtime / internalDependencyClasspath).value
|
||||||
val prods = (Runtime / exportedProducts).value
|
val prods = (Runtime / exportedProducts).value
|
||||||
val depMap =
|
val depMap = projectDescriptors.value
|
||||||
if useIvy.value then projectDescriptors.value + ivyModule.value.dependencyMapping(state.log)
|
|
||||||
else projectDescriptors.value
|
|
||||||
|
|
||||||
GlobalPluginData(
|
GlobalPluginData(
|
||||||
projectID.value,
|
projectID.value,
|
||||||
|
|
@ -125,7 +121,7 @@ object GlobalPlugin {
|
||||||
final case class GlobalPluginData(
|
final case class GlobalPluginData(
|
||||||
projectID: ModuleID,
|
projectID: ModuleID,
|
||||||
dependencies: Seq[ModuleID],
|
dependencies: Seq[ModuleID],
|
||||||
descriptors: Map[ModuleRevisionId, ModuleDescriptor],
|
descriptors: Map[Any, Any],
|
||||||
resolvers: Vector[Resolver],
|
resolvers: Vector[Resolver],
|
||||||
fullClasspath: Classpath,
|
fullClasspath: Classpath,
|
||||||
internalClasspath: Classpath
|
internalClasspath: Classpath
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@ private[sbt] object LibraryManagement {
|
||||||
Seq[ScopedKey[?]],
|
Seq[ScopedKey[?]],
|
||||||
ScopedKey[?],
|
ScopedKey[?],
|
||||||
Option[FiniteDuration],
|
Option[FiniteDuration],
|
||||||
IvySbt#Module,
|
ModuleSettings,
|
||||||
String,
|
String,
|
||||||
ProjectRef,
|
ProjectRef,
|
||||||
Boolean,
|
Boolean,
|
||||||
|
|
@ -318,7 +318,6 @@ private[sbt] object LibraryManagement {
|
||||||
UnresolvedWarningConfiguration,
|
UnresolvedWarningConfiguration,
|
||||||
Boolean,
|
Boolean,
|
||||||
CompatibilityWarningOptions,
|
CompatibilityWarningOptions,
|
||||||
IvySbt,
|
|
||||||
GetClassifiersModule,
|
GetClassifiersModule,
|
||||||
File,
|
File,
|
||||||
xsbti.AppConfiguration,
|
xsbti.AppConfiguration,
|
||||||
|
|
@ -334,7 +333,7 @@ private[sbt] object LibraryManagement {
|
||||||
Keys.executionRoots,
|
Keys.executionRoots,
|
||||||
Keys.resolvedScoped.toTaskable,
|
Keys.resolvedScoped.toTaskable,
|
||||||
Keys.forceUpdatePeriod.toTaskable,
|
Keys.forceUpdatePeriod.toTaskable,
|
||||||
Keys.ivyModule.toTaskable,
|
Keys.moduleSettings.toTaskable,
|
||||||
Keys.updateCacheName.toTaskable,
|
Keys.updateCacheName.toTaskable,
|
||||||
Keys.thisProjectRef.toTaskable,
|
Keys.thisProjectRef.toTaskable,
|
||||||
(Keys.update / Keys.skip).toTaskable,
|
(Keys.update / Keys.skip).toTaskable,
|
||||||
|
|
@ -342,7 +341,6 @@ private[sbt] object LibraryManagement {
|
||||||
(Keys.update / Keys.unresolvedWarningConfiguration).toTaskable,
|
(Keys.update / Keys.unresolvedWarningConfiguration).toTaskable,
|
||||||
Keys.publishMavenStyle.toTaskable,
|
Keys.publishMavenStyle.toTaskable,
|
||||||
Keys.compatibilityWarningOptions.toTaskable,
|
Keys.compatibilityWarningOptions.toTaskable,
|
||||||
Keys.ivySbt,
|
|
||||||
Keys.classifiersModule,
|
Keys.classifiersModule,
|
||||||
Keys.dependencyCacheDirectory,
|
Keys.dependencyCacheDirectory,
|
||||||
Keys.appConfiguration.toTaskable,
|
Keys.appConfiguration.toTaskable,
|
||||||
|
|
@ -358,7 +356,7 @@ private[sbt] object LibraryManagement {
|
||||||
er,
|
er,
|
||||||
rs,
|
rs,
|
||||||
fup,
|
fup,
|
||||||
im,
|
ms,
|
||||||
ucn,
|
ucn,
|
||||||
thisRef,
|
thisRef,
|
||||||
sk,
|
sk,
|
||||||
|
|
@ -366,7 +364,6 @@ private[sbt] object LibraryManagement {
|
||||||
uwConfig,
|
uwConfig,
|
||||||
mavenStyle,
|
mavenStyle,
|
||||||
cwo,
|
cwo,
|
||||||
ivySbt0,
|
|
||||||
mod,
|
mod,
|
||||||
dcd,
|
dcd,
|
||||||
app,
|
app,
|
||||||
|
|
@ -400,10 +397,8 @@ private[sbt] object LibraryManagement {
|
||||||
conf1.withLogicalClock(LogicalClock(state0.hashCode))
|
conf1.withLogicalClock(LogicalClock(state0.hashCode))
|
||||||
}
|
}
|
||||||
cachedUpdate(
|
cachedUpdate(
|
||||||
// LM API
|
|
||||||
lm = lm,
|
lm = lm,
|
||||||
// Ivy-free ModuleDescriptor
|
module = lm.moduleDescriptor(ms.asInstanceOf[ModuleDescriptorConfiguration]),
|
||||||
module = im,
|
|
||||||
s.cacheStoreFactory.sub(ucn),
|
s.cacheStoreFactory.sub(ucn),
|
||||||
Reference.display(thisRef),
|
Reference.display(thisRef),
|
||||||
updateConf,
|
updateConf,
|
||||||
|
|
@ -446,12 +441,12 @@ private[sbt] object LibraryManagement {
|
||||||
)
|
)
|
||||||
val report = f(excludes)
|
val report = f(excludes)
|
||||||
val allExcludes: Map[ModuleID, Vector[ConfigRef]] = excludes ++
|
val allExcludes: Map[ModuleID, Vector[ConfigRef]] = excludes ++
|
||||||
IvyActions
|
UpdateClassifiersUtil
|
||||||
.extractExcludes(report)
|
.extractExcludes(report)
|
||||||
.view
|
.view
|
||||||
.mapValues(cs => cs.map(c => ConfigRef(c)).toVector)
|
.mapValues(cs => cs.map(c => ConfigRef(c)).toVector)
|
||||||
store.write(allExcludes)
|
store.write(allExcludes)
|
||||||
IvyActions
|
UpdateClassifiersUtil
|
||||||
.addExcluded(
|
.addExcluded(
|
||||||
report,
|
report,
|
||||||
classifiers.toVector,
|
classifiers.toVector,
|
||||||
|
|
@ -986,7 +981,7 @@ private[sbt] object LibraryManagement {
|
||||||
Def.task {
|
Def.task {
|
||||||
val log = streams.value.log
|
val log = streams.value.log
|
||||||
val conf = publishConfiguration.value
|
val conf = publishConfiguration.value
|
||||||
val module = ivyModule.value
|
val module = ivyModule.value.asInstanceOf[ModuleDescriptor]
|
||||||
val publisherInterface = publisher.value
|
val publisherInterface = publisher.value
|
||||||
publisherInterface.publish(module, conf, log)
|
publisherInterface.publish(module, conf, log)
|
||||||
}
|
}
|
||||||
|
|
@ -1114,7 +1109,7 @@ private[sbt] object LibraryManagement {
|
||||||
Def.task {
|
Def.task {
|
||||||
val log = streams.value.log
|
val log = streams.value.log
|
||||||
val conf = publishLocalConfiguration.value
|
val conf = publishLocalConfiguration.value
|
||||||
val module = ivyModule.value
|
val module = ivyModule.value.asInstanceOf[ModuleDescriptor]
|
||||||
val publisherInterface = publisher.value
|
val publisherInterface = publisher.value
|
||||||
publisherInterface.publish(module, conf, log)
|
publisherInterface.publish(module, conf, log)
|
||||||
}
|
}
|
||||||
|
|
@ -1157,7 +1152,7 @@ private[sbt] object LibraryManagement {
|
||||||
Def.task {
|
Def.task {
|
||||||
val log = streams.value.log
|
val log = streams.value.log
|
||||||
val conf = publishM2Configuration.value
|
val conf = publishM2Configuration.value
|
||||||
val module = ivyModule.value
|
val module = ivyModule.value.asInstanceOf[ModuleDescriptor]
|
||||||
val publisherInterface = publisher.value
|
val publisherInterface = publisher.value
|
||||||
publisherInterface.publish(module, conf, log)
|
publisherInterface.publish(module, conf, log)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,285 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2023, Scala center
|
||||||
|
* Copyright 2011 - 2022, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sbt
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import sbt.librarymanagement.*
|
||||||
|
import scala.xml.{ Elem, Node, NodeSeq }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates Maven POM XML from sbt's own types, without requiring Ivy.
|
||||||
|
* This is used by the default publisher when the sbt-ivy plugin is not loaded.
|
||||||
|
*/
|
||||||
|
private[sbt] object PomGenerator:
|
||||||
|
|
||||||
|
def makePom(
|
||||||
|
mid: ModuleID,
|
||||||
|
info: Option[ModuleInfo],
|
||||||
|
deps: Vector[ModuleID],
|
||||||
|
configurations: Option[Vector[Configuration]],
|
||||||
|
extra: NodeSeq,
|
||||||
|
scalaModuleInfo: Option[ScalaModuleInfo] = None,
|
||||||
|
resolvers: Vector[Resolver] = Vector.empty,
|
||||||
|
filterRepositories: MavenRepository => Boolean = _ => true,
|
||||||
|
allRepositories: Boolean = false,
|
||||||
|
): Node =
|
||||||
|
val crossMid = crossVersionDep(mid, scalaModuleInfo)
|
||||||
|
val keepConfs: Set[String] =
|
||||||
|
configurations.map(_.map(_.name).toSet).getOrElse(Set.empty)
|
||||||
|
val crossVersioned = deps.map(crossVersionDep(_, scalaModuleInfo))
|
||||||
|
val filteredDeps =
|
||||||
|
if keepConfs.isEmpty then crossVersioned
|
||||||
|
else crossVersioned.filter(d => d.configurations.forall(c => confIntersects(c, keepConfs)))
|
||||||
|
|
||||||
|
val (bomDeps, regularDeps) = filteredDeps.partition: d =>
|
||||||
|
d.explicitArtifacts.nonEmpty && d.explicitArtifacts.forall(_.`type` == Artifact.PomType)
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
{makeModuleID(crossMid)}
|
||||||
|
{info.map(i => <name>{i.nameFormal}</name>).getOrElse(NodeSeq.Empty)}
|
||||||
|
{info.map(makeStartYear).getOrElse(NodeSeq.Empty)}
|
||||||
|
{info.map(makeOrganization).getOrElse(NodeSeq.Empty)}
|
||||||
|
{info.map(makeScmInfo).getOrElse(NodeSeq.Empty)}
|
||||||
|
{info.map(makeDeveloperInfo).getOrElse(NodeSeq.Empty)}
|
||||||
|
{info.map(makeLicenses).getOrElse(NodeSeq.Empty)}
|
||||||
|
{makeProperties(crossMid)}
|
||||||
|
{extra}
|
||||||
|
{makeRepositories(resolvers, filterRepositories, allRepositories)}
|
||||||
|
{makeDependencyManagement(bomDeps)}
|
||||||
|
{makeDependencies(regularDeps)}
|
||||||
|
</project>
|
||||||
|
|
||||||
|
private def crossVersionDep(dep: ModuleID, scalaInfo: Option[ScalaModuleInfo]): ModuleID =
|
||||||
|
val crossFn = CrossVersion(dep, scalaInfo)
|
||||||
|
val crossDep = crossFn match
|
||||||
|
case Some(fn) => dep.withName(fn(dep.name)).withCrossVersion(CrossVersion.disabled)
|
||||||
|
case None => dep
|
||||||
|
if crossDep.exclusions.isEmpty || scalaInfo.isEmpty then crossDep
|
||||||
|
else
|
||||||
|
val si = scalaInfo.get
|
||||||
|
val crossedExclusions = crossDep.exclusions.map: excl =>
|
||||||
|
CrossVersion(excl.crossVersion, si.scalaFullVersion, si.scalaBinaryVersion) match
|
||||||
|
case Some(fn) =>
|
||||||
|
excl.withName(fn(excl.name)).withCrossVersion(CrossVersion.disabled)
|
||||||
|
case None => excl
|
||||||
|
crossDep.withExclusions(crossedExclusions)
|
||||||
|
|
||||||
|
private def confIntersects(confStr: String, keepConfs: Set[String]): Boolean =
|
||||||
|
confStr
|
||||||
|
.split(';')
|
||||||
|
.exists: mapping =>
|
||||||
|
val from = mapping.split("->").head.trim
|
||||||
|
from.split(',').exists(c => keepConfs.contains(c.trim) || c.trim == "*")
|
||||||
|
|
||||||
|
private def makeModuleID(mid: ModuleID): NodeSeq =
|
||||||
|
val packaging =
|
||||||
|
if mid.explicitArtifacts.isEmpty then "jar"
|
||||||
|
else
|
||||||
|
val types = mid.explicitArtifacts.map(_.`type`).filterNot(IgnoreTypes)
|
||||||
|
if types.isEmpty then Artifact.PomType
|
||||||
|
else if types.contains(Artifact.DefaultType) then Artifact.DefaultType
|
||||||
|
else types.head
|
||||||
|
(<groupId>{mid.organization}</groupId>
|
||||||
|
<artifactId>{mid.name}</artifactId>
|
||||||
|
<version>{mid.revision}</version>
|
||||||
|
<packaging>{packaging}</packaging>)
|
||||||
|
|
||||||
|
private val IgnoreTypes: Set[String] =
|
||||||
|
Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType)
|
||||||
|
|
||||||
|
private def makeStartYear(info: ModuleInfo): NodeSeq =
|
||||||
|
info.startYear match
|
||||||
|
case Some(y) => <inceptionYear>{y}</inceptionYear>
|
||||||
|
case _ => NodeSeq.Empty
|
||||||
|
|
||||||
|
private def makeOrganization(info: ModuleInfo): NodeSeq =
|
||||||
|
<organization>
|
||||||
|
<name>{info.organizationName}</name>
|
||||||
|
{info.organizationHomepage.map(h => <url>{h}</url>).getOrElse(NodeSeq.Empty)}
|
||||||
|
</organization>
|
||||||
|
|
||||||
|
private def makeScmInfo(info: ModuleInfo): NodeSeq =
|
||||||
|
info.scmInfo match
|
||||||
|
case Some(s) =>
|
||||||
|
<scm>
|
||||||
|
<url>{s.browseUrl}</url>
|
||||||
|
<connection>{s.connection}</connection>
|
||||||
|
{
|
||||||
|
s.devConnection
|
||||||
|
.map(d => <developerConnection>{d}</developerConnection>)
|
||||||
|
.getOrElse(NodeSeq.Empty)
|
||||||
|
}
|
||||||
|
</scm>
|
||||||
|
case _ => NodeSeq.Empty
|
||||||
|
|
||||||
|
private def makeDeveloperInfo(info: ModuleInfo): NodeSeq =
|
||||||
|
if info.developers.nonEmpty then
|
||||||
|
<developers>
|
||||||
|
{
|
||||||
|
info.developers.map: dev =>
|
||||||
|
<developer>
|
||||||
|
<id>{dev.id}</id>
|
||||||
|
<name>{dev.name}</name>
|
||||||
|
<url>{dev.url}</url>
|
||||||
|
{
|
||||||
|
if dev.email != null && dev.email.nonEmpty then <email>{dev.email}</email>
|
||||||
|
else NodeSeq.Empty
|
||||||
|
}
|
||||||
|
</developer>
|
||||||
|
}
|
||||||
|
</developers>
|
||||||
|
else NodeSeq.Empty
|
||||||
|
|
||||||
|
private def makeLicenses(info: ModuleInfo): NodeSeq =
|
||||||
|
if info.licenses.nonEmpty then
|
||||||
|
<licenses>
|
||||||
|
{
|
||||||
|
info.licenses.map: lic =>
|
||||||
|
<license>
|
||||||
|
<name>{lic.spdxId}</name>
|
||||||
|
<url>{lic.uri}</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
}
|
||||||
|
</licenses>
|
||||||
|
else NodeSeq.Empty
|
||||||
|
|
||||||
|
private def makeProperties(mid: ModuleID): NodeSeq =
|
||||||
|
val props = mid.extraAttributes
|
||||||
|
.collect:
|
||||||
|
case (k, v) if k.startsWith("e:info.") => (k.stripPrefix("e:"), v)
|
||||||
|
case (k, v) if k.startsWith("info.") => (k, v)
|
||||||
|
if props.isEmpty then NodeSeq.Empty
|
||||||
|
else
|
||||||
|
<properties>
|
||||||
|
{
|
||||||
|
props.toSeq
|
||||||
|
.sortBy(_._1)
|
||||||
|
.map: (k, v) =>
|
||||||
|
Elem(null, k, scala.xml.Null, scala.xml.TopScope, false, scala.xml.Text(v))
|
||||||
|
}
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
private def makeRepositories(
|
||||||
|
resolvers: Vector[Resolver],
|
||||||
|
filter: MavenRepository => Boolean,
|
||||||
|
allRepositories: Boolean,
|
||||||
|
): NodeSeq =
|
||||||
|
val repos = resolvers.collect:
|
||||||
|
case r: MavenRepository if r.name != "public" && (allRepositories || filter(r)) =>
|
||||||
|
<repository>
|
||||||
|
<id>{r.name}</id>
|
||||||
|
<name>{r.name}</name>
|
||||||
|
<url>{r.root}</url>
|
||||||
|
</repository>
|
||||||
|
if repos.isEmpty then NodeSeq.Empty
|
||||||
|
else <repositories>{repos}</repositories>
|
||||||
|
|
||||||
|
private def makeDependencyManagement(deps: Vector[ModuleID]): NodeSeq =
|
||||||
|
if deps.isEmpty then NodeSeq.Empty
|
||||||
|
else
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
{
|
||||||
|
deps.map: dep =>
|
||||||
|
<dependency>
|
||||||
|
<groupId>{dep.organization}</groupId>
|
||||||
|
<artifactId>{dep.name}</artifactId>
|
||||||
|
<version>{dep.revision}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
}
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
private def makeDependencies(deps: Vector[ModuleID]): NodeSeq =
|
||||||
|
if deps.isEmpty then NodeSeq.Empty
|
||||||
|
else <dependencies>
|
||||||
|
{deps.map(makeDependencyElem)}
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
private def makeDependencyElem(dep: ModuleID): Elem =
|
||||||
|
val (scope, optional) = getScopeAndOptional(dep.configurations)
|
||||||
|
val mavenVersion = convertVersion(dep.revision)
|
||||||
|
val versionNode: NodeSeq =
|
||||||
|
if mavenVersion == null || mavenVersion == "*" || mavenVersion.isEmpty then NodeSeq.Empty
|
||||||
|
else <version>{mavenVersion}</version>
|
||||||
|
val result: Elem =
|
||||||
|
<dependency>
|
||||||
|
<groupId>{dep.organization}</groupId>
|
||||||
|
<artifactId>{dep.name}</artifactId>
|
||||||
|
{versionNode}
|
||||||
|
{scopeElem(scope)}
|
||||||
|
{optionalElem(optional)}
|
||||||
|
{classifierElem(dep)}
|
||||||
|
{exclusions(dep)}
|
||||||
|
</dependency>
|
||||||
|
result
|
||||||
|
|
||||||
|
private def getScopeAndOptional(configurations: Option[String]): (Option[String], Boolean) =
|
||||||
|
configurations match
|
||||||
|
case None => (None, false)
|
||||||
|
case Some(confStr) =>
|
||||||
|
val confs =
|
||||||
|
confStr.split(';').flatMap(_.split("->").head.trim.split(',')).map(_.trim).toSet
|
||||||
|
val optional = confs.contains(Configurations.Optional.name)
|
||||||
|
val notOptional = confs - Configurations.Optional.name
|
||||||
|
val scope = Configurations.defaultMavenConfigurations
|
||||||
|
.find(c => notOptional.contains(c.name))
|
||||||
|
.map(_.name)
|
||||||
|
(scope, optional)
|
||||||
|
|
||||||
|
/** Convert Ivy-style dynamic versions to Maven range format. */
|
||||||
|
private def convertVersion(version: String): String =
|
||||||
|
if version == null then null
|
||||||
|
else if version.endsWith("+") then
|
||||||
|
val base = version.stripSuffix("+").stripSuffix(".")
|
||||||
|
val parts = base.split('.')
|
||||||
|
if parts.nonEmpty then
|
||||||
|
val last =
|
||||||
|
try parts.last.toInt + 1
|
||||||
|
catch case _: NumberFormatException => return version
|
||||||
|
val upper = (parts.init :+ last.toString).mkString(".")
|
||||||
|
s"[$base,$upper)"
|
||||||
|
else version
|
||||||
|
else if version == "latest.integration" || version == "latest.release" then ""
|
||||||
|
else version
|
||||||
|
|
||||||
|
private def scopeElem(scope: Option[String]): NodeSeq =
|
||||||
|
scope match
|
||||||
|
case None | Some("compile") => NodeSeq.Empty
|
||||||
|
case Some(s) => <scope>{s}</scope>
|
||||||
|
|
||||||
|
private def optionalElem(opt: Boolean): NodeSeq =
|
||||||
|
if opt then <optional>true</optional> else NodeSeq.Empty
|
||||||
|
|
||||||
|
private def classifierElem(dep: ModuleID): NodeSeq =
|
||||||
|
dep.explicitArtifacts.headOption.flatMap(_.classifier) match
|
||||||
|
case Some(c) => <classifier>{c}</classifier>
|
||||||
|
case None => NodeSeq.Empty
|
||||||
|
|
||||||
|
private def exclusions(dep: ModuleID): NodeSeq =
|
||||||
|
if dep.exclusions.isEmpty then NodeSeq.Empty
|
||||||
|
else
|
||||||
|
val elems = dep.exclusions.flatMap { excl =>
|
||||||
|
val g = excl.organization
|
||||||
|
val a = excl.name
|
||||||
|
if g.nonEmpty && g != "*" && a.nonEmpty && a != "*" then Some(<exclusion>
|
||||||
|
<groupId>{g}</groupId>
|
||||||
|
<artifactId>{a}</artifactId>
|
||||||
|
</exclusion>)
|
||||||
|
else None
|
||||||
|
}
|
||||||
|
if elems.isEmpty then NodeSeq.Empty
|
||||||
|
else <exclusions>{elems}</exclusions>
|
||||||
|
end PomGenerator
|
||||||
|
|
@ -15,7 +15,7 @@ import sbt.internal.util.MessageOnlyException
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
import sbt.io.Path.contentOf
|
import sbt.io.Path.contentOf
|
||||||
import sbt.librarymanagement.Credentials
|
import sbt.librarymanagement.Credentials
|
||||||
import sbt.internal.librarymanagement.ivy.IvyCredentials
|
import sbt.librarymanagement.CredentialUtils
|
||||||
import sona.{ PublishingType, Sona }
|
import sona.{ PublishingType, Sona }
|
||||||
|
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
|
|
@ -65,7 +65,7 @@ see https://www.scala-sbt.org/1.x/docs/Using-Sonatype.html for details.""")
|
||||||
}
|
}
|
||||||
|
|
||||||
private def fromCreds(creds: Seq[Credentials], uploadRequestTimeout: FiniteDuration): Sona = {
|
private def fromCreds(creds: Seq[Credentials], uploadRequestTimeout: FiniteDuration): Sona = {
|
||||||
val cred = IvyCredentials
|
val cred = CredentialUtils
|
||||||
.forHost(creds, Sona.host)
|
.forHost(creds, Sona.host)
|
||||||
.getOrElse(throw new MessageOnlyException(s"no credentials are found for ${Sona.host}"))
|
.getOrElse(throw new MessageOnlyException(s"no credentials are found for ${Sona.host}"))
|
||||||
Sona.oauthClient(cred.userName, cred.passwd, uploadRequestTimeout)
|
Sona.oauthClient(cred.userName, cred.passwd, uploadRequestTimeout)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ import sbt.ProjectExtra.*
|
||||||
import sbt.internal.graph.*
|
import sbt.internal.graph.*
|
||||||
import sbt.internal.graph.backend.SbtUpdateReport
|
import sbt.internal.graph.backend.SbtUpdateReport
|
||||||
import sbt.internal.graph.rendering.{ DagreHTML, TreeView }
|
import sbt.internal.graph.rendering.{ DagreHTML, TreeView }
|
||||||
import sbt.internal.librarymanagement.*
|
|
||||||
import sbt.internal.util.complete.{ Parser, Parsers }
|
import sbt.internal.util.complete.{ Parser, Parsers }
|
||||||
import sbt.internal.util.complete.DefaultParsers.*
|
import sbt.internal.util.complete.DefaultParsers.*
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
|
|
@ -110,29 +109,12 @@ OPTIONS
|
||||||
*/
|
*/
|
||||||
def coreSettings =
|
def coreSettings =
|
||||||
Seq(
|
Seq(
|
||||||
// disable the cached resolution engine (exposing a scoped `ivyModule` used directly by `updateTask`), as it
|
|
||||||
// generates artificial module descriptors which are internal to sbt, making it hard to reconstruct the
|
|
||||||
// dependency tree
|
|
||||||
dependencyTreeIgnoreMissingUpdate / updateOptions := updateOptions.value
|
|
||||||
.withCachedResolution(false),
|
|
||||||
dependencyTreeIgnoreMissingUpdate / ivyConfiguration := Def.uncached {
|
|
||||||
// inTask will make sure the new definition will pick up `updateOptions in dependencyTreeIgnoreMissingUpdate`
|
|
||||||
Project.inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.mkIvyConfiguration).value
|
|
||||||
},
|
|
||||||
dependencyTreeIgnoreMissingUpdate / ivyModule := Def.uncached {
|
|
||||||
// concatenating & inlining ivySbt & ivyModule default task implementations, as `SbtAccess.inTask` does
|
|
||||||
// NOT correctly force the scope when applied to `TaskKey.toTask` instances (as opposed to raw
|
|
||||||
// implementations like `Classpaths.mkIvyConfiguration` or `Classpaths.updateTask`)
|
|
||||||
val is = new IvySbt((dependencyTreeIgnoreMissingUpdate / ivyConfiguration).value)
|
|
||||||
new is.Module(moduleSettings.value)
|
|
||||||
},
|
|
||||||
// don't fail on missing dependencies or eviction errors
|
// don't fail on missing dependencies or eviction errors
|
||||||
dependencyTreeIgnoreMissingUpdate / updateConfiguration := updateConfiguration.value
|
dependencyTreeIgnoreMissingUpdate / updateConfiguration := updateConfiguration.value
|
||||||
.withMissingOk(true),
|
.withMissingOk(true),
|
||||||
dependencyTreeIgnoreMissingUpdate / evictionErrorLevel := Level.Warn,
|
dependencyTreeIgnoreMissingUpdate / evictionErrorLevel := Level.Warn,
|
||||||
dependencyTreeIgnoreMissingUpdate / assumedEvictionErrorLevel := Level.Warn,
|
dependencyTreeIgnoreMissingUpdate / assumedEvictionErrorLevel := Level.Warn,
|
||||||
dependencyTreeIgnoreMissingUpdate := Def.uncached {
|
dependencyTreeIgnoreMissingUpdate := Def.uncached {
|
||||||
// inTask will make sure the new definition will pick up `ivyModule/updateConfiguration in ignoreMissingUpdate`
|
|
||||||
Project.inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.updateTask).value
|
Project.inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.updateTask).value
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -390,8 +372,8 @@ OPTIONS
|
||||||
type HasModule = {
|
type HasModule = {
|
||||||
val module: ModuleID
|
val module: ModuleID
|
||||||
}
|
}
|
||||||
def crossName(ivyModule: IvySbt#Module) =
|
def crossName(module: Any) =
|
||||||
ivyModule.moduleSettings match {
|
module match {
|
||||||
case ic: ModuleDescriptorConfiguration => ic.module.name
|
case ic: ModuleDescriptorConfiguration => ic.module.name
|
||||||
case _ =>
|
case _ =>
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
scalaVersion := "2.12.21"
|
|
||||||
|
|
||||||
libraryDependencies += "org.slf4j" % "slf4j-api" % "1.7.28"
|
|
||||||
updateOptions := updateOptions.value.withCachedResolution(true)
|
|
||||||
|
|
||||||
TaskKey[Unit]("check") := {
|
|
||||||
val report = (Test / updateFull).value
|
|
||||||
val graph = (Test / dependencyTree).toTask(" --quiet").value
|
|
||||||
|
|
||||||
def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n")
|
|
||||||
val expectedGraph =
|
|
||||||
"""default:cachedresolution_2.12:0.1.0-SNAPSHOT
|
|
||||||
| +-org.slf4j:slf4j-api:1.7.28
|
|
||||||
| """.stripMargin
|
|
||||||
require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph)))
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
> check
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
ThisBuild / useIvy := true
|
||||||
lazy val root = (project in file("."))
|
lazy val root = (project in file("."))
|
||||||
lazy val a = project
|
lazy val a = project
|
||||||
lazy val b = project
|
lazy val b = project
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
libraryDependencies += {
|
||||||
|
val sbtV = sbtVersion.value
|
||||||
|
("org.scala-sbt" % s"sbt-ivy_sbt${sbtV}_${scalaBinaryVersion.value}" % sbtV).intransitive()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
libraryDependencies += {
|
||||||
|
val sbtV = sbtVersion.value
|
||||||
|
("org.scala-sbt" % s"sbt-ivy_sbt${sbtV}_${scalaBinaryVersion.value}" % sbtV).intransitive()
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,8 @@ import scala.xml.{ Node, _ }
|
||||||
import scala.xml.Utility.trim
|
import scala.xml.Utility.trim
|
||||||
import sbt.internal.librarymanagement.{ IvySbt, MakePom }
|
import sbt.internal.librarymanagement.{ IvySbt, MakePom }
|
||||||
|
|
||||||
|
ThisBuild / useIvy := true
|
||||||
|
|
||||||
lazy val check = taskKey[Unit]("check")
|
lazy val check = taskKey[Unit]("check")
|
||||||
|
|
||||||
val dispatch = "net.databinder.dispatch" %% "dispatch-core" % "0.11.2"
|
val dispatch = "net.databinder.dispatch" %% "dispatch-core" % "0.11.2"
|
||||||
|
|
@ -36,7 +38,7 @@ lazy val root = (project in file(".")).
|
||||||
sys.error("dispatch-core_2.11-0.11.1.jar found when it should NOT be included: " + bcp.toString)
|
sys.error("dispatch-core_2.11-0.11.1.jar found when it should NOT be included: " + bcp.toString)
|
||||||
}
|
}
|
||||||
|
|
||||||
val bPomXml = makePomXml(streams.value.log, (b / makePomConfiguration).value, (b / ivyModule).value)
|
val bPomXml = makePomXml(streams.value.log, (b / makePomConfiguration).value, (b / ivyModule).value.asInstanceOf[IvySbt#Module])
|
||||||
|
|
||||||
val repatchTwitterXml = bPomXml \ "dependencies" \ "dependency" find { d =>
|
val repatchTwitterXml = bPomXml \ "dependencies" \ "dependency" find { d =>
|
||||||
(d \ "groupId").text == "com.eed3si9n" && (d \ "artifactId").text == "repatch-twitter-core_2.11"
|
(d \ "groupId").text == "com.eed3si9n" && (d \ "artifactId").text == "repatch-twitter-core_2.11"
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
libraryDependencies += {
|
||||||
|
val sbtV = sbtVersion.value
|
||||||
|
("org.scala-sbt" % s"sbt-ivy_sbt${sbtV}_${scalaBinaryVersion.value}" % sbtV).intransitive()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
libraryDependencies += {
|
||||||
|
val sbtV = sbtVersion.value
|
||||||
|
("org.scala-sbt" % s"sbt-ivy_sbt${sbtV}_${scalaBinaryVersion.value}" % sbtV).intransitive()
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
ThisBuild / scalaVersion := "2.12.21"
|
ThisBuild / scalaVersion := "2.12.21"
|
||||||
|
ThisBuild / useIvy := true
|
||||||
def configIvyScala =
|
def configIvyScala =
|
||||||
scalaModuleInfo ~= (_ map (_ withCheckExplicit false))
|
scalaModuleInfo ~= (_ map (_ withCheckExplicit false))
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
libraryDependencies += {
|
||||||
|
val sbtV = sbtVersion.value
|
||||||
|
("org.scala-sbt" % s"sbt-ivy_sbt${sbtV}_${scalaBinaryVersion.value}" % sbtV).intransitive()
|
||||||
|
}
|
||||||
|
|
@ -210,21 +210,25 @@ object IvyXml {
|
||||||
shadedConfigOpt: Option[Configuration]
|
shadedConfigOpt: Option[Configuration]
|
||||||
): Setting[Task[T]] =
|
): Setting[Task[T]] =
|
||||||
task := Def.uncached(task.dependsOnTask {
|
task := Def.uncached(task.dependsOnTask {
|
||||||
Def.task {
|
Def.ifS(Def.task { sbt.Keys.useIvy.value })(
|
||||||
val currentProject = {
|
Def.task {
|
||||||
val proj = csrProject.value
|
val currentProject = {
|
||||||
val publications = csrPublications.value
|
val proj = csrProject.value
|
||||||
proj.withPublications(publications)
|
val publications = csrPublications.value
|
||||||
|
proj.withPublications(publications)
|
||||||
|
}
|
||||||
|
val resolved = sbt.Keys.resolvedDependencies.value
|
||||||
|
IvyXml.writeFiles(
|
||||||
|
currentProject,
|
||||||
|
shadedConfigOpt,
|
||||||
|
sbt.Keys.ivySbt.value.asInstanceOf[IvySbt],
|
||||||
|
sbt.Keys.streams.value.log,
|
||||||
|
resolved
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val resolved = sbt.Keys.resolvedDependencies.value
|
)(
|
||||||
IvyXml.writeFiles(
|
Def.task { () }
|
||||||
currentProject,
|
)
|
||||||
shadedConfigOpt,
|
|
||||||
sbt.Keys.ivySbt.value,
|
|
||||||
sbt.Keys.streams.value.log,
|
|
||||||
resolved
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}.value)
|
}.value)
|
||||||
|
|
||||||
private lazy val needsIvyXmlLocal = Seq(publishLocalConfiguration) ++ getPubConf(
|
private lazy val needsIvyXmlLocal = Seq(publishLocalConfiguration) ++ getPubConf(
|
||||||
|
|
@ -0,0 +1,274 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2023, Scala center
|
||||||
|
* Copyright 2011 - 2022, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sbt
|
||||||
|
package plugins
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import org.apache.ivy.core.module.descriptor.{ DependencyDescriptor, ModuleDescriptor }
|
||||||
|
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||||
|
import sbt.Def.{ Initialize, Setting }
|
||||||
|
import sbt.Keys.*
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
|
import sbt.internal.LibraryManagement
|
||||||
|
import sbt.internal.librarymanagement.{ IvyActions, IvySbt, IvyXml, ProjectResolver }
|
||||||
|
import sbt.internal.librarymanagement.ivy.*
|
||||||
|
import sbt.io.syntax.*
|
||||||
|
import sbt.librarymanagement.*
|
||||||
|
import sbt.std.TaskExtra.*
|
||||||
|
import lmcoursier.definitions.{
|
||||||
|
Classifier as CClassifier,
|
||||||
|
Configuration as CConfiguration,
|
||||||
|
Dependency as CDependency,
|
||||||
|
Extension as CExtension,
|
||||||
|
Info as CInfo,
|
||||||
|
Module as CModule,
|
||||||
|
ModuleName as CModuleName,
|
||||||
|
Organization as COrganization,
|
||||||
|
Project as CProject,
|
||||||
|
Publication as CPublication,
|
||||||
|
Type as CType,
|
||||||
|
}
|
||||||
|
import lmcoursier.Inputs
|
||||||
|
import scala.jdk.CollectionConverters.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoPlugin that provides all Ivy-specific functionality.
|
||||||
|
* This plugin overrides the stub defaults in main/ with real Ivy implementations.
|
||||||
|
*/
|
||||||
|
object IvyDependencyPlugin extends AutoPlugin:
|
||||||
|
override def requires = IvyPlugin
|
||||||
|
override def trigger = allRequirements
|
||||||
|
|
||||||
|
override lazy val globalSettings: Seq[Setting[?]] = Seq(
|
||||||
|
updateOptions := UpdateOptions(),
|
||||||
|
)
|
||||||
|
|
||||||
|
override lazy val projectSettings: Seq[Setting[?]] = Seq(
|
||||||
|
ivyConfiguration := Def.uncached(
|
||||||
|
Def
|
||||||
|
.ifS(Def.task { useIvy.value })(
|
||||||
|
Def.task { mkIvyConfiguration.value: Any }
|
||||||
|
)(
|
||||||
|
Def.task { (): Any }
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
),
|
||||||
|
publisher := Def.uncached(
|
||||||
|
Def
|
||||||
|
.ifS(Def.task { useIvy.value })(
|
||||||
|
Def.task {
|
||||||
|
IvyPublisher(ivyConfiguration.value.asInstanceOf[IvyConfiguration])
|
||||||
|
}
|
||||||
|
)(
|
||||||
|
Def.task {
|
||||||
|
Classpaths.defaultPublisher(dependencyResolution.value, fullResolvers.value.toVector)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
),
|
||||||
|
ivySbt := Def.uncached(
|
||||||
|
Def
|
||||||
|
.ifS(Def.task { useIvy.value })(
|
||||||
|
Def.task { ivySbt0.value: Any }
|
||||||
|
)(
|
||||||
|
Def.task { (): Any }
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
),
|
||||||
|
ivyModule := Def.uncached(
|
||||||
|
Def
|
||||||
|
.ifS(Def.task { useIvy.value })(
|
||||||
|
Def.task {
|
||||||
|
val is = ivySbt.value.asInstanceOf[IvySbt]
|
||||||
|
new is.Module(moduleSettings.value): Any
|
||||||
|
}
|
||||||
|
)(
|
||||||
|
Def.task { (): Any }
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
),
|
||||||
|
projectDescriptors := Def.uncached(
|
||||||
|
Def
|
||||||
|
.ifS(Def.task { useIvy.value })(
|
||||||
|
Def.task { depMap.value.asInstanceOf[Map[Any, Any]] }
|
||||||
|
)(
|
||||||
|
Def.task { Map.empty[Any, Any] }
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
),
|
||||||
|
projectResolver := Def.uncached(
|
||||||
|
Def
|
||||||
|
.ifS(Def.task { useIvy.value })(
|
||||||
|
projectResolverTask
|
||||||
|
)(
|
||||||
|
Classpaths.projectResolverTask
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
),
|
||||||
|
csrExtraProjects := Def.uncached(
|
||||||
|
Def
|
||||||
|
.ifS(Def.task { useIvy.value })(
|
||||||
|
coursierExtraProjectsTask
|
||||||
|
)(
|
||||||
|
Def.task { Nil }
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
),
|
||||||
|
) ++ IvyXml.generateIvyXmlSettings() ++ ivyPublishOrSkipSettings
|
||||||
|
|
||||||
|
private lazy val ivySbt0: Initialize[Task[IvySbt]] =
|
||||||
|
Def.task {
|
||||||
|
IvyCredentials.register(credentials.value, streams.value.log)
|
||||||
|
new IvySbt(ivyConfiguration.value.asInstanceOf[IvyConfiguration])
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy val mkIvyConfiguration: Initialize[Task[InlineIvyConfiguration]] =
|
||||||
|
Def.task {
|
||||||
|
val (rs, other) = (fullResolvers.value.toVector, otherResolvers.value.toVector)
|
||||||
|
val s = streams.value
|
||||||
|
Classpaths.warnResolversConflict(rs ++: other, s.log)
|
||||||
|
Classpaths.errorInsecureProtocol(rs ++: other, s.log)
|
||||||
|
InlineIvyConfiguration()
|
||||||
|
.withPaths(ivyPaths.value)
|
||||||
|
.withResolvers(rs)
|
||||||
|
.withOtherResolvers(other)
|
||||||
|
.withModuleConfigurations(moduleConfigurations.value.toVector)
|
||||||
|
.withLock(LibraryManagement.lock(appConfiguration.value))
|
||||||
|
.withChecksums((update / checksums).value.toVector)
|
||||||
|
.withResolutionCacheDir(target.value / "resolution-cache")
|
||||||
|
.withUpdateOptions(updateOptions.value.asInstanceOf[UpdateOptions])
|
||||||
|
.withLog(s.log)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def depMap: Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] =
|
||||||
|
import sbt.TupleSyntax.*
|
||||||
|
(buildDependencies.toTaskable, thisProjectRef.toTaskable, settingsData, streams)
|
||||||
|
.flatMapN { (bd, thisProj, data, s) =>
|
||||||
|
depMap(bd.classpathTransitiveRefs(thisProj), data, s.log)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def depMap(
|
||||||
|
projects: Seq[ProjectRef],
|
||||||
|
data: Def.Settings,
|
||||||
|
log: sbt.util.Logger
|
||||||
|
): Task[Map[ModuleRevisionId, ModuleDescriptor]] =
|
||||||
|
val ivyModules = projects.flatMap { proj =>
|
||||||
|
(proj / ivyModule).get(data)
|
||||||
|
}.join
|
||||||
|
ivyModules.mapN { mod =>
|
||||||
|
mod.map { m => m.asInstanceOf[IvySbt#Module].dependencyMapping(log) }.toMap
|
||||||
|
}
|
||||||
|
|
||||||
|
private def projectResolverTask: Initialize[Task[Resolver]] =
|
||||||
|
projectDescriptors.map { m =>
|
||||||
|
val typedMap = m.asInstanceOf[Map[ModuleRevisionId, ModuleDescriptor]]
|
||||||
|
val resolver = new ProjectResolver(ProjectResolver.InterProject, typedMap)
|
||||||
|
new RawRepository(resolver, resolver.getName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def ivyPublishOrSkipSettings: Seq[Setting[?]] =
|
||||||
|
Seq(
|
||||||
|
deliver := deliverTask(makeIvyXmlConfiguration).value,
|
||||||
|
deliverLocal := deliverTask(makeIvyXmlLocalConfiguration).value,
|
||||||
|
makeIvyXml := deliverTask(makeIvyXmlConfiguration).value,
|
||||||
|
)
|
||||||
|
|
||||||
|
private def deliverTask(config: TaskKey[PublishConfiguration]): Initialize[Task[File]] =
|
||||||
|
Def.task {
|
||||||
|
Def.unit(update.value)
|
||||||
|
if !useIvy.value then sys.error("deliver/makeIvyXml requires useIvy := true")
|
||||||
|
IvyActions.deliver(
|
||||||
|
ivyModule.value.asInstanceOf[IvySbt#Module],
|
||||||
|
config.value,
|
||||||
|
streams.value.log
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy val coursierExtraProjectsTask: Initialize[Task[Seq[CProject]]] =
|
||||||
|
Def.task {
|
||||||
|
val projects = csrInterProjectDependencies.value
|
||||||
|
val projectModules = projects.map(_.module).toSet
|
||||||
|
projectDescriptors.value
|
||||||
|
.map { (k, v) =>
|
||||||
|
val id = k.asInstanceOf[ModuleRevisionId]
|
||||||
|
val desc = v.asInstanceOf[ModuleDescriptor]
|
||||||
|
moduleFromIvy(id) -> desc
|
||||||
|
}
|
||||||
|
.filter { case (module, _) =>
|
||||||
|
!projectModules(module)
|
||||||
|
}
|
||||||
|
.toVector
|
||||||
|
.map { (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.toSeq,
|
||||||
|
configurations,
|
||||||
|
Nil,
|
||||||
|
None,
|
||||||
|
Nil,
|
||||||
|
CInfo("", "", Nil, Nil, None)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def moduleFromIvy(id: ModuleRevisionId): CModule =
|
||||||
|
CModule(
|
||||||
|
COrganization(id.getOrganisation),
|
||||||
|
CModuleName(id.getName),
|
||||||
|
id.getExtraAttributes.asScala.map { (k0, v0) =>
|
||||||
|
k0.asInstanceOf[String] -> v0.asInstanceOf[String]
|
||||||
|
}.toMap
|
||||||
|
)
|
||||||
|
|
||||||
|
private def dependencyFromIvy(
|
||||||
|
desc: DependencyDescriptor
|
||||||
|
): Seq[(CConfiguration, CDependency)] =
|
||||||
|
val id = desc.getDependencyRevisionId
|
||||||
|
val module = moduleFromIvy(id)
|
||||||
|
val exclusions = desc.getAllExcludeRules.map { rule =>
|
||||||
|
val modId = rule.getId.getModuleId
|
||||||
|
(COrganization(modId.getOrganisation), CModuleName(modId.getName))
|
||||||
|
}.toSet
|
||||||
|
val configurations = desc.getModuleConfigurations.toVector
|
||||||
|
.flatMap(Inputs.ivyXmlMappings)
|
||||||
|
|
||||||
|
def dependency(conf: CConfiguration, pub: CPublication) = CDependency(
|
||||||
|
module,
|
||||||
|
id.getRevision,
|
||||||
|
conf,
|
||||||
|
exclusions,
|
||||||
|
pub,
|
||||||
|
optional = false,
|
||||||
|
desc.isTransitive
|
||||||
|
)
|
||||||
|
|
||||||
|
val publications: CConfiguration => CPublication =
|
||||||
|
val artifacts = desc.getAllDependencyArtifacts
|
||||||
|
val m = artifacts.toVector.flatMap { art =>
|
||||||
|
val pub = CPublication(
|
||||||
|
art.getName,
|
||||||
|
CType(art.getType),
|
||||||
|
CExtension(art.getExt()),
|
||||||
|
CClassifier("")
|
||||||
|
)
|
||||||
|
art.getConfigurations.map(CConfiguration(_)).toVector.map { conf =>
|
||||||
|
conf -> pub
|
||||||
|
}
|
||||||
|
}.toMap
|
||||||
|
c => m.getOrElse(c, CPublication("", CType(""), CExtension(""), CClassifier("")))
|
||||||
|
|
||||||
|
configurations.map { (from, to) =>
|
||||||
|
from -> dependency(to, publications(to))
|
||||||
|
}
|
||||||
|
end IvyDependencyPlugin
|
||||||
Loading…
Reference in New Issue