Apply Scala 3 optional brace style to all sbtw sources

Per contributing-docs/03_coding_style.md: object/trait with : and end,
if/while with then/do, fewer braces, colon syntax for lambdas.
This commit is contained in:
bitloi 2026-02-16 01:16:55 +01:00
parent a1ec294a6d
commit 72e3b14f30
5 changed files with 111 additions and 147 deletions

View File

@ -4,20 +4,20 @@ import java.io.File
import scala.io.Source
import scala.util.Using
object ConfigLoader {
object ConfigLoader:
def loadLines(file: File): Seq[String] =
if (!file.isFile) Nil
if !file.isFile then Nil
else
try
Using.resource(Source.fromFile(file))(_.getLines().toList.flatMap { line =>
Using.resource(Source.fromFile(file))(_.getLines().toList.flatMap: line =>
val trimmed = line.trim
if (trimmed.isEmpty || trimmed.startsWith("#")) Nil
if trimmed.isEmpty || trimmed.startsWith("#") then Nil
else Seq(trimmed)
})
)
catch { case _: Exception => Nil }
def loadSbtOpts(cwd: File, sbtHome: File): Seq[String] = {
def loadSbtOpts(cwd: File, sbtHome: File): Seq[String] =
val fromProject = new File(cwd, ".sbtopts")
val fromConfig = new File(sbtHome, "conf/sbtopts")
val fromEtc = new File("/etc/sbt/sbtopts")
@ -28,38 +28,34 @@ object ConfigLoader {
val fromEtcLines = loadLines(fromEtc)
val fromSbtConfigLines = loadLines(fromSbtConfig)
(fromEtcLines ++ fromConfigLines ++ fromSbtConfigLines ++ fromEnv ++ fromProjectLines).toSeq
}
def loadJvmOpts(cwd: File): Seq[String] = {
def loadJvmOpts(cwd: File): Seq[String] =
val fromProject = new File(cwd, ".jvmopts")
val fromEnv = sys.env.get("JAVA_OPTS").toSeq.flatMap(_.split("\\s+").filter(_.nonEmpty))
fromEnv ++ loadLines(fromProject)
}
private def stripJ(s: String): String = if (s.startsWith("-J")) s.substring(2).trim else s
private def stripJ(s: String): String = if s.startsWith("-J") then s.substring(2).trim else s
def defaultJavaOpts: Seq[String] = Seq("-Dfile.encoding=UTF-8")
def defaultSbtOpts: Seq[String] = Nil
def sbtVersionFromBuildProperties(projectDir: File): Option[String] = {
def sbtVersionFromBuildProperties(projectDir: File): Option[String] =
val f = new File(projectDir, "project/build.properties")
if (!f.isFile) return None
try
Using.resource(Source.fromFile(f)) { src =>
src
.getLines()
.map(_.trim)
.filterNot(_.startsWith("#"))
.find(line => line.startsWith("sbt.version") && (line.contains("=")))
.flatMap { line =>
val eq = line.indexOf('=')
if (eq >= 0) Some(line.substring(eq + 1).trim).filter(_.nonEmpty)
else None
}
}
catch { case _: Exception => None }
}
if !f.isFile then None
else
try
Using.resource(Source.fromFile(f)): src =>
src
.getLines()
.map(_.trim)
.filterNot(_.startsWith("#"))
.find(line => line.startsWith("sbt.version") && line.contains("="))
.flatMap: line =>
val eq = line.indexOf('=')
if eq >= 0 then Some(line.substring(eq + 1).trim).filter(_.nonEmpty)
else None
catch { case _: Exception => None }
def isSbtProjectDir(dir: File): Boolean =
new File(dir, "build.sbt").isFile || new File(dir, "project/build.properties").isFile
}
end ConfigLoader

View File

@ -36,7 +36,7 @@ case class LauncherOptions(
sbtNew: Boolean = false,
)
object LauncherOptions {
object LauncherOptions:
val defaultMemMb = 1024
val initSbtVersion = "_to_be_replaced"
}
end LauncherOptions

View File

@ -3,157 +3,141 @@ package sbtw
import java.io.File
import scala.sys.process.*
object Main {
object Main:
def main(args: Array[String]): Unit = {
def main(args: Array[String]): Unit =
val cwd = new File(sys.props("user.dir"))
val sbtHome = new File(sys.env.get("SBT_HOME").getOrElse {
sys.env.get("SBT_BIN_DIR").map(d => new File(d).getParent).getOrElse(cwd.getAbsolutePath)
})
val sbtHome = new File(
sys.env
.get("SBT_HOME")
.getOrElse:
sys.env.get("SBT_BIN_DIR").map(d => new File(d).getParent).getOrElse(cwd.getAbsolutePath)
)
val sbtBinDir = new File(sbtHome, "bin")
val fileSbtOpts = ConfigLoader.loadSbtOpts(cwd, sbtHome)
val fileArgs = fileSbtOpts.flatMap(_.split("\\s+").filter(_.nonEmpty))
val allArgs = fileArgs ++ args
ArgParser.parse(allArgs.toArray) match {
ArgParser.parse(allArgs.toArray) match
case None => System.exit(1)
case Some(opts) =>
val exitCode = run(cwd, sbtHome, sbtBinDir, opts)
System.exit(if (exitCode == 0) 0 else 1)
}
}
System.exit(if exitCode == 0 then 0 else 1)
private def run(cwd: File, sbtHome: File, sbtBinDir: File, opts: LauncherOptions): Int = {
if (opts.help) return printUsage()
if (opts.version || opts.numericVersion || opts.scriptVersion) {
private def run(cwd: File, sbtHome: File, sbtBinDir: File, opts: LauncherOptions): Int =
if opts.help then return printUsage()
if opts.version || opts.numericVersion || opts.scriptVersion then
return handleVersionCommands(cwd, sbtHome, sbtBinDir, opts)
}
if (opts.shutdownAll) {
if opts.shutdownAll then
val javaCmd = Runner.findJavaCmd(opts.javaHome)
return Runner.shutdownAll(javaCmd)
}
if (!opts.allowEmpty && !opts.sbtNew && !ConfigLoader.isSbtProjectDir(cwd)) {
if !opts.allowEmpty && !opts.sbtNew && !ConfigLoader.isSbtProjectDir(cwd) then
System.err.println(
"[error] Neither build.sbt nor a 'project' directory in the current directory: " + cwd
)
System.err.println("[error] run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'.")
return 1
}
val buildPropsVersion = ConfigLoader.sbtVersionFromBuildProperties(cwd)
val clientOpt = opts.client || sys.env.get("SBT_NATIVE_CLIENT").contains("true")
val useNativeClient = shouldRunNativeClient(opts.copy(client = clientOpt), buildPropsVersion)
if (useNativeClient) {
if useNativeClient then
val scriptPath = sbtBinDir.getAbsolutePath.replace("\\", "/") + "/sbt.bat"
return Runner.runNativeClient(sbtBinDir, scriptPath, opts)
}
val javaCmd = Runner.findJavaCmd(opts.javaHome)
val javaVer = Runner.javaVersion(javaCmd)
if (javaVer > 0 && javaVer < 8) {
if javaVer > 0 && javaVer < 8 then
System.err.println("[error] sbt requires at least JDK 8+, you have " + javaVer)
return 1
}
val sbtJar = opts.sbtJar
.filter(p => new File(p).isFile)
.getOrElse(new File(sbtBinDir, "sbt-launch.jar").getAbsolutePath)
if (!new File(sbtJar).isFile) {
if !new File(sbtJar).isFile then
System.err.println("[error] Launcher jar not found: " + sbtJar)
return 1
}
var javaOpts = ConfigLoader.loadJvmOpts(cwd)
if (javaOpts.isEmpty) javaOpts = ConfigLoader.defaultJavaOpts
if javaOpts.isEmpty then javaOpts = ConfigLoader.defaultJavaOpts
var sbtOpts = Runner.buildSbtOpts(opts)
val (residualJava, bootArgs) = Runner.splitResidual(opts.residual)
javaOpts = javaOpts ++ residualJava
val (finalJava, finalSbt) = if (opts.mem.isDefined) {
val (finalJava, finalSbt) = if opts.mem.isDefined then
val evictedJava = Memory.evictMemoryOpts(javaOpts)
val evictedSbt = Memory.evictMemoryOpts(sbtOpts)
val memOpts = Memory.addMemory(opts.mem.get, javaVer)
(evictedJava ++ memOpts, evictedSbt)
} else {
Memory.addDefaultMemory(javaOpts, sbtOpts, javaVer, LauncherOptions.defaultMemMb)
}
else Memory.addDefaultMemory(javaOpts, sbtOpts, javaVer, LauncherOptions.defaultMemMb)
sbtOpts = finalSbt
if (!opts.noHideJdkWarnings && javaVer == 25) {
if !opts.noHideJdkWarnings && javaVer == 25 then
sbtOpts = sbtOpts ++ Seq(
"--sun-misc-unsafe-memory-access=allow",
"--enable-native-access=ALL-UNNAMED"
)
}
val javaOptsWithDebug = opts.jvmDebug.fold(finalJava)(port =>
finalJava :+ s"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$port"
)
Runner.runJvm(javaCmd, javaOptsWithDebug, sbtOpts, sbtJar, bootArgs, opts.verbose)
}
private def shouldRunNativeClient(
opts: LauncherOptions,
buildPropsVersion: Option[String]
): Boolean = {
if (opts.sbtNew) return false
if (opts.jvmClient) return false
): Boolean =
if opts.sbtNew then return false
if opts.jvmClient then return false
val version = buildPropsVersion.getOrElse(LauncherOptions.initSbtVersion)
val parts = version.split("[.-]").take(2).flatMap(s => scala.util.Try(s.toInt).toOption)
val (major, minor) = (parts.lift(0).getOrElse(0), parts.lift(1).getOrElse(0))
if (major >= 2) !opts.server
else if (major >= 1 && minor >= 4) opts.client
if major >= 2 then !opts.server
else if major >= 1 && minor >= 4 then opts.client
else false
}
private def handleVersionCommands(
cwd: File,
sbtHome: File,
sbtBinDir: File,
opts: LauncherOptions
): Int = {
if (opts.scriptVersion) {
): Int =
if opts.scriptVersion then
println(LauncherOptions.initSbtVersion)
return 0
}
val javaCmd = Runner.findJavaCmd(opts.javaHome)
val sbtJar = opts.sbtJar
.filter(p => new File(p).isFile)
.getOrElse(new File(sbtBinDir, "sbt-launch.jar").getAbsolutePath)
if (!new File(sbtJar).isFile) {
if !new File(sbtJar).isFile then
System.err.println("[error] Launcher jar not found for version check")
return 1
}
if (opts.numericVersion) {
try {
if opts.numericVersion then
try
val out = Process(Seq(javaCmd, "-jar", sbtJar, "sbtVersion")).!!
println(out.linesIterator.toSeq.lastOption.map(_.trim).getOrElse(""))
return 0
} catch { case _: Exception => return 1 }
}
if (opts.version) {
if (ConfigLoader.isSbtProjectDir(cwd)) {
catch { case _: Exception => return 1 }
if opts.version then
if ConfigLoader.isSbtProjectDir(cwd) then
val out =
try Process(Seq(javaCmd, "-jar", sbtJar, "sbtVersion")).!!
catch { case _: Exception => "" }
val ver = out.linesIterator.toSeq.lastOption.map(_.trim).getOrElse("")
println("sbt version in this project: " + ver)
}
println("sbt runner version: " + LauncherOptions.initSbtVersion)
System.err.println("[info] sbt runner (sbtw) is a runner to run any declared version of sbt.")
System.err.println(
"[info] Actual version of sbt is declared using project\\build.properties for each build."
)
return 0
}
0
}
private def printUsage(): Int = {
private def printUsage(): Int =
println("""
|Usage: sbtw [options]
|
@ -177,5 +161,4 @@ object Main {
| -J-X pass -X to the JVM (-J is stripped)
|""".stripMargin)
0
}
}
end Main

View File

@ -1,6 +1,6 @@
package sbtw
object Memory {
object Memory:
private val memoryOptPrefixes = Set(
"-Xmx",
@ -22,10 +22,10 @@ object Memory {
def evictMemoryOpts(opts: Seq[String]): Seq[String] =
opts.filter(o => !memoryOptPrefixes.exists(p => o.startsWith(p)))
def addMemory(memMb: Int, javaVersion: Int): Seq[String] = {
def addMemory(memMb: Int, javaVersion: Int): Seq[String] =
var codecache = memMb / 8
if (codecache > 512) codecache = 512
if (codecache < 128) codecache = 128
if codecache > 512 then codecache = 512
if codecache < 128 then codecache = 128
val classMetadataSize = codecache * 2
val base = Seq(
s"-Xms${memMb}m",
@ -33,28 +33,24 @@ object Memory {
"-Xss4M",
s"-XX:ReservedCodeCacheSize=${codecache}m"
)
if (javaVersion < 8) base :+ s"-XX:MaxPermSize=${classMetadataSize}m"
if javaVersion < 8 then base :+ s"-XX:MaxPermSize=${classMetadataSize}m"
else base
}
def addDefaultMemory(
javaOpts: Seq[String],
sbtOpts: Seq[String],
javaVersion: Int,
defaultMemMb: Int
): (Seq[String], Seq[String]) = {
): (Seq[String], Seq[String]) =
val fromJava = hasMemoryOpts(javaOpts)
val fromTool =
sys.env.get("JAVA_TOOL_OPTIONS").exists(s => hasMemoryOpts(s.split("\\s+").toSeq))
val fromJdk = sys.env.get("JDK_JAVA_OPTIONS").exists(s => hasMemoryOpts(s.split("\\s+").toSeq))
val fromSbt = hasMemoryOpts(sbtOpts)
if (fromJava || fromTool || fromJdk || fromSbt)
(javaOpts, sbtOpts)
else {
if fromJava || fromTool || fromJdk || fromSbt then (javaOpts, sbtOpts)
else
val evictedJava = evictMemoryOpts(javaOpts)
val evictedSbt = evictMemoryOpts(sbtOpts)
val memOpts = addMemory(defaultMemMb, javaVersion)
(evictedJava ++ memOpts, evictedSbt)
}
}
}
end Memory

View File

@ -4,13 +4,13 @@ import java.io.File
import java.lang.ProcessBuilder as JProcessBuilder
import scala.sys.process.*
object Runner {
object Runner:
def findJavaCmd(javaHome: Option[String]): String = {
val cmd = javaHome match {
def findJavaCmd(javaHome: Option[String]): String =
val cmd = javaHome match
case Some(h) =>
val exe = new File(h, "bin/java.exe")
if (exe.isFile) exe.getAbsolutePath
if exe.isFile then exe.getAbsolutePath
else
sys.env
.get("JAVACMD")
@ -23,31 +23,28 @@ object Runner {
.get("JAVACMD")
.orElse(sys.env.get("JAVA_HOME").map(h => new File(h, "bin/java.exe").getAbsolutePath))
.getOrElse("java")
}
cmd.replace("\"", "")
}
def javaVersion(javaCmd: String): Int = {
try {
def javaVersion(javaCmd: String): Int =
try
val pb = Process(Seq(javaCmd, "-Xms32M", "-Xmx32M", "-version"))
val out = pb.!!
val line = out.linesIterator.find(_.contains("version")).getOrElse("")
val quoted = line.split("\"").lift(1).getOrElse("")
val parts = quoted.replaceFirst("^1\\.", "").split("[.-_]")
val major = parts.headOption.flatMap(s => scala.util.Try(s.toInt).toOption).getOrElse(0)
if (quoted.startsWith("1.") && parts.nonEmpty)
if quoted.startsWith("1.") && parts.nonEmpty then
scala.util.Try(parts(0).toInt).toOption.getOrElse(major)
else major
} catch { case _: Exception => 0 }
}
catch { case _: Exception => 0 }
def buildSbtOpts(opts: LauncherOptions): Seq[String] = {
def buildSbtOpts(opts: LauncherOptions): Seq[String] =
var s: Seq[String] = Nil
if (opts.debug) s = s :+ "-debug"
if (opts.debugInc) s = s :+ "-Dxsbt.inc.debug=true"
if (opts.noColors) s = s :+ "-Dsbt.log.noformat=true"
if (opts.noGlobal) s = s :+ "-Dsbt.global.base=project/.sbtboot"
if (opts.noShare)
if opts.debug then s = s :+ "-debug"
if opts.debugInc then s = s :+ "-Dxsbt.inc.debug=true"
if opts.noColors then s = s :+ "-Dsbt.log.noformat=true"
if opts.noGlobal then s = s :+ "-Dsbt.global.base=project/.sbtboot"
if opts.noShare then
s = s ++ Seq(
"-Dsbt.global.base=project/.sbtboot",
"-Dsbt.boot.directory=project/.boot",
@ -60,30 +57,27 @@ object Runner {
opts.sbtCache.foreach(v => s = s :+ s"-Dsbt.global.localcache=$v")
opts.ivy.foreach(v => s = s :+ s"-Dsbt.ivy.home=$v")
opts.color.foreach(v => s = s :+ s"-Dsbt.color=$v")
if (opts.timings) s = s ++ Seq("-Dsbt.task.timings=true", "-Dsbt.task.timings.on.shutdown=true")
if (opts.traces) s = s :+ "-Dsbt.traces=true"
if (opts.noServer) s = s ++ Seq("-Dsbt.io.virtual=false", "-Dsbt.server.autostart=false")
if (opts.jvmClient) s = s :+ "--client"
if opts.timings then
s = s ++ Seq("-Dsbt.task.timings=true", "-Dsbt.task.timings.on.shutdown=true")
if opts.traces then s = s :+ "-Dsbt.traces=true"
if opts.noServer then s = s ++ Seq("-Dsbt.io.virtual=false", "-Dsbt.server.autostart=false")
if opts.jvmClient then s = s :+ "--client"
s
}
def runNativeClient(sbtBinDir: File, scriptPath: String, opts: LauncherOptions): Int = {
def runNativeClient(sbtBinDir: File, scriptPath: String, opts: LauncherOptions): Int =
val sbtn = new File(sbtBinDir, "sbtn-x86_64-pc-win32.exe")
if (!sbtn.isFile) {
if !sbtn.isFile then
System.err.println("[error] sbtn-x86_64-pc-win32.exe not found in " + sbtBinDir)
return 1
}
val args = Seq("--sbt-script=" + scriptPath.replace(" ", "%20")) ++
(if (opts.verbose) Seq("-v") else Nil) ++
(if opts.verbose then Seq("-v") else Nil) ++
opts.residual
val cmd = sbtn.getAbsolutePath +: args
if (opts.verbose) {
if opts.verbose then
System.err.println("# running native client")
cmd.foreach(a => System.err.println(a))
}
val proc = Process(cmd, None, "SBT_SCRIPT" -> scriptPath)
proc.!
}
def runJvm(
javaCmd: String,
@ -109,44 +103,39 @@ object Runner {
p.exitValue()
finally if p.isAlive then p.destroy()
def shutdownAll(javaCmd: String): Int = {
try {
def shutdownAll(javaCmd: String): Int =
try
val jpsOut = Process(Seq("jps", "-lv")).!!
val pids = jpsOut.linesIterator
.filter(_.contains("xsbt.boot.Boot"))
.flatMap { line =>
.flatMap: line =>
val pidStr = line.trim.takeWhile(_.isDigit)
if (pidStr.nonEmpty) scala.util.Try(pidStr.toLong).toOption else None
}
if pidStr.nonEmpty then scala.util.Try(pidStr.toLong).toOption else None
.toList
pids.foreach { pid =>
pids.foreach: pid =>
try Process(Seq("taskkill", "/F", "/PID", pid.toString)).!
catch { case _: Exception => }
}
System.err.println(s"shutdown ${pids.size} sbt processes")
0
} catch { case _: Exception => 1 }
}
catch { case _: Exception => 1 }
def splitResidual(residual: Seq[String]): (Seq[String], Seq[String]) = {
def splitResidual(residual: Seq[String]): (Seq[String], Seq[String]) =
var javaOpts: Seq[String] = Nil
var bootArgs: Seq[String] = Nil
var i = 0
while (i < residual.size) {
while i < residual.size do
val a = residual(i)
if (a.startsWith("-J")) javaOpts = javaOpts :+ a.drop(2)
else if (a.startsWith("-X")) javaOpts = javaOpts :+ a
else if (a.startsWith("-D") && a.contains("=")) bootArgs = bootArgs :+ a
else if (a.startsWith("-D") && i + 1 < residual.size) {
if a.startsWith("-J") then javaOpts = javaOpts :+ a.drop(2)
else if a.startsWith("-X") then javaOpts = javaOpts :+ a
else if a.startsWith("-D") && a.contains("=") then bootArgs = bootArgs :+ a
else if a.startsWith("-D") && i + 1 < residual.size then
bootArgs = bootArgs :+ s"$a=${residual(i + 1)}"
i += 1
} else if (a.startsWith("-XX") && a.contains("=")) bootArgs = bootArgs :+ a
else if (a.startsWith("-XX") && i + 1 < residual.size) {
else if a.startsWith("-XX") && a.contains("=") then bootArgs = bootArgs :+ a
else if a.startsWith("-XX") && i + 1 < residual.size then
bootArgs = bootArgs :+ s"$a=${residual(i + 1)}"
i += 1
} else bootArgs = bootArgs :+ a
else bootArgs = bootArgs :+ a
i += 1
}
(javaOpts, bootArgs)
}
}
end Runner