From b3f10556f0ab8a92bdd92e25c67685947317d188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Thu, 27 Jul 2023 20:59:47 +0200 Subject: [PATCH] Use os.UserCacheDir as first fallback if cacheDir is not set We will now try 1. cacheDir (or, commonly set in environment as `HUGO_CACHEDIR`) 2. if on Netlify we use `/opt/build/cache/hugo_cache/` 3. os.UserCacheDir 4. A temp dir Storing the cache, especially the module cache, in a temporary idea has had lots of hard to debug issues, especially on MacOS, which this commit tries to fix. This should also make it easier to locate the Hugo cache: >UserCacheDir returns the default root directory to use for user-specific cached data. Users should create their own application-specific subdirectory within this one and use that. > >On Unix systems, it returns $XDG_CACHE_HOME as specified by https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if non-empty, else $HOME/.cache. On Darwin, it returns $HOME/Library/Caches. On Windows, it returns %LocalAppData%. On Plan 9, it returns $home/lib/cache. > >If the location cannot be determined (for example, $HOME is not defined), then it will return an error. Fixes #11286 Fixes #11291 --- config/allconfig/allconfig.go | 5 +++++ helpers/path.go | 17 ++++++++++++++--- main_test.go | 19 +++++++++++++++++-- testscripts/commands/config__cachedir.txt | 18 ++++++++++++++++++ 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 testscripts/commands/config__cachedir.txt diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go index 72f2883f2..ec95f5eba 100644 --- a/config/allconfig/allconfig.go +++ b/config/allconfig/allconfig.go @@ -729,6 +729,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon cfg := res.Cfg all := &Config{} + err := decodeConfigFromParams(fs, bcfg, cfg, all, nil) if err != nil { return nil, err @@ -871,6 +872,10 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon bcfg.PublishDir = all.PublishDir res.BaseConfig = bcfg + all.CommonDirs.CacheDir = bcfg.CacheDir + for _, l := range langConfigs { + l.CommonDirs.CacheDir = bcfg.CacheDir + } cm := &Configs{ Base: all, diff --git a/helpers/path.go b/helpers/path.go index 4c2799ac2..57877bfed 100644 --- a/helpers/path.go +++ b/helpers/path.go @@ -394,6 +394,7 @@ func OpenFileForWriting(fs afero.Fs, filename string) (afero.File, error) { // The dir will be created if it does not exist. func GetCacheDir(fs afero.Fs, cacheDir string) (string, error) { cacheDir = cacheDirDefault(cacheDir) + if cacheDir != "" { exists, err := DirExists(cacheDir, fs) if err != nil { @@ -408,12 +409,22 @@ func GetCacheDir(fs afero.Fs, cacheDir string) (string, error) { return cacheDir, nil } + const hugoCacheBase = "hugo_cache" + + userCacheDir, err := os.UserCacheDir() + if err == nil { + cacheDir := filepath.Join(userCacheDir, hugoCacheBase) + if err := fs.Mkdir(cacheDir, 0777); err == nil || os.IsExist(err) { + return cacheDir, nil + } + } + // Fall back to a cache in /tmp. userName := os.Getenv("USER") if userName != "" { - return GetTempDir("hugo_cache_"+userName, fs), nil + return GetTempDir(hugoCacheBase+"_"+userName, fs), nil } else { - return GetTempDir("hugo_cache", fs), nil + return GetTempDir(hugoCacheBase, fs), nil } } @@ -433,7 +444,7 @@ func cacheDirDefault(cacheDir string) string { return "/opt/build/cache/hugo_cache/" } - // This will fall back to an hugo_cache folder in the tmp dir, which should work fine for most CI + // This will fall back to an hugo_cache folder in either os.UserCacheDir or the tmp dir, which should work fine for most CI // providers. See this for a working CircleCI setup: // https://github.com/bep/hugo-sass-test/blob/6c3960a8f4b90e8938228688bc49bdcdd6b2d99e/.circleci/config.yml // If not, they can set the HUGO_CACHEDIR environment variable or cacheDir config key. diff --git a/main_test.go b/main_test.go index 6274cd9bb..c5a59828f 100644 --- a/main_test.go +++ b/main_test.go @@ -375,8 +375,23 @@ func testSetupFunc() func(env *testscript.Env) error { return func(env *testscript.Env) error { var keyVals []string keyVals = append(keyVals, "HUGO_TESTRUN", "true") - hugoCachedDir := filepath.Join(env.WorkDir, "hugocache") - keyVals = append(keyVals, "HUGO_CACHEDIR", hugoCachedDir) + keyVals = append(keyVals, "HUGO_CACHEDIR", filepath.Join(env.WorkDir, "hugocache")) + xdghome := filepath.Join(env.WorkDir, "xdgcachehome") + keyVals = append(keyVals, "XDG_CACHE_HOME", xdghome) + home := filepath.Join(env.WorkDir, "home") + keyVals = append(keyVals, "HOME", home) + + if runtime.GOOS == "darwin" { + if err := os.MkdirAll(filepath.Join(home, "Library", "Caches"), 0777); err != nil { + return err + } + } + + if runtime.GOOS == "linux" { + if err := os.MkdirAll(xdghome, 0777); err != nil { + return err + } + } keyVals = append(keyVals, "SOURCE", sourceDir) diff --git a/testscripts/commands/config__cachedir.txt b/testscripts/commands/config__cachedir.txt new file mode 100644 index 000000000..aecb40b6c --- /dev/null +++ b/testscripts/commands/config__cachedir.txt @@ -0,0 +1,18 @@ + +[windows] skip + +env HUGO_CACHEDIR= +hugo config + +[darwin] stdout 'home/Library/Caches/hugo_cache' +[linux] stdout 'xdgcachehome/hugo_cache' + +# Repeat it to make sure it handles an existing hugo_cache dir. +hugo config + +[darwin] stdout 'home/Library/Caches/hugo_cache' +[linux] stdout 'xdgcachehome/hugo_cache' + +-- hugo.toml -- +baseURL="https://example.com/" +title="My New Hugo Site"