mirror of https://github.com/sbt/sbt.git
[2.x] fix: Fixes publishing platform-specific artifacts (like Scala Native)
**Problem** Platform suffix is absent in published artifacts. #9118 partially solved this. It didn't touch publish-side naming though, so the published files still drop the suffix in three places. **Solution** This fixes - ivyless publication names - CoursierArtifactsTasks.coursierPublicationsTask - ivyless POM <artifactId> (the coordinate written inside the .pom) - PomGenerator.crossVersionDep - Ivy backend (useIvy := true) - CrossVersion.substituteCross via IvyActions
This commit is contained in:
parent
e27f3df021
commit
3b097cc3cc
|
|
@ -106,11 +106,7 @@ private[librarymanagement] abstract class ArtifactFunctions {
|
|||
val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary)
|
||||
val withPlatform = module.crossVersion match {
|
||||
case _: Disabled => artifact.name
|
||||
case _ =>
|
||||
module.platformOpt match {
|
||||
case Some(p) if p.nonEmpty && p != Platform.jvm => s"${artifact.name}_$p"
|
||||
case _ => artifact.name
|
||||
}
|
||||
case _ => CrossVersion.addPlatformSuffix(artifact.name, module.platformOpt, None)
|
||||
}
|
||||
val base = CrossVersion.applyCross(withPlatform, cross)
|
||||
base + "-" + module.revision + classifierStr + "." + artifact.extension
|
||||
|
|
|
|||
|
|
@ -166,6 +166,20 @@ private[librarymanagement] abstract class CrossVersionFunctions {
|
|||
private[sbt] def crossName(name: String, cross: String): String =
|
||||
name + "_" + cross
|
||||
|
||||
/**
|
||||
* Appends the platform suffix (e.g. `native0.5`, `sjs1`) to `name`, preferring an explicit
|
||||
* `platformOpt` over the `projectPlatform`. `""` and `jvm` add no suffix. Keep in sync with
|
||||
* `lmcoursier.FromSbt.addPlatformSuffix` (until lm-coursier moves under sbt).
|
||||
*/
|
||||
private[sbt] def addPlatformSuffix(
|
||||
name: String,
|
||||
platformOpt: Option[String],
|
||||
projectPlatform: Option[String]
|
||||
): String =
|
||||
platformOpt.orElse(projectPlatform) match
|
||||
case Some(p) if p.nonEmpty && p != Platform.jvm => crossName(name, p)
|
||||
case _ => name
|
||||
|
||||
/** Cross-versions `exclude` according to its `crossVersion`. */
|
||||
private[sbt] def substituteCross(
|
||||
exclude: ExclusionRule,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ object FromSbt {
|
|||
}
|
||||
}
|
||||
|
||||
// Duplicate of sbt.librarymanagement.CrossVersion.addPlatformSuffix. Keep the two in sync
|
||||
// until lm-coursier moves under sbt
|
||||
private def addPlatformSuffix(
|
||||
name: String,
|
||||
platformOpt: Option[String],
|
||||
|
|
|
|||
|
|
@ -234,8 +234,18 @@ object IvyActions {
|
|||
}
|
||||
private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] =
|
||||
moduleSettings match {
|
||||
case i: InlineConfiguration => CrossVersion(i.module, i.scalaModuleInfo)
|
||||
case _ => None
|
||||
case i: InlineConfiguration =>
|
||||
// Platform suffix before cross suffix, matching the coordinate (sbt/sbt#9117).
|
||||
CrossVersion(i.module, i.scalaModuleInfo).map { fn => (name: String) =>
|
||||
fn(
|
||||
CrossVersion.addPlatformSuffix(
|
||||
name,
|
||||
i.module.platformOpt,
|
||||
i.scalaModuleInfo.flatMap(_.platform)
|
||||
)
|
||||
)
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
def mapArtifacts(
|
||||
module: ModuleDescriptor,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ object CoursierArtifactsTasks {
|
|||
val projId = sbt.Keys.projectID.value
|
||||
val sv = sbt.Keys.scalaVersion.value
|
||||
val sbv = sbt.Keys.scalaBinaryVersion.value
|
||||
val projectPlatform = sbt.Keys.scalaModuleInfo.value.flatMap(_.platform)
|
||||
val ivyConfs = sbt.Keys.ivyConfigurations.value
|
||||
val extracted = Project.extract(s)
|
||||
import extracted.*
|
||||
|
|
@ -97,8 +98,13 @@ object CoursierArtifactsTasks {
|
|||
|
||||
def artifactPublication(artifact: Artifact) = {
|
||||
|
||||
// Platform suffix before cross suffix, matching the coordinate
|
||||
val base = projId.crossVersion match
|
||||
case _: Disabled => artifact.name
|
||||
case _ =>
|
||||
CrossVersion.addPlatformSuffix(artifact.name, projId.platformOpt, projectPlatform)
|
||||
val name = CrossVersion(projId.crossVersion, sv, sbv)
|
||||
.fold(artifact.name)(_(artifact.name))
|
||||
.fold(base)(_(base))
|
||||
|
||||
CPublication(
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -61,9 +61,14 @@ private[sbt] object PomGenerator:
|
|||
</project>
|
||||
|
||||
private def crossVersionDep(dep: ModuleID, scalaInfo: Option[ScalaModuleInfo]): ModuleID =
|
||||
// Platform suffix before cross suffix, matching the coordinate (sbt/sbt#9117).
|
||||
val base = dep.crossVersion match
|
||||
case _: Disabled => dep.name
|
||||
case _ =>
|
||||
CrossVersion.addPlatformSuffix(dep.name, dep.platformOpt, scalaInfo.flatMap(_.platform))
|
||||
val crossFn = CrossVersion(dep, scalaInfo)
|
||||
val crossDep = crossFn match
|
||||
case Some(fn) => dep.withName(fn(dep.name)).withCrossVersion(CrossVersion.disabled)
|
||||
case Some(fn) => dep.withName(fn(base)).withCrossVersion(CrossVersion.disabled)
|
||||
case None => dep
|
||||
if crossDep.exclusions.isEmpty || scalaInfo.isEmpty then crossDep
|
||||
else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
// sbt/sbt#9117: published artifact names must carry the platform suffix, matching the
|
||||
// coordinate, on both publish backends. `platform` is set directly, as sbt-scala-native does.
|
||||
|
||||
ThisBuild / organization := "com.example"
|
||||
ThisBuild / version := "0.1.0"
|
||||
ThisBuild / scalaVersion := "3.8.3"
|
||||
ThisBuild / csrCacheDirectory := (ThisBuild / baseDirectory).value / "coursier-cache"
|
||||
|
||||
lazy val mavenRepo = settingKey[File]("shared local Maven repo for the consume round-trip")
|
||||
ThisBuild / mavenRepo := (ThisBuild / baseDirectory).value / "maven-repo"
|
||||
|
||||
def expected(name: String) = s"${name}_native0.5_3"
|
||||
|
||||
def producer(useIvyFlag: Boolean): Seq[Setting[?]] = Seq(
|
||||
platform := "native0.5",
|
||||
crossVersion := CrossVersion.binary,
|
||||
useIvy := useIvyFlag,
|
||||
publishMavenStyle := true,
|
||||
ivyPaths := IvyPaths(baseDirectory.value.toString, Some((target.value / "ivy2").toString)),
|
||||
publishTo := Some(MavenCache("platform-publish-local", (ThisBuild / mavenRepo).value))
|
||||
)
|
||||
|
||||
// checkPomArtifactId only for ivyless: there the artifactId comes from PomGenerator (and
|
||||
// resolution does not validate POM content); the Ivy backend's is correct regardless.
|
||||
def ivyLayoutCheck(base: String, checkPomArtifactId: Boolean): Setting[?] =
|
||||
TaskKey[Unit]("check") := {
|
||||
val nm = expected(base)
|
||||
val dir = target.value / "ivy2" / "local" / organization.value / nm / version.value
|
||||
def req(f: File): Unit = assert(f.exists, s"expected $f to exist")
|
||||
req(dir / "jars" / s"$nm.jar")
|
||||
req(dir / "srcs" / s"$nm-sources.jar")
|
||||
val pom = dir / "poms" / s"$nm.pom"
|
||||
req(pom)
|
||||
if (checkPomArtifactId)
|
||||
assert(IO.read(pom).contains(s"<artifactId>$nm</artifactId>"), s"POM artifactId must be $nm: ${IO.read(pom)}")
|
||||
}
|
||||
|
||||
lazy val ivyless = (project in file("ivyless"))
|
||||
.settings(name := "libivyless", producer(false), ivyLayoutCheck("libivyless", checkPomArtifactId = true))
|
||||
|
||||
lazy val ivyfull = (project in file("ivyfull"))
|
||||
.settings(name := "libivyfull", producer(true), ivyLayoutCheck("libivyfull", checkPomArtifactId = false))
|
||||
|
||||
// Must not dependsOn the producers, so the coordinates resolve from the Maven repo rather
|
||||
// than inter-project - otherwise a suffix-dropped published name would not be caught.
|
||||
lazy val consumer = (project in file("consumer"))
|
||||
.settings(
|
||||
publish / skip := true,
|
||||
resolvers += MavenCache("platform-publish-local", (ThisBuild / mavenRepo).value),
|
||||
libraryDependencies += organization.value % expected("libivyless") % version.value,
|
||||
libraryDependencies += organization.value % expected("libivyfull") % version.value
|
||||
)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package lib
|
||||
|
||||
object Lib:
|
||||
def greeting: String = "hi"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package lib
|
||||
|
||||
object Lib:
|
||||
def greeting: String = "hi"
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// sbt-ivy provides the Ivy publish backend exercised by the `ivyfull` project.
|
||||
libraryDependencies += {
|
||||
val sbtV = sbtVersion.value
|
||||
("org.scala-sbt" % s"sbt-ivy_sbt${sbtV}_${scalaBinaryVersion.value}" % sbtV).intransitive()
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# sbt/sbt#9117: published artifact names must carry the platform suffix (_native0.5),
|
||||
# matching the coordinate, on both the ivyless and Ivy backends.
|
||||
|
||||
# publishLocal (ivy layout): filenames + POM artifactId
|
||||
> ivyless/publishLocal
|
||||
> ivyless/check
|
||||
> ivyfull/publishLocal
|
||||
> ivyfull/check
|
||||
|
||||
# publish to a local Maven repo, then resolve the artifacts back under their platform
|
||||
# coordinate
|
||||
> ivyless/publish
|
||||
> ivyfull/publish
|
||||
> consumer/update
|
||||
Loading…
Reference in New Issue