[2.x] fix: Upgrade launcher-package to sbt 1.10.7 and replace dispatch-http (#8465)

Fixes #7826

Changes:
- Upgrade sbt version from 0.13.18 to 1.10.7 in launcher-package/project/build.properties
- Remove dead dispatch-http 0.8.10 dependency from plugins.sbt
- Update sbt-native-packager from 1.7.6 to 1.10.4 (com.github.sbt)
- Update sbt-pgp from 2.1.2 to 2.3.1
- Replace all dispatch.classic._ HTTP calls with Java URL.openStream()

The dispatch-http library is dead and doesn't support sbt 1.x. This change
uses standard Java networking APIs for HTTP downloads, eliminating the
dependency on outdated libraries.

All HTTP download operations now use:
- java.net.URL.openConnection()
- InputStream with buffered reading
- Proper resource cleanup with try-finally blocks

- Removes the sbt-export-repo plugin dependency
- Defines exportRepo and exportRepoDirectory settings locally
- Removes ExportRepoPlugin from dist project
- Fixes exportRepo task to not reference itself

* fix: Update PackageSignerPlugin.scala for sbt 1.x compatibility
- Use withExtension instead of copy(extension = ...) for Artifact
- Update Classpaths.publishConfig to use sbt 1.x signature with all required parameters
- Use new slash syntax for scoped keys (pgpSigner / skip instead of skip in pgpSigner)

* fix: Use computed status instead of status key in PackageSignerPlugin

* fix: Use withRevision instead of copy for ModuleID in build.sbt

- Add scala.sys.process._ import for shell command execution (! method)
- Fix resolvers setting to use new slash syntax and proper Option handling
- Fix publish/publishLocal to use {} instead of () to avoid deprecation warning
- Fix Classpaths.publishTask to use variant without delivery key (deprecated since 1.1.1)
- Add scala.sys.process._ import for shell command execution
- Fix publish/publishLocal to use {} instead of ()
- Remove problematic resolvers setting that caused task/setting dependency issues
- Use IvyActions.publish directly instead of deprecated Classpaths.publishTask
- Fix ModuleID.copy to use withRevision
- Fix Artifact.copy to use withExtension
- Use computed status value instead of status key

Build now compiles successfully with sbt 1.10.7.
This commit is contained in:
MkDev11 2026-01-11 04:17:24 -08:00 committed by Eugene Yokota
parent fcb4e0e43c
commit 08469d8b8c
4 changed files with 138 additions and 52 deletions

View File

@ -1,4 +1,5 @@
import scala.util.control.Exception.catching
import scala.sys.process._
import NativePackagerHelper._
import com.typesafe.sbt.packager.SettingsHelper._
import DebianConstants._
@ -69,6 +70,8 @@ val debianBuildId = settingKey[Int]("build id for Debian")
val exportRepoUsingCoursier = taskKey[File]("export Maven style repository")
val exportRepoCsrDirectory = settingKey[File]("")
val exportRepo = taskKey[File]("export Ivy style repository")
val exportRepoDirectory = settingKey[File]("directory for exported repository")
val universalMacPlatform = "universal-apple-darwin"
val x86LinuxPlatform = "x86_64-pc-linux"
@ -109,13 +112,24 @@ val root = (project in file(".")).
sbtLaunchJar := {
val uri = sbtLaunchJarUrl.value
val file = sbtLaunchJarLocation.value
import dispatch.classic._
if(!file.exists) {
// oddly, some places require us to create the file before writing...
IO.touch(file)
val url = new java.net.URL(uri)
val connection = url.openConnection()
val input = connection.getInputStream
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(file))
try Http(url(uri) >>> writer)
finally writer.close()
try {
val buffer = new Array[Byte](8192)
var bytesRead = input.read(buffer)
while (bytesRead != -1) {
writer.write(buffer, 0, bytesRead)
bytesRead = input.read(buffer)
}
} finally {
input.close()
writer.close()
}
}
// TODO - GPG Trust validation.
file
@ -135,12 +149,23 @@ val root = (project in file(".")).
val linuxX86Tar = t / linuxX86ImageTar
val linuxAarch64Tar = t / linuxAarch64ImageTar
val windowsZip = t / windowsImageZip
import dispatch.classic._
if(!macosUniversalTar.exists && !isWindows && sbtIncludeSbtn) {
IO.touch(macosUniversalTar)
val url = new java.net.URL(s"$baseUrl/v$v/$macosUniversalImageTar")
val connection = url.openConnection()
val input = connection.getInputStream
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(macosUniversalTar))
try Http(url(s"$baseUrl/v$v/$macosUniversalImageTar") >>> writer)
finally writer.close()
try {
val buffer = new Array[Byte](8192)
var bytesRead = input.read(buffer)
while (bytesRead != -1) {
writer.write(buffer, 0, bytesRead)
bytesRead = input.read(buffer)
}
} finally {
input.close()
writer.close()
}
val platformDir = t / universalMacPlatform
IO.createDirectory(platformDir)
s"tar zxvf $macosUniversalTar --directory $platformDir".!
@ -148,9 +173,21 @@ val root = (project in file(".")).
}
if(!linuxX86Tar.exists && !isWindows && sbtIncludeSbtn) {
IO.touch(linuxX86Tar)
val url = new java.net.URL(s"$baseUrl/v$v/$linuxX86ImageTar")
val connection = url.openConnection()
val input = connection.getInputStream
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(linuxX86Tar))
try Http(url(s"$baseUrl/v$v/$linuxX86ImageTar") >>> writer)
finally writer.close()
try {
val buffer = new Array[Byte](8192)
var bytesRead = input.read(buffer)
while (bytesRead != -1) {
writer.write(buffer, 0, bytesRead)
bytesRead = input.read(buffer)
}
} finally {
input.close()
writer.close()
}
val platformDir = t / x86LinuxPlatform
IO.createDirectory(platformDir)
s"""tar zxvf $linuxX86Tar --directory $platformDir""".!
@ -158,9 +195,21 @@ val root = (project in file(".")).
}
if(!linuxAarch64Tar.exists && !isWindows && sbtIncludeSbtn) {
IO.touch(linuxAarch64Tar)
val url = new java.net.URL(s"$baseUrl/v$v/$linuxAarch64ImageTar")
val connection = url.openConnection()
val input = connection.getInputStream
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(linuxAarch64Tar))
try Http(url(s"$baseUrl/v$v/$linuxAarch64ImageTar") >>> writer)
finally writer.close()
try {
val buffer = new Array[Byte](8192)
var bytesRead = input.read(buffer)
while (bytesRead != -1) {
writer.write(buffer, 0, bytesRead)
bytesRead = input.read(buffer)
}
} finally {
input.close()
writer.close()
}
val platformDir = t / aarch64LinuxPlatform
IO.createDirectory(platformDir)
s"""tar zxvf $linuxAarch64Tar --directory $platformDir""".!
@ -168,9 +217,21 @@ val root = (project in file(".")).
}
if(!windowsZip.exists && sbtIncludeSbtn) {
IO.touch(windowsZip)
val url = new java.net.URL(s"$baseUrl/v$v/$windowsImageZip")
val connection = url.openConnection()
val input = connection.getInputStream
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(windowsZip))
try Http(url(s"$baseUrl/v$v/$windowsImageZip") >>> writer)
finally writer.close()
try {
val buffer = new Array[Byte](8192)
var bytesRead = input.read(buffer)
while (bytesRead != -1) {
writer.write(buffer, 0, bytesRead)
bytesRead = input.read(buffer)
}
} finally {
input.close()
writer.close()
}
val platformDir = t / x86WindowsPlatform
IO.unzip(windowsZip, platformDir)
IO.move(platformDir / "sbtn.exe", t / x86WindowsImageName)
@ -336,22 +397,22 @@ val root = (project in file(".")).
else Seq[(File, String)](base.getParentFile / "LICENSE" -> "LICENSE", base / "NOTICE" -> "NOTICE")
},
// Misccelaneous publishing stuff...
projectID in Debian := {
// Miscellaneous publishing stuff...
(Debian / projectID) := {
val m = moduleID.value
m.copy(revision = (version in Debian).value)
m.withRevision((Debian / version).value)
},
projectID in Windows := {
(Windows / projectID) := {
val m = moduleID.value
m.copy(revision = (version in Windows).value)
m.withRevision((Windows / version).value)
},
projectID in Rpm := {
(Rpm / projectID) := {
val m = moduleID.value
m.copy(revision = (version in Rpm).value)
m.withRevision((Rpm / version).value)
},
projectID in Universal := {
(Universal / projectID) := {
val m = moduleID.value
m.copy(revision = (version in Universal).value)
m.withRevision((Universal / version).value)
}
)
@ -406,9 +467,7 @@ def makePublishToForConfig(config: Configuration) = {
val resolver = Resolver.url(id, new URL(url))(Patterns(pattern))
Some(resolver)
}
)) ++ Seq(
resolvers ++= ((publishTo in config) apply (_.toSeq)).value
)
))
}
def publishToSettings =
@ -416,19 +475,29 @@ def publishToSettings =
def downloadUrl(uri: URI, out: File): Unit =
{
import dispatch.classic._
if(!out.exists) {
IO.touch(out)
val url = new java.net.URL(uri.toString)
val connection = url.openConnection()
val input = connection.getInputStream
val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(out))
try Http(url(uri.toString) >>> writer)
finally writer.close()
try {
val buffer = new Array[Byte](8192)
var bytesRead = input.read(buffer)
while (bytesRead != -1) {
writer.write(buffer, 0, bytesRead)
bytesRead = input.read(buffer)
}
} finally {
input.close()
writer.close()
}
}
}
def colonName(m: ModuleID): String = s"${m.organization}:${m.name}:${m.revision}"
lazy val dist = (project in file("dist"))
.enablePlugins(ExportRepoPlugin)
.settings(
name := "dist",
scalaVersion := {
@ -437,19 +506,19 @@ lazy val dist = (project in file("dist"))
},
libraryDependencies ++= Seq(sbtActual, jansi, scala212Compiler, scala212Jline, scala212Xml) ++ sbt013ExtraDeps,
exportRepo := {
val old = exportRepo.value
val outDir = exportRepoDirectory.value
sbtVersionToRelease match {
case v if v.startsWith("1.") =>
sys.error("sbt 1.x should use coursier")
case v if v.startsWith("0.13.") =>
val outbase = exportRepoDirectory.value / "org.scala-sbt" / "compiler-interface" / v
val outbase = outDir / "org.scala-sbt" / "compiler-interface" / v
val uribase = s"https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/compiler-interface/$v/"
downloadUrl(uri(uribase + "ivys/ivy.xml"), outbase / "ivys" / "ivy.xml")
downloadUrl(uri(uribase + "jars/compiler-interface.jar"), outbase / "jars" / "compiler-interface.jar")
downloadUrl(uri(uribase + "srcs/compiler-interface-sources.jar"), outbase / "srcs" / "compiler-interface-sources.jar")
case _ =>
}
old
outDir
},
exportRepoDirectory := target.value / "lib" / "local-preloaded",
exportRepoCsrDirectory := exportRepoDirectory.value,
@ -481,7 +550,7 @@ lazy val dist = (project in file("dist"))
outDirectory
},
conflictWarning := ConflictWarning.disable,
publish := (),
publishLocal := (),
publish := {},
publishLocal := {},
resolvers += Resolver.typesafeIvyRepo("releases")
)

View File

@ -1,5 +1,6 @@
import sbt._
import Keys._
import sbt.internal.librarymanagement.IvyActions
import com.jsuereth.sbtpgp.SbtPgp
import com.typesafe.sbt.packager.universal.{ UniversalPlugin, UniversalDeployPlugin }
import com.typesafe.sbt.packager.debian.{ DebianPlugin, DebianDeployPlugin }
@ -21,13 +22,13 @@ object PackageSignerPlugin extends sbt.AutoPlugin {
inConfig(Rpm)(packageSignerSettings)
def subExtension(art: Artifact, ext: String): Artifact =
art.copy(extension = ext)
art.withExtension(ext)
def packageSignerSettings: Seq[Setting[_]] = Seq(
signedArtifacts := {
val artifacts = packagedArtifacts.value
val r = pgpSigner.value
val skipZ = (skip in pgpSigner).value
val skipZ = (pgpSigner / skip).value
val s = streams.value
if (!skipZ) {
artifacts flatMap { case (art, f) =>
@ -39,21 +40,39 @@ object PackageSignerPlugin extends sbt.AutoPlugin {
else artifacts
},
publishSignedConfiguration := Classpaths.publishConfig(
signedArtifacts.value,
None,
publishMavenStyle = publishMavenStyle.value,
deliverIvyPattern = (Compile / packageBin / artifactPath).value.getParent + "/[artifact]-[revision](-[classifier]).[ext]",
status = if (isSnapshot.value) "integration" else "release",
configurations = Vector.empty,
artifacts = signedArtifacts.value.toVector,
checksums = (publish / checksums).value.toVector,
resolverName = Classpaths.getPublishTo(publishTo.value).name,
checksums = (checksums in publish).value,
logging = ivyLoggingLevel.value,
overwrite = isSnapshot.value),
logging = ivyLoggingLevel.value,
overwrite = isSnapshot.value),
publishLocalSignedConfiguration := Classpaths.publishConfig(
signedArtifacts.value,
None,
publishMavenStyle = publishMavenStyle.value,
deliverIvyPattern = (Compile / packageBin / artifactPath).value.getParent + "/[artifact]-[revision](-[classifier]).[ext]",
status = if (isSnapshot.value) "integration" else "release",
configurations = Vector.empty,
artifacts = signedArtifacts.value.toVector,
checksums = (publish / checksums).value.toVector,
resolverName = "local",
checksums = (checksums in publish).value,
logging = ivyLoggingLevel.value,
overwrite = isSnapshot.value),
publishSigned := Classpaths.publishTask(publishSignedConfiguration, deliver).value,
publishLocalSigned := Classpaths.publishTask(publishLocalSignedConfiguration, deliver).value
logging = ivyLoggingLevel.value,
overwrite = isSnapshot.value),
publishSigned := Def.taskDyn {
val config = publishSignedConfiguration.value
val s = streams.value
Def.task {
IvyActions.publish(ivyModule.value, config, s.log)
}
}.value,
publishLocalSigned := Def.taskDyn {
val config = publishLocalSignedConfiguration.value
val s = streams.value
Def.task {
IvyActions.publish(ivyModule.value, config, s.log)
}
}.value
)
}

View File

@ -1 +1 @@
sbt.version=0.13.18
sbt.version=1.10.7

View File

@ -1,4 +1,2 @@
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.7.6")
libraryDependencies += "net.databinder" %% "dispatch-http" % "0.8.10"
addSbtPlugin("com.eed3si9n" % "sbt-export-repo" % "0.1.1")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.10.4")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1")