mirror of https://github.com/sbt/sbt.git
[2.x] fix: Fixes double quotes handling in fork mode (#8765)
When using the arguments file (`@argsfile`) mechanism for forked runs,
double quotes inside arguments were not escaped, causing the JVM's
argument file parser to strip them. For example, passing `{"a":1}` as
an argument would result in `{a:1}`.
Escape `"` as `\"` in `createArgumentsFile`, matching the existing
backslash escaping, so the JVM correctly round-trips quoted arguments.
Fixes sbt/sbt#7129
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c031bdd9b1
commit
87414a8733
|
|
@ -166,7 +166,7 @@ object Fork {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an arguments file from a sequence of command line arguments
|
* Create an arguments file from a sequence of command line arguments
|
||||||
* by quoting each argument to a line with escaped backslashes
|
* by quoting each argument to a line with escaped backslashes and double quotes
|
||||||
*
|
*
|
||||||
* @param options command line options to write to the args file
|
* @param options command line options to write to the args file
|
||||||
* @return
|
* @return
|
||||||
|
|
@ -178,7 +178,7 @@ object Fork {
|
||||||
val pw = new PrintWriter(file)
|
val pw = new PrintWriter(file)
|
||||||
options.foreach { option =>
|
options.foreach { option =>
|
||||||
pw.write("\"")
|
pw.write("\"")
|
||||||
pw.write(option.replace("\\", "\\\\"))
|
pw.write(option.replace("\\", "\\\\").replace("\"", "\\\""))
|
||||||
pw.write("\"")
|
pw.write("\"")
|
||||||
pw.write(System.lineSeparator())
|
pw.write(System.lineSeparator())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,25 @@ object ForkTest extends Properties("Fork") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property("Arguments with double quotes preserved in arguments file mode.") = {
|
||||||
|
val baos = new java.io.ByteArrayOutputStream()
|
||||||
|
val jsonArg = """{"a":1}"""
|
||||||
|
// Pad JVM options to exceed MaxConcatenatedOptionLength (5000) and trigger argsfile mode
|
||||||
|
val padding = "-Dproperty=" + ("X" * 5000)
|
||||||
|
val absClasspath = Path.makeString(requiredEntries)
|
||||||
|
val args = List("-cp", absClasspath, padding, "sbt.echoArgs", jsonArg)
|
||||||
|
val config = ForkOptions()
|
||||||
|
.withOutputStrategy(CustomOutput(baos))
|
||||||
|
.withCanUseArgumentsFile(true)
|
||||||
|
val exitCode =
|
||||||
|
try Fork.java(config, args)
|
||||||
|
catch { case e: Exception => e.printStackTrace(); 1 }
|
||||||
|
val output = baos.toString("UTF-8").trim
|
||||||
|
s"exitCode: $exitCode" |:
|
||||||
|
s"output: '$output', expected: '$jsonArg'" |:
|
||||||
|
(exitCode == 0) && (output == jsonArg)
|
||||||
|
}
|
||||||
|
|
||||||
private def trimClasspath(cp: String): String =
|
private def trimClasspath(cp: String): String =
|
||||||
if (cp.length > MaximumClasspathLength) {
|
if (cp.length > MaximumClasspathLength) {
|
||||||
val lastEntryI = cp.lastIndexOf(File.pathSeparatorChar.toInt, MaximumClasspathLength)
|
val lastEntryI = cp.lastIndexOf(File.pathSeparatorChar.toInt, MaximumClasspathLength)
|
||||||
|
|
@ -80,3 +99,10 @@ object exit {
|
||||||
System.exit(java.lang.Integer.parseInt(args(0)))
|
System.exit(java.lang.Integer.parseInt(args(0)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Echoes each argument on its own line, used to verify argument passing
|
||||||
|
object echoArgs {
|
||||||
|
def main(args: Array[String]): Unit = {
|
||||||
|
args.foreach(println)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
scalaVersion := "3.6.4"
|
||||||
|
run / fork := true
|
||||||
|
// Force arguments file mode by exceeding MaxConcatenatedOptionLength (5000)
|
||||||
|
run / javaOptions += ("-Dsome.long.property=" + ("X" * 5000))
|
||||||
|
// Pass JSON with double quotes as a system property — this goes through the argsfile
|
||||||
|
run / javaOptions += """-Djson={"a":1}"""
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
object Main {
|
||||||
|
def main(args: Array[String]): Unit = {
|
||||||
|
val json = System.getProperty("json")
|
||||||
|
assert(json == """{"a":1}""", s"""Expected '{"a":1}' but got '$json'""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Verify that double quotes in JVM options survive the argsfile round-trip (sbt/sbt#7129)
|
||||||
|
> run
|
||||||
Loading…
Reference in New Issue