mirror of https://github.com/sbt/sbt.git
[2.x] fix: Fixes double quotes handling in fork mode (#8846)
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: BrianHotopp <brihoto@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f976330759
commit
38acd80147
|
|
@ -166,7 +166,7 @@ object Fork {
|
|||
|
||||
/**
|
||||
* 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
|
||||
* @return
|
||||
|
|
@ -178,7 +178,7 @@ object Fork {
|
|||
val pw = new PrintWriter(file)
|
||||
options.foreach { option =>
|
||||
pw.write("\"")
|
||||
pw.write(option.replace("\\", "\\\\"))
|
||||
pw.write(option.replace("\\", "\\\\").replace("\"", "\\\""))
|
||||
pw.write("\"")
|
||||
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 =
|
||||
if (cp.length > MaximumClasspathLength) {
|
||||
val lastEntryI = cp.lastIndexOf(File.pathSeparatorChar.toInt, MaximumClasspathLength)
|
||||
|
|
@ -80,3 +99,10 @@ object exit {
|
|||
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