mirror of https://github.com/sbt/sbt.git
[2.x] fix: Fix sbtopts files priority in sbt launch script (#8514)
* Fix sbtopts files priority in sbt launch script (fixes #7179) - Change project .sbtopts from prepend to append so it appears last
This commit is contained in:
parent
4ed22747dc
commit
bb02c3331c
|
|
@ -122,4 +122,76 @@ object RunnerScriptTest extends verify.BasicTestSuite with ShellScriptUtil:
|
|||
testOutput("--sbt-cache")("--sbt-cache", "./cachePath"): (out: List[String]) =>
|
||||
assert(out.contains[String]("-Dsbt.global.localcache=./cachePath"))
|
||||
|
||||
// Test for issue #7179: sbtopts files priority
|
||||
testOutput(
|
||||
"project .sbtopts overrides dist sbtopts",
|
||||
distSbtoptsContents = "-Dsbt.test.config=dist-default",
|
||||
sbtOptsFileContents = "-Dsbt.test.config=project-local"
|
||||
)("-d", "-v"): (out: List[String]) =>
|
||||
if (isWindows) cancel("Test not supported on windows")
|
||||
else
|
||||
// Find the command line section
|
||||
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 distIndex = cmdLine.indexWhere(_.contains("Dsbt.test.config=dist-default"))
|
||||
val projectIndex = cmdLine.indexWhere(_.contains("Dsbt.test.config=project-local"))
|
||||
|
||||
assert(distIndex >= 0, "Dist config not found in command line")
|
||||
assert(projectIndex >= 0, "Project config not found in command line")
|
||||
assert(
|
||||
projectIndex > distIndex,
|
||||
s"Project config should appear after dist config. distIndex=$distIndex, projectIndex=$projectIndex"
|
||||
)
|
||||
|
||||
testOutput(
|
||||
"project .sbtopts overrides machine sbtopts",
|
||||
machineSbtoptsContents = "-Dsbt.test.config=machine-config",
|
||||
sbtOptsFileContents = "-Dsbt.test.config=project-local"
|
||||
)("-d", "-v"): (out: List[String]) =>
|
||||
if (isWindows) cancel("Test not supported on windows")
|
||||
else
|
||||
// Find the command line section
|
||||
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 machineIndex = cmdLine.indexWhere(_.contains("Dsbt.test.config=machine-config"))
|
||||
val projectIndex = cmdLine.indexWhere(_.contains("Dsbt.test.config=project-local"))
|
||||
|
||||
assert(machineIndex >= 0, "Machine config not found in command line")
|
||||
assert(projectIndex >= 0, "Project config not found in command line")
|
||||
assert(
|
||||
projectIndex > machineIndex,
|
||||
s"Project config should appear after machine config. machineIndex=$machineIndex, projectIndex=$projectIndex"
|
||||
)
|
||||
|
||||
testOutput(
|
||||
"project .sbtopts overrides both dist and machine sbtopts",
|
||||
distSbtoptsContents = "-Dsbt.test.config=dist-default",
|
||||
machineSbtoptsContents = "-Dsbt.test.config=machine-config",
|
||||
sbtOptsFileContents = "-Dsbt.test.config=project-local"
|
||||
)("-d", "-v"): (out: List[String]) =>
|
||||
if (isWindows) cancel("Test not supported on windows")
|
||||
else
|
||||
// Find the command line section
|
||||
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 distIndex = cmdLine.indexWhere(_.contains("Dsbt.test.config=dist-default"))
|
||||
val machineIndex = cmdLine.indexWhere(_.contains("Dsbt.test.config=machine-config"))
|
||||
val projectIndex = cmdLine.indexWhere(_.contains("Dsbt.test.config=project-local"))
|
||||
|
||||
// When machine sbtopts exists, the script only loads machine (not dist) due to if-else structure
|
||||
// So dist should NOT be present, but machine and project should be
|
||||
assert(distIndex < 0, "Dist config should NOT be present when machine config exists")
|
||||
assert(machineIndex >= 0, "Machine config not found in command line")
|
||||
assert(projectIndex >= 0, "Project config not found in command line")
|
||||
assert(
|
||||
machineIndex < projectIndex,
|
||||
s"Machine config should appear before project config. machineIndex=$machineIndex, projectIndex=$projectIndex"
|
||||
)
|
||||
|
||||
end RunnerScriptTest
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ trait ShellScriptUtil extends BasicTestSuite {
|
|||
val isWindows: Boolean =
|
||||
sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows")
|
||||
|
||||
private val javaBinDir = new File("launcher-package/integration-test/bin").getAbsolutePath
|
||||
protected val javaBinDir = new File("launcher-package/integration-test/bin").getAbsolutePath
|
||||
|
||||
private def retry[A1](f: () => A1, maxAttempt: Int = 10): A1 =
|
||||
protected def retry[A1](f: () => A1, maxAttempt: Int = 10): A1 =
|
||||
try {
|
||||
f()
|
||||
} catch {
|
||||
|
|
@ -33,12 +33,18 @@ trait ShellScriptUtil extends BasicTestSuite {
|
|||
javaOpts: String = "",
|
||||
sbtOpts: String = "",
|
||||
sbtOptsFileContents: String = "",
|
||||
javaToolOptions: String = ""
|
||||
javaToolOptions: String = "",
|
||||
distSbtoptsContents: String = "",
|
||||
machineSbtoptsContents: String = ""
|
||||
)(args: String*)(f: List[String] => Any) =
|
||||
test(name) {
|
||||
val workingDirectory = Files.createTempDirectory("sbt-launcher-package-test").toFile
|
||||
retry(() => IO.copyDirectory(new File("launcher-package/citest"), workingDirectory))
|
||||
|
||||
var sbtHome: Option[File] = None
|
||||
var configHome: Option[File] = None
|
||||
var tempSbtHome: Option[File] = None
|
||||
var testSbtScript: File = sbtScript
|
||||
try
|
||||
val sbtOptsFile = new File(workingDirectory, ".sbtopts")
|
||||
sbtOptsFile.createNewFile()
|
||||
|
|
@ -48,24 +54,77 @@ trait ShellScriptUtil extends BasicTestSuite {
|
|||
} finally {
|
||||
writer.close()
|
||||
}
|
||||
|
||||
val envVars = scala.collection.mutable.Map[String, String]()
|
||||
|
||||
// Set up dist sbtopts if provided
|
||||
// Note: sbt script derives sbt_home from script location, not SBT_HOME env var
|
||||
// Copy the sbt staging directory to a temp location to avoid modifying the staging directory
|
||||
if (distSbtoptsContents.nonEmpty) {
|
||||
val originalSbtHome = sbtScript.getParentFile.getParentFile
|
||||
val tempSbtHomeDir = Files.createTempDirectory("sbt-home-test").toFile
|
||||
tempSbtHome = Some(tempSbtHomeDir)
|
||||
// Copy the entire sbt home directory structure
|
||||
retry(() => IO.copyDirectory(originalSbtHome, tempSbtHomeDir))
|
||||
// Get the script from the copied directory
|
||||
val binDir = new File(tempSbtHomeDir, "bin")
|
||||
testSbtScript = new File(binDir, sbtScript.getName)
|
||||
// Create dist sbtopts in the copied directory
|
||||
val distSbtoptsDir = new File(tempSbtHomeDir, "conf")
|
||||
distSbtoptsDir.mkdirs()
|
||||
val distSbtoptsFile = new File(distSbtoptsDir, "sbtopts")
|
||||
IO.write(distSbtoptsFile, distSbtoptsContents)
|
||||
// Store reference for cleanup
|
||||
sbtHome = Some(tempSbtHomeDir)
|
||||
}
|
||||
|
||||
// Ensure no machine sbtopts exists when testing dist-only (unless explicitly provided)
|
||||
// The script only loads dist if machine doesn't exist
|
||||
if (distSbtoptsContents.nonEmpty && machineSbtoptsContents.isEmpty && configHome.isEmpty) {
|
||||
// Set XDG_CONFIG_HOME to a temp directory without sbtopts to prevent default machine sbtopts from being found
|
||||
val emptyConfigHome = Files.createTempDirectory("empty-config-home").toFile
|
||||
envVars("XDG_CONFIG_HOME") = emptyConfigHome.getAbsolutePath
|
||||
// Also unset SBT_ETC_FILE if it exists
|
||||
sys.env.get("SBT_ETC_FILE").foreach(_ => envVars("SBT_ETC_FILE") = "")
|
||||
// Store for cleanup
|
||||
configHome = Some(emptyConfigHome)
|
||||
}
|
||||
|
||||
// Set up machine sbtopts if provided
|
||||
if (machineSbtoptsContents.nonEmpty) {
|
||||
val configHomeDir = Files.createTempDirectory("config-home").toFile
|
||||
configHome = Some(configHomeDir)
|
||||
val machineSbtoptsDir = new File(configHomeDir, "sbt")
|
||||
machineSbtoptsDir.mkdirs()
|
||||
val machineSbtoptsFile = new File(machineSbtoptsDir, "sbtopts")
|
||||
IO.write(machineSbtoptsFile, machineSbtoptsContents)
|
||||
envVars("XDG_CONFIG_HOME") = configHomeDir.getAbsolutePath
|
||||
}
|
||||
|
||||
val path = sys.env.getOrElse("PATH", sys.env("Path"))
|
||||
envVars("JAVA_OPTS") = javaOpts
|
||||
envVars("SBT_OPTS") = sbtOpts
|
||||
envVars("JAVA_TOOL_OPTIONS") = javaToolOptions
|
||||
if (isWindows)
|
||||
envVars("JAVACMD") = new File(javaBinDir, "java").getAbsolutePath()
|
||||
else
|
||||
envVars("PATH") = javaBinDir + File.pathSeparator + path
|
||||
|
||||
val out = scala.sys.process
|
||||
.Process(
|
||||
Seq(sbtScript.getAbsolutePath) ++ args,
|
||||
Seq(testSbtScript.getAbsolutePath) ++ args,
|
||||
workingDirectory,
|
||||
"JAVA_OPTS" -> javaOpts,
|
||||
"SBT_OPTS" -> sbtOpts,
|
||||
"JAVA_TOOL_OPTIONS" -> javaToolOptions,
|
||||
if (isWindows)
|
||||
"JAVACMD" -> new File(javaBinDir, "java").getAbsolutePath()
|
||||
else
|
||||
"PATH" -> (javaBinDir + File.pathSeparator + path)
|
||||
envVars.toSeq*
|
||||
)
|
||||
.!!
|
||||
.linesIterator
|
||||
.toList
|
||||
f(out)
|
||||
()
|
||||
finally IO.delete(workingDirectory)
|
||||
finally
|
||||
IO.delete(workingDirectory)
|
||||
// Clean up temporary sbt home directory if we created one
|
||||
tempSbtHome.foreach(IO.delete)
|
||||
configHome.foreach(IO.delete)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
sbt
9
sbt
|
|
@ -858,14 +858,15 @@ original_args=("$@")
|
|||
|
||||
# Pull in the machine-wide settings configuration.
|
||||
if [[ -f "$machine_sbt_opts_file" ]]; then
|
||||
set -- $(loadConfigFile "$machine_sbt_opts_file") "$@"
|
||||
set -- "$@" $(loadConfigFile "$machine_sbt_opts_file")
|
||||
else
|
||||
# Otherwise pull in the default settings configuration.
|
||||
[[ -f "$dist_sbt_opts_file" ]] && set -- $(loadConfigFile "$dist_sbt_opts_file") "$@"
|
||||
[[ -f "$dist_sbt_opts_file" ]] && set -- "$@" $(loadConfigFile "$dist_sbt_opts_file")
|
||||
fi
|
||||
|
||||
# Pull in the project-level config file, if it exists.
|
||||
[[ -f "$sbt_opts_file" ]] && set -- $(loadConfigFile "$sbt_opts_file") "$@"
|
||||
# Pull in the project-level config file, if it exists (highest priority, overrides machine/dist).
|
||||
# Append so it appears last in command line and wins for duplicate properties.
|
||||
[[ -f "$sbt_opts_file" ]] && set -- "$@" $(loadConfigFile "$sbt_opts_file")
|
||||
|
||||
# Pull in the project-level java config, if it exists.
|
||||
[[ -f ".jvmopts" ]] && export JAVA_OPTS="$JAVA_OPTS $(loadConfigFile .jvmopts)"
|
||||
|
|
|
|||
Loading…
Reference in New Issue