From f454c05fe1ed5c9a6d83703c911a5dd920ff11a3 Mon Sep 17 00:00:00 2001 From: kenji yoshida <6b656e6a69@gmail.com> Date: Sat, 16 May 2026 18:51:07 +0900 Subject: [PATCH] [2.x] refactor: Use scala.util.Using.resource instead of try-finally (#9230) --- .../librarymanagement/ComponentManager.scala | 6 ++---- main-command/src/main/scala/xsbt/IPC.scala | 7 ++++--- .../scala/sbt/internal/ClassLoaderCacheTest.scala | 5 ++--- .../sbt/internal/graph/rendering/TreeView.scala | 11 ++++++----- sbt-app/src/test/scala/sbt/RunFromSourceMain.scala | 7 ++++--- .../src/main/scala/sbt/util/ActionCacheStore.scala | 7 +++---- util-cache/src/main/scala/sbt/util/Digest.scala | 14 ++++++-------- .../scala/sbt/internal/inc/ResourceLoader.scala | 6 +++--- 8 files changed, 30 insertions(+), 33 deletions(-) diff --git a/lm-ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala b/lm-ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala index fa4cd850f..962dc7f95 100644 --- a/lm-ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala +++ b/lm-ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala @@ -7,6 +7,7 @@ import java.io.File import java.util.concurrent.Callable import sbt.util.Logger import sbt.librarymanagement.* +import scala.util.Using /** * A component manager provides access to the pieces of xsbt that are distributed as components. @@ -101,11 +102,8 @@ object IfMissing { object ComponentManager { lazy val (version, timestamp) = { val properties = new java.util.Properties - val propertiesStream = getClass.getResourceAsStream("/xsbt.version.properties") - try { + Using.resource(getClass.getResourceAsStream("/xsbt.version.properties")) { propertiesStream => properties.load(propertiesStream) - } finally { - propertiesStream.close() } (properties.getProperty("version"), properties.getProperty("timestamp")) } diff --git a/main-command/src/main/scala/xsbt/IPC.scala b/main-command/src/main/scala/xsbt/IPC.scala index 9fa842c98..ef71e7ee7 100644 --- a/main-command/src/main/scala/xsbt/IPC.scala +++ b/main-command/src/main/scala/xsbt/IPC.scala @@ -13,6 +13,7 @@ import java.net.{ InetAddress, ServerSocket, Socket } import scala.annotation.tailrec import scala.util.control.NonFatal +import scala.util.Using object IPC { private val portMin = 1025 @@ -23,9 +24,9 @@ object IPC { def client[T](port: Int)(f: IPC => T): T = ipc(new Socket(loopback, port))(f) def pullServer[T](f: Server => T): T = { - val server = makeServer - try f(new Server(server)) - finally server.close() + Using.resource(makeServer) { server => + f(new Server(server)) + } } def unmanagedServer: Server = new Server(makeServer) diff --git a/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala b/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala index f2d0515a7..b63a4cf85 100644 --- a/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala +++ b/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala @@ -14,15 +14,14 @@ import java.nio.file.Files import sbt.internal.classpath.ClassLoaderCache import sbt.io.IO import verify.BasicTestSuite +import scala.util.Using object ClassLoaderCacheTest extends BasicTestSuite: extension (c: ClassLoaderCache) def get(classpath: Seq[File]): ClassLoader = c(classpath.toList) private def withCache[R](f: ClassLoaderCache => R): R = - val cache = new ClassLoaderCache(ClassLoader.getSystemClassLoader) - try f(cache) - finally cache.close() + Using.resource(new ClassLoaderCache(ClassLoader.getSystemClassLoader))(f) test("ClassLoaderCache should make a new loader when cleared"): withCache: cache => diff --git a/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala b/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala index 9dea1d56c..9a9f58f03 100644 --- a/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala +++ b/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala @@ -17,6 +17,7 @@ import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter } import java.io.{ File, FileOutputStream, InputStream, OutputStream } import java.net.URI +import scala.util.Using object TreeView { def createJson(graph: ModuleGraph): String = { @@ -70,11 +71,11 @@ object TreeView { val is = getClass.getClassLoader.getResourceAsStream(resourcePath) require(is ne null, s"Couldn't load '$resourcePath' from classpath.") - val fos = new FileOutputStream(to) - try copy(is, fos) - finally { - is.close() - fos.close() + Using.resource(new FileOutputStream(to)) { fos => + try copy(is, fos) + finally { + is.close() + } } } diff --git a/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala b/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala index c7917f63a..de8e021fa 100644 --- a/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala +++ b/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala @@ -15,6 +15,7 @@ import sbt.util.LoggerContext import scala.annotation.tailrec import scala.sys.process.Process +import scala.util.Using object RunFromSourceMain { def fork( @@ -58,9 +59,9 @@ object RunFromSourceMain { case Array(wd, scalaVersion, sbtVersion, classpath, args*) => if (System.getProperty("jna.nosys") == null) System.setProperty("jna.nosys", "true") if (args.exists(_.startsWith("<"))) System.setProperty("sbt.io.virtual", "false") - val context = LoggerContext() - try run(file(wd), scalaVersion, sbtVersion, classpath, args, context) - finally context.close() + Using.resource(LoggerContext()) { context => + run(file(wd), scalaVersion, sbtVersion, classpath, args, context) + } } // this arrangement is because Scala does not always properly optimize away diff --git a/util-cache/src/main/scala/sbt/util/ActionCacheStore.scala b/util-cache/src/main/scala/sbt/util/ActionCacheStore.scala index cb6c78e47..5cd174640 100644 --- a/util-cache/src/main/scala/sbt/util/ActionCacheStore.scala +++ b/util-cache/src/main/scala/sbt/util/ActionCacheStore.scala @@ -25,6 +25,7 @@ import sbt.internal.util.{ StringVirtualFile1, Util } import sbt.internal.util.codec.ActionResultCodec.given import xsbti.{ FileConverter, HashedVirtualFileRef, PathBasedFile, VirtualFile } import java.io.InputStream +import scala.util.Using /** * An abstraction of a remote or local cache store. @@ -234,11 +235,9 @@ case class DiskActionCacheStore(base: Path, converter: FileConverter) (casBase.toFile / digest.toString.replace("/", "-")).toPath() def putBlob(blob: Path, digest: Digest): Path = - val in = Files.newInputStream(blob) - try + Using.resource(Files.newInputStream(blob)) { in => putBlob(in, digest) - finally - in.close() + } def putBlob(input: InputStream, digest: Digest): Path = val casFile = toCasFile(digest) diff --git a/util-cache/src/main/scala/sbt/util/Digest.scala b/util-cache/src/main/scala/sbt/util/Digest.scala index 86ef90513..2e95324f1 100644 --- a/util-cache/src/main/scala/sbt/util/Digest.scala +++ b/util-cache/src/main/scala/sbt/util/Digest.scala @@ -7,6 +7,7 @@ import java.io.{ BufferedInputStream, InputStream } import java.nio.ByteBuffer import java.nio.file.{ Files, Path } import java.security.{ DigestInputStream, MessageDigest } +import scala.util.Using opaque type Digest = String @@ -43,11 +44,9 @@ object Digest: apply(ref.contentHashStr() + "/" + ref.sizeBytes.toString) def apply(algo: String, path: Path): Digest = - val input = Files.newInputStream(path) - try + Using.resource(Files.newInputStream(path)) { input => apply(algo, hashBytes(algo, input), Files.size(path)) - finally - input.close() + } // used to wrap a Long value as a fake Digest, which will // later be hashed using sha256 anyway. @@ -82,15 +81,14 @@ object Digest: private def hashBytes(algo: String, input: InputStream): Array[Byte] = val BufferSize = 8192 - val bis = BufferedInputStream(input) - val digest = MessageDigest.getInstance(jvmAlgo(algo)) - try + Using.resource(BufferedInputStream(input)) { bis => + val digest = MessageDigest.getInstance(jvmAlgo(algo)) val dis = DigestInputStream(bis, digest) val buffer = new Array[Byte](BufferSize) while dis.read(buffer) >= 0 do () dis.close() digest.digest - finally bis.close() + } private def validateString(s: String): Unit = parse(s) diff --git a/zinc-lm-integration/src/main/scala/sbt/internal/inc/ResourceLoader.scala b/zinc-lm-integration/src/main/scala/sbt/internal/inc/ResourceLoader.scala index d5eddcb71..82ea68cc0 100644 --- a/zinc-lm-integration/src/main/scala/sbt/internal/inc/ResourceLoader.scala +++ b/zinc-lm-integration/src/main/scala/sbt/internal/inc/ResourceLoader.scala @@ -9,6 +9,7 @@ package sbt.internal.inc import java.util.Properties +import scala.util.Using /** Defines utilities to load Java properties from the JVM. */ private[inc] object ResourceLoader { @@ -18,10 +19,9 @@ private[inc] object ResourceLoader { if (resourceUrl eq null) { throw new java.io.FileNotFoundException(s"Resource not found: $resource") } - val propertiesStream = resourceUrl.openStream - try { + Using.resource(resourceUrl.openStream) { propertiesStream => properties.load(propertiesStream) - } finally propertiesStream.close() + } properties }