mirror of https://github.com/sbt/sbt.git
Use LOCALAPPDATA or $HOME/AppData/Local on Windows
Fixes https://github.com/sbt/sbt/issues/5206 Problem -------- Coursier uses directories-jvm to determine its default cache directory. Currently directories-jvm shells out to Powershell to call the [Known Folders API](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid), which doesn't work in various environments, and instead of an error, it apparently returns `null/Coursier/cache` as the directory name. Solution -------- With due respect to the heroic effort directories-jvm is making to comply to the directory standards on all operating systems, including that of Microsoft, I don't think the majority of the sbt users care exactly where that directory is as long as it is well-documented, and calculated in a fast and predictable way. Instead of shelling out to Powershell, or using JNI, to hit the Known Folders API, I propose we first look at `LOCALAPPDATA` environment variable. When it is not found, it will fall back to `$HOME/AppData/Local`. Per discussion in https://github.com/dirs-dev/directories-jvm/issues/43, `LOCALAPPDATA` environment variable may NOT represent the one-true Known Folders API value of the AppData directory in case the user happened to have set the `LOCALAPPDATA` environmental variable. For the purpose of picking a directory for Coursier cache, I don't find that to be a problem because it will be faster, more reliable, and predictable.
This commit is contained in:
parent
07687e51e4
commit
01e3d9e9d8
|
|
@ -22,6 +22,7 @@ import lmcoursier.definitions.{
|
|||
import lmcoursier._
|
||||
import lmcoursier.credentials.Credentials
|
||||
import Keys._
|
||||
import sbt.internal.util.Util
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.ivy.{
|
||||
Credentials => IvyCredentials,
|
||||
|
|
@ -37,12 +38,36 @@ object LMCoursier {
|
|||
private[this] val credentialRegistry: ConcurrentHashMap[(String, String), IvyCredentials] =
|
||||
new ConcurrentHashMap
|
||||
|
||||
def defaultCacheLocation: File =
|
||||
sys.props.get("sbt.coursier.home") match {
|
||||
case Some(home) => new File(home).getAbsoluteFile / "cache"
|
||||
case _ =>
|
||||
CoursierDependencyResolution.defaultCacheLocation
|
||||
def defaultCacheLocation: File = {
|
||||
def absoluteFile(path: String): File = new File(path).getAbsoluteFile()
|
||||
def windowsCacheDirectory: File = {
|
||||
// Per discussion in https://github.com/dirs-dev/directories-jvm/issues/43,
|
||||
// LOCALAPPDATA environment variable may NOT represent the one-true
|
||||
// Known Folders API (https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid)
|
||||
// in case the user happened to have set the LOCALAPPDATA environmental variable.
|
||||
// Given that there's no reliable way of accessing this API from JVM, I think it's actually
|
||||
// better to use the LOCALAPPDATA as the first place to look.
|
||||
// When it is not found, it will fall back to $HOME/AppData/Local.
|
||||
// For the purpose of picking the Coursier cache directory, it's better to be
|
||||
// fast, reliable, and predictable rather than strict adherence to Microsoft.
|
||||
val base =
|
||||
sys.env
|
||||
.get("LOCALAPPDATA")
|
||||
.map(absoluteFile)
|
||||
.getOrElse(absoluteFile(sys.props("user.home")) / "AppData" / "Local")
|
||||
base / "Coursier" / "Cache" / "v1"
|
||||
}
|
||||
sys.props
|
||||
.get("sbt.coursier.home")
|
||||
.map(home => absoluteFile(home) / "cache")
|
||||
.orElse(sys.env.get("COURSIER_CACHE").map(absoluteFile))
|
||||
.orElse(sys.props.get("coursier.cache").map(absoluteFile)) match {
|
||||
case Some(dir) => dir
|
||||
case _ =>
|
||||
if (Util.isWindows) windowsCacheDirectory
|
||||
else CoursierDependencyResolution.defaultCacheLocation
|
||||
}
|
||||
}
|
||||
|
||||
def relaxedForAllModules: Seq[(ModuleMatchers, Reconciliation)] =
|
||||
Vector((ModuleMatchers.all, Reconciliation.Relaxed))
|
||||
|
|
|
|||
Loading…
Reference in New Issue