[2.x] fix: Resolve relative paths from -sbt-dir / sbt.global.base (#9001)

getFileProperty returned relative File objects when system properties
like sbt.global.base were set to relative paths (e.g. via -sbt-dir
../cache in .sbtopts). This caused an assertion failure in
IO.directoryURI: "Not absolute: ../cache/plugins".

Also fixes misleading scaladoc in SemanticSelector that claimed
`<=1.0` is equivalent to `<1.1.0` — they differ for pre-release
versions like 1.1.0-M1 (#4423).

Fixes #3729

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BrianHotopp 2026-04-05 19:27:34 -04:00 committed by GitHub
parent 4e4ab9f464
commit 3890cc7086
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 24 additions and 6 deletions

View File

@ -18,10 +18,10 @@ package sbt.librarymanagement
* If no operator is specified, `=` is assumed. * If no operator is specified, `=` is assumed.
* *
* If minor or patch versions are not specified, some numbers are assumed. * If minor or patch versions are not specified, some numbers are assumed.
* - `<=1.0` is equivalent to `<1.1.0`. * - `<=1.0` matches `1.0.x` and below (but not `1.1.0-M1`).
* - `<1.0` is equivalent to `<1.0.0`. * - `<1.0` is equivalent to `<1.0.0`.
* - `>=1.0` is equivalent to `>=1.0.0`. * - `>=1.0` is equivalent to `>=1.0.0`.
* - `>1.0` is equivalent to `>=1.1.0`. * - `>1.0` matches `1.1.0-M1` and above.
* - `=1.0` is equivalent to `>=1.0 <=1.0` (so `>=1.0.0 <1.1.0`). * - `=1.0` is equivalent to `>=1.0 <=1.0` (so `>=1.0.0 <1.1.0`).
* *
* Comparators can be combined by spaces to form the intersection set of the comparators. * Comparators can be combined by spaces to form the intersection set of the comparators.

View File

@ -37,10 +37,10 @@
"If no operator is specified, `=` is assumed.", "If no operator is specified, `=` is assumed.",
"", "",
"If minor or patch versions are not specified, some numbers are assumed.", "If minor or patch versions are not specified, some numbers are assumed.",
"- `<=1.0` is equivalent to `<1.1.0`.", "- `<=1.0` matches `1.0.x` and below (but not `1.1.0-M1`).",
"- `<1.0` is equivalent to `<1.0.0`.", "- `<1.0` is equivalent to `<1.0.0`.",
"- `>=1.0` is equivalent to `>=1.0.0`.", "- `>=1.0` is equivalent to `>=1.0.0`.",
"- `>1.0` is equivalent to `>=1.1.0`.", "- `>1.0` matches `1.1.0-M1` and above.",
"- `=1.0` is equivalent to `>=1.0 <=1.0` (so `>=1.0.0 <1.1.0`).", "- `=1.0` is equivalent to `>=1.0 <=1.0` (so `>=1.0.0 <1.1.0`).",
"", "",
"Comparators can be combined by spaces to form the intersection set of the comparators.", "Comparators can be combined by spaces to form the intersection set of the comparators.",

View File

@ -92,7 +92,7 @@ object BuildPaths:
val tildePath = expandTildePrefix(path) val tildePath = expandTildePrefix(path)
Some(new File(tildePath)) Some(new File(tildePath))
} else { } else {
Some(new File(path)) Some(new File(path).getAbsoluteFile)
} }
} }
} }

View File

@ -9,7 +9,7 @@
package sbt package sbt
import java.io.File import java.io.File
import BuildPaths.{ expandTildePrefix, defaultGlobalBase, GlobalBaseProperty } import BuildPaths.{ expandTildePrefix, defaultGlobalBase, getFileProperty, GlobalBaseProperty }
object BuildPathsTest extends verify.BasicTestSuite: object BuildPathsTest extends verify.BasicTestSuite:
@ -54,4 +54,22 @@ object BuildPathsTest extends verify.BasicTestSuite:
test("it should expand ~-/foo/bar to $OLDPWD/foo/bar"): test("it should expand ~-/foo/bar to $OLDPWD/foo/bar"):
assertEquals(sys.env.getOrElse("OLDPWD", "") + "/foo/bar", expandTildePrefix("~-/foo/bar")) assertEquals(sys.env.getOrElse("OLDPWD", "") + "/foo/bar", expandTildePrefix("~-/foo/bar"))
test("getFileProperty resolves relative paths to absolute"):
val prop = "sbt.test.relative.path"
try
sys.props(prop) = "../relative/dir"
val result = getFileProperty(prop)
assert(result.isDefined)
assert(result.get.isAbsolute, s"Expected absolute path, got: ${result.get}")
finally sys.props.remove(prop)
test("getFileProperty preserves absolute paths"):
val prop = "sbt.test.absolute.path"
try
sys.props(prop) = "/absolute/path"
val result = getFileProperty(prop)
assert(result.isDefined)
assert(result.get.getPath == "/absolute/path")
finally sys.props.remove(prop)
end BuildPathsTest end BuildPathsTest