mirror of https://github.com/sbt/sbt.git
[2.x] fix: handle -sbt-dir with spaces from .sbtopts (#8875)
**Problem** When you pass -sbt-dir "/Users/a' dog" on the command line, the launcher correctly produces: -Dsbt.global.base=/Users/a' dog But when you put the same option into .sbtopts, the launcher previously split the line on spaces without respecting quotes, so the resulting -Dsbt.global.base was truncated (for example, -Dsbt.global.base=/Users/a'). This made .sbtopts behavior inconsistent with CLI behavior and broke setups where the global sbt directory path contains spaces and an embedded quote.
This commit is contained in:
parent
ed96b4e1e0
commit
119aa4d1a7
|
|
@ -252,6 +252,31 @@ abstract class RunnerScriptTest extends verify.BasicTestSuite with ShellScriptUt
|
|||
s"sbtopts options should appear before CLI memory settings. g1Index=$g1Index, xmxCliIndex=$xmxCliIndex"
|
||||
)
|
||||
|
||||
// Test for issue #7197: -sbt-dir with spaces (and quotes) in .sbtopts
|
||||
// windowsSupport = false: skip on Windows cmd, but runs on Git Bash (#8779)
|
||||
testOutput(
|
||||
"sbt -sbt-dir with space and quote in .sbtopts",
|
||||
sbtOptsFileContents = """-sbt-dir "/Users/a' dog"""",
|
||||
windowsSupport = false,
|
||||
)("-d", "-v"): (out: List[String]) =>
|
||||
val cmdLineStart = out.indexWhere(_.contains("Executing command line"))
|
||||
assert(cmdLineStart >= 0, "Command line section not found")
|
||||
|
||||
val cmdLine = out.drop(cmdLineStart + 1).takeWhile(!_.trim.isEmpty)
|
||||
val globalBaseArgs =
|
||||
cmdLine.filter(_.contains("Dsbt.global.base"))
|
||||
|
||||
assert(
|
||||
globalBaseArgs.nonEmpty,
|
||||
s"-Dsbt.global.base should be present in command line. cmdLine=${cmdLine.mkString(", ")}"
|
||||
)
|
||||
assert(
|
||||
globalBaseArgs.exists(arg =>
|
||||
arg.contains("= /Users/a' dog") || arg.contains("=/Users/a' dog")
|
||||
),
|
||||
s"-Dsbt.global.base should contain full path with space and quote. args=${globalBaseArgs.mkString(", ")}"
|
||||
)
|
||||
|
||||
// Test for issue #7333: JVM parameters with spaces in .sbtopts
|
||||
testOutput(
|
||||
"sbt with -J--add-modules ALL-DEFAULT in .sbtopts (args with spaces)",
|
||||
|
|
|
|||
62
sbt
62
sbt
|
|
@ -738,6 +738,47 @@ map_args () {
|
|||
declare -p commands
|
||||
}
|
||||
|
||||
# Parse a line into words, respecting single and double quotes.
|
||||
# This is used for .sbtopts so that options like:
|
||||
# -sbt-dir "/Users/a' dog"
|
||||
# are split into two arguments: -sbt-dir and /Users/a' dog
|
||||
parseLineIntoWords() {
|
||||
local line="$1"
|
||||
local word=""
|
||||
local i=0
|
||||
local len=${#line}
|
||||
local in_dq=0
|
||||
local in_sq=0
|
||||
while (( i < len )); do
|
||||
local c="${line:$i:1}"
|
||||
if (( in_dq )); then
|
||||
if [[ "$c" == '"' ]]; then
|
||||
in_dq=0
|
||||
else
|
||||
word+="$c"
|
||||
fi
|
||||
elif (( in_sq )); then
|
||||
if [[ "$c" == "'" ]]; then
|
||||
in_sq=0
|
||||
else
|
||||
word+="$c"
|
||||
fi
|
||||
else
|
||||
case "$c" in
|
||||
'"') in_dq=1 ;;
|
||||
"'") in_sq=1 ;;
|
||||
' '|$'\t')
|
||||
[[ -n "$word" ]] && printf '%s\n' "$word"
|
||||
word=""
|
||||
;;
|
||||
*) word+="$c" ;;
|
||||
esac
|
||||
fi
|
||||
((i++))
|
||||
done
|
||||
[[ -n "$word" ]] && printf '%s\n' "$word"
|
||||
}
|
||||
|
||||
process_args () {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
|
|
@ -794,6 +835,21 @@ loadConfigFile() {
|
|||
done
|
||||
}
|
||||
|
||||
# Append tokens from an sbtopts-style file into the global sbt_file_opts array.
|
||||
# Each non-empty, non-comment line is split using parseLineIntoWords so that
|
||||
# quoted values with spaces (and embedded quotes) are preserved as single arguments.
|
||||
appendSbtoptsFromFile() {
|
||||
local file="$1"
|
||||
[[ ! -f "$file" ]] && return
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
line=$(printf '%s' "$line" | sed $'/^\#/d;s/[[:space:]]\{1,\}#.*//;s/\r$//')
|
||||
[[ -z "$line" ]] && continue
|
||||
while IFS= read -r token; do
|
||||
[[ -n "$token" ]] && sbt_file_opts+=("$token")
|
||||
done < <(parseLineIntoWords "$line")
|
||||
done < "$file"
|
||||
}
|
||||
|
||||
loadPropFile() {
|
||||
# trim key and value so as to be more forgiving with spaces around the '=':
|
||||
k=$(trimString $k)
|
||||
|
|
@ -893,14 +949,14 @@ fi
|
|||
|
||||
# Pull in the machine-wide settings configuration.
|
||||
if [[ -f "$machine_sbt_opts_file" ]]; then
|
||||
sbt_file_opts+=($(loadConfigFile "$machine_sbt_opts_file"))
|
||||
appendSbtoptsFromFile "$machine_sbt_opts_file"
|
||||
else
|
||||
# Otherwise pull in the default settings configuration.
|
||||
[[ -f "$dist_sbt_opts_file" ]] && sbt_file_opts+=($(loadConfigFile "$dist_sbt_opts_file"))
|
||||
[[ -f "$dist_sbt_opts_file" ]] && appendSbtoptsFromFile "$dist_sbt_opts_file"
|
||||
fi
|
||||
|
||||
# Pull in the project-level config file, if it exists (highest priority, overrides machine/dist).
|
||||
[[ -f "$sbt_opts_file" ]] && sbt_file_opts+=($(loadConfigFile "$sbt_opts_file"))
|
||||
[[ -f "$sbt_opts_file" ]] && appendSbtoptsFromFile "$sbt_opts_file"
|
||||
|
||||
# Prepend sbtopts so command line args appear last and win for duplicate properties.
|
||||
if (( ${#sbt_file_opts[@]} > 0 )); then
|
||||
|
|
|
|||
Loading…
Reference in New Issue