use sync/atomic.Value for concurrency safe caching
diff --git a/homedir.go b/homedir.go
index 5cff371..2f54ed6 100644
--- a/homedir.go
+++ b/homedir.go
@@ -8,32 +8,42 @@
"path/filepath"
"runtime"
"strings"
+ "sync/atomic"
)
-var homedir string
+// DisableCache will disable caching of the home directory. Caching is enabled
+// by default.
+var DisableCache bool
+
+var homedirCache atomic.Value
// Dir returns the home directory for the executing user.
//
// This uses an OS-specific method for discovering the home directory.
// An error is returned if a home directory cannot be detected.
func Dir() (string, error) {
- if homedir != "" {
- return homedir, nil
+ if !DisableCache {
+ cached := homedirCache.Load()
+ if cached != nil && cached != "" {
+ return cached.(string), nil
+ }
}
+ var result string
var err error
if runtime.GOOS == "windows" {
- homedir, err = dirWindows()
+ result, err = dirWindows()
} else {
// Unix-like system, so just assume Unix
- homedir, err = dirUnix()
+ result, err = dirUnix()
}
if err != nil {
return "", err
}
- return homedir, nil
+ homedirCache.Store(result)
+ return result, nil
}
// Expand expands the path to include the home directory if the path
diff --git a/homedir_test.go b/homedir_test.go
index ddc24ee..c34dbc7 100644
--- a/homedir_test.go
+++ b/homedir_test.go
@@ -17,6 +17,18 @@
return deferFunc
}
+func BenchmarkDir(b *testing.B) {
+ // We do this for any "warmups"
+ for i := 0; i < 10; i++ {
+ Dir()
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Dir()
+ }
+}
+
func TestDir(t *testing.T) {
u, err := user.Current()
if err != nil {
@@ -86,6 +98,8 @@
}
}
+ DisableCache = true
+ defer func() { DisableCache = false }()
defer patchEnv("HOME", "/custom/path/")()
expected := "/custom/path/foo/bar"
actual, err := Expand("~/foo/bar")