mirror of https://github.com/sbt/sbt.git
Merge b779fab5dd into b1db6ba44d
This commit is contained in:
commit
b3ea0f20d3
|
|
@ -2782,7 +2782,7 @@ object Classpaths {
|
|||
Seq(
|
||||
publishMavenStyle :== true,
|
||||
sbtPluginPublishLegacyMavenStyle :== false,
|
||||
useIvy :== true,
|
||||
useIvy :== false,
|
||||
publishArtifact :== true,
|
||||
(Test / publishArtifact) :== false
|
||||
)
|
||||
|
|
@ -2912,7 +2912,7 @@ object Classpaths {
|
|||
}.value,
|
||||
publish := LibraryManagement.ivylessPublishTask.tag(Tags.Publish, Tags.Network).value,
|
||||
publishLocal := LibraryManagement.ivylessPublishLocalTask.value,
|
||||
publishM2 := publishOrSkip(publishM2Configuration, publishM2 / skip).value,
|
||||
publishM2 := LibraryManagement.ivylessPublishM2Task.tag(Tags.Publish, Tags.Network).value,
|
||||
credentials ++= Def.uncached {
|
||||
val alreadyContainsCentralCredentials: Boolean = credentials.value.exists {
|
||||
case d: Credentials.DirectCredentials => d.host == Sona.host
|
||||
|
|
@ -3352,8 +3352,11 @@ object Classpaths {
|
|||
import ShowLines.*
|
||||
val report = updateTask.value
|
||||
val log = streams.value.log
|
||||
val module = dependencyResolution.value.moduleDescriptor(
|
||||
moduleSettings.value.asInstanceOf[ModuleDescriptorConfiguration]
|
||||
)
|
||||
val ew =
|
||||
EvictionWarning(ivyModule.value, (evicted / evictionWarningOptions).value, report)
|
||||
EvictionWarning(module, (evicted / evictionWarningOptions).value, report)
|
||||
ew.lines foreach { log.warn(_) }
|
||||
ew.infoAllTheThings foreach { log.info(_) }
|
||||
ew
|
||||
|
|
@ -3721,6 +3724,7 @@ object Classpaths {
|
|||
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, config.value, streams.value.log)
|
||||
}
|
||||
|
||||
|
|
@ -3752,6 +3756,10 @@ object Classpaths {
|
|||
val log = streams.value.log
|
||||
val ref = thisProjectRef.value
|
||||
logSkipPublish(log, ref)
|
||||
} else if (!useIvy.value) {
|
||||
sys.error(
|
||||
"publishOrSkip requires useIvy := true. Use publish/publishLocal for ivyless publishing."
|
||||
)
|
||||
} else {
|
||||
val conf = config.value
|
||||
val log = streams.value.log
|
||||
|
|
@ -4209,10 +4217,10 @@ object Classpaths {
|
|||
|
||||
private[sbt] def depMap: Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] =
|
||||
import sbt.TupleSyntax.*
|
||||
(buildDependencies.toTaskable, thisProjectRef.toTaskable, settingsData, streams).flatMapN {
|
||||
(bd, thisProj, data, s) =>
|
||||
(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],
|
||||
|
|
|
|||
|
|
@ -79,7 +79,9 @@ object GlobalPlugin {
|
|||
val taskInit = Def.task {
|
||||
val intcp = (Runtime / internalDependencyClasspath).value
|
||||
val prods = (Runtime / exportedProducts).value
|
||||
val depMap = projectDescriptors.value + ivyModule.value.dependencyMapping(state.log)
|
||||
val depMap =
|
||||
if useIvy.value then projectDescriptors.value + ivyModule.value.dependencyMapping(state.log)
|
||||
else projectDescriptors.value
|
||||
|
||||
GlobalPluginData(
|
||||
projectID.value,
|
||||
|
|
|
|||
|
|
@ -622,14 +622,23 @@ private[sbt] object LibraryManagement {
|
|||
writeChecksums(ivyXmlFile)
|
||||
else log.warn(s"$ivyXmlFile already exists, skipping (overwrite=$overwrite)")
|
||||
|
||||
// Build a lookup from (type, classifier, ext) to cross-versioned publication name
|
||||
val pubNameLookup: Map[(String, String, String), String] =
|
||||
project.publications.map { (_, pub) =>
|
||||
(pub.`type`.value, pub.classifier.value, pub.ext.value) -> pub.name
|
||||
}.toMap
|
||||
|
||||
// Publish each artifact
|
||||
artifacts.foreach: (artifact, sourceFile) =>
|
||||
val folder = typeToFolder(artifact.`type`)
|
||||
val targetDir = moduleDir / folder
|
||||
|
||||
// Construct filename using module name (includes Scala version suffix) + classifier + extension
|
||||
// Look up the cross-versioned artifact name from publications, fall back to module name
|
||||
val classifierStr = artifact.classifier.getOrElse("")
|
||||
val artName = pubNameLookup
|
||||
.getOrElse((artifact.`type`, classifierStr, artifact.extension), moduleName)
|
||||
val classifier = artifact.classifier.map("-" + _).getOrElse("")
|
||||
val fileName = s"$moduleName$classifier.${artifact.extension}"
|
||||
val fileName = s"$artName$classifier.${artifact.extension}"
|
||||
val targetFile = targetDir / fileName
|
||||
|
||||
if !targetFile.exists || overwrite then
|
||||
|
|
@ -845,7 +854,13 @@ private[sbt] object LibraryManagement {
|
|||
): Unit =
|
||||
if repoBase == null then throw new IllegalArgumentException("repoBase must not be null")
|
||||
val groupId = project.module.organization.value
|
||||
val artifactId = project.module.name.value
|
||||
// Derive artifactId: for sbt 2 plugins, module.name has cross-version (e.g. sbt-example_sbt2_3).
|
||||
// For sbt 1 plugins, mavenArtifactsOfSbtPlugin cross-versions the POM artifact name (e.g. sbt-example_2.12_1.0).
|
||||
val baseModuleName = project.module.name.value
|
||||
val pomArtName = artifacts.collectFirst { case (a, _) if a.`type` == "pom" => a.name }
|
||||
val artifactId = pomArtName match
|
||||
case Some(name) if name.startsWith(baseModuleName) && name != baseModuleName => name
|
||||
case _ => baseModuleName
|
||||
val version = project.version
|
||||
val groupPath = groupId.replace('.', '/')
|
||||
val versionDir = new File(repoBase, s"$groupPath/$artifactId/$version")
|
||||
|
|
@ -878,7 +893,13 @@ private[sbt] object LibraryManagement {
|
|||
if baseUrl == null || baseUrl.trim.isEmpty then
|
||||
throw new IllegalArgumentException("baseUrl must not be null or empty")
|
||||
val groupId = project.module.organization.value
|
||||
val artifactId = project.module.name.value
|
||||
// Derive artifactId: for sbt 2 plugins, module.name has cross-version (e.g. sbt-example_sbt2_3).
|
||||
// For sbt 1 plugins, mavenArtifactsOfSbtPlugin cross-versions the POM artifact name (e.g. sbt-example_2.12_1.0).
|
||||
val baseModuleName = project.module.name.value
|
||||
val pomArtName = artifacts.collectFirst { case (a, _) if a.`type` == "pom" => a.name }
|
||||
val artifactId = pomArtName match
|
||||
case Some(name) if name.startsWith(baseModuleName) && name != baseModuleName => name
|
||||
case _ => baseModuleName
|
||||
val version = project.version
|
||||
val directCreds = credentials.collect:
|
||||
case d: Credentials.DirectCredentials => d
|
||||
|
|
@ -939,8 +960,13 @@ private[sbt] object LibraryManagement {
|
|||
if (normalized.startsWith("file:")) new File(new java.net.URI(normalized))
|
||||
else new File(normalized)
|
||||
val repoDir = localRepoBase.getAbsoluteFile
|
||||
log.info(s"Ivyless publish to file repo: $repoDir")
|
||||
ivylessPublishLocal(project, artifacts, checksumAlgorithms, repoDir, overwrite, log)
|
||||
val isMavenLayout = fileRepo.patterns.isMavenCompatible
|
||||
if isMavenLayout then
|
||||
log.info(s"Ivyless publish (Maven layout) to file repo: $repoDir")
|
||||
ivylessPublishMavenToFile(project, artifacts, checksumAlgorithms, repoDir, overwrite, log)
|
||||
else
|
||||
log.info(s"Ivyless publish (Ivy layout) to file repo: $repoDir")
|
||||
ivylessPublishLocal(project, artifacts, checksumAlgorithms, repoDir, overwrite, log)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1003,15 +1029,26 @@ private[sbt] object LibraryManagement {
|
|||
val repoDir =
|
||||
(if (baseStr.startsWith("file:")) new File(new java.net.URI(baseStr))
|
||||
else new File(baseStr)).getAbsoluteFile
|
||||
log.info(s"Ivyless publish to file repo: $repoDir")
|
||||
ivylessPublishLocal(
|
||||
project,
|
||||
artifacts,
|
||||
config.checksums,
|
||||
repoDir,
|
||||
config.overwrite,
|
||||
log
|
||||
)
|
||||
if pbr.patterns.isMavenCompatible then
|
||||
log.info(s"Ivyless publish (Maven layout) to file repo: $repoDir")
|
||||
ivylessPublishMavenToFile(
|
||||
project,
|
||||
artifacts,
|
||||
config.checksums,
|
||||
repoDir,
|
||||
config.overwrite,
|
||||
log
|
||||
)
|
||||
else
|
||||
log.info(s"Ivyless publish (Ivy layout) to file repo: $repoDir")
|
||||
ivylessPublishLocal(
|
||||
project,
|
||||
artifacts,
|
||||
config.checksums,
|
||||
repoDir,
|
||||
config.overwrite,
|
||||
log
|
||||
)
|
||||
case mavenCache: sbt.librarymanagement.MavenCache =>
|
||||
ivylessPublishMavenToFile(
|
||||
project,
|
||||
|
|
@ -1045,18 +1082,13 @@ private[sbt] object LibraryManagement {
|
|||
log
|
||||
)
|
||||
else
|
||||
log.warn(s"Ivyless Maven publish: unsupported root '$root'. Falling back to Ivy.")
|
||||
val conf = publishConfiguration.value
|
||||
val module = ivyModule.value
|
||||
publisher.value.publish(module, conf, log)
|
||||
case _ =>
|
||||
log.warn(
|
||||
"Ivyless publish only supports URLRepository, FileRepository, or MavenRepository. Falling back to Ivy."
|
||||
sys.error(
|
||||
s"Ivyless Maven publish: unsupported root '$root'. Set useIvy := true or use a supported repository (http/https/file)."
|
||||
)
|
||||
case other =>
|
||||
sys.error(
|
||||
s"Ivyless publish does not support ${other.getClass.getName}. Set useIvy := true or use URLRepository, FileRepository, or MavenRepository."
|
||||
)
|
||||
val conf = publishConfiguration.value
|
||||
val module = ivyModule.value
|
||||
val publisherInterface = publisher.value
|
||||
publisherInterface.publish(module, conf, log)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -1104,4 +1136,48 @@ private[sbt] object LibraryManagement {
|
|||
}
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* Task initializer for ivyless publishM2 (publish to local Maven ~/.m2 repository).
|
||||
* Uses Def.ifS for proper selective functor behavior.
|
||||
*/
|
||||
def ivylessPublishM2Task: Def.Initialize[Task[Unit]] =
|
||||
import Keys.*
|
||||
Def.ifS(Def.task { (publishM2 / skip).value })(
|
||||
// skip = true
|
||||
Def.task {
|
||||
val log = streams.value.log
|
||||
val ref = thisProjectRef.value
|
||||
log.debug(s"Skipping publishM2 for ${Reference.display(ref)}")
|
||||
}
|
||||
)(
|
||||
// skip = false
|
||||
Def.ifS(Def.task { useIvy.value })(
|
||||
// useIvy = true: use Ivy-based publisher
|
||||
Def.task {
|
||||
val log = streams.value.log
|
||||
val conf = publishM2Configuration.value
|
||||
val module = ivyModule.value
|
||||
val publisherInterface = publisher.value
|
||||
publisherInterface.publish(module, conf, log)
|
||||
}
|
||||
)(
|
||||
// useIvy = false: use ivyless publisher to Maven local
|
||||
Def.task {
|
||||
val log = streams.value.log
|
||||
val project = csrProject.value.withPublications(csrPublications.value)
|
||||
val config = publishM2Configuration.value
|
||||
val artifacts = config.artifacts.map { case (a, f) => (a, f) }
|
||||
val m2Repo = Resolver.publishMavenLocal
|
||||
ivylessPublishMavenToFile(
|
||||
project,
|
||||
artifacts,
|
||||
config.checksums,
|
||||
m2Repo.rootFile,
|
||||
config.overwrite,
|
||||
log
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
ThisBuild / csrCacheDirectory := (ThisBuild / baseDirectory).value / "coursier-cache"
|
||||
ThisBuild / organization := "org.example"
|
||||
ThisBuild / version := "1.0"
|
||||
ThisBuild / useIvy := true
|
||||
|
||||
lazy val a = project.settings(common).settings(
|
||||
// verifies that a can be published as an ivy.xml file and preserve the extra artifact information,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ val descriptionValue = "This is just a test"
|
|||
val homepageValue = "http://example.com"
|
||||
|
||||
lazy val root = (project in file(".")) settings(
|
||||
useIvy := true,
|
||||
name := "ivy-xml-test",
|
||||
description := descriptionValue,
|
||||
homepage := Some(url(homepageValue)),
|
||||
|
|
|
|||
Loading…
Reference in New Issue