@@ -3,48 +3,101 @@ package paths
33import (
44 "os"
55 "path/filepath"
6+ "sync/atomic"
67)
78
9+ // overridable holds an optional directory override backed by an atomic pointer.
10+ // A nil pointer (the zero value) means "use the default".
11+ type overridable struct { p atomic.Pointer [string ] }
12+
13+ // Set stores an override directory. An empty value clears the override.
14+ func (o * overridable ) Set (dir string ) {
15+ if dir == "" {
16+ o .p .Store (nil )
17+ } else {
18+ o .p .Store (& dir )
19+ }
20+ }
21+
22+ // get returns the override if set, or falls back to the result of defaultFn.
23+ func (o * overridable ) get (defaultFn func () string ) string {
24+ if p := o .p .Load (); p != nil {
25+ return filepath .Clean (* p )
26+ }
27+ return defaultFn ()
28+ }
29+
30+ var (
31+ cacheDirOverride overridable
32+ configDirOverride overridable
33+ dataDirOverride overridable
34+ )
35+
36+ // SetCacheDir overrides the default cache directory returned by [GetCacheDir].
37+ // An empty value restores the default behaviour.
38+ // This should be called early (e.g. during CLI flag processing) before any
39+ // goroutine calls the corresponding getter.
40+ func SetCacheDir (dir string ) { cacheDirOverride .Set (dir ) }
41+
42+ // SetConfigDir overrides the default config directory returned by [GetConfigDir].
43+ // An empty value restores the default behaviour.
44+ func SetConfigDir (dir string ) { configDirOverride .Set (dir ) }
45+
46+ // SetDataDir overrides the default data directory returned by [GetDataDir].
47+ // An empty value restores the default behaviour.
48+ func SetDataDir (dir string ) { dataDirOverride .Set (dir ) }
49+
850// GetCacheDir returns the user's cache directory for cagent.
951//
52+ // If an override has been set via [SetCacheDir] it is returned instead.
53+ //
1054// On Linux this follows XDG: $XDG_CACHE_HOME/cagent (default ~/.cache/cagent).
1155// On macOS this uses ~/Library/Caches/cagent.
1256// On Windows this uses %LocalAppData%/cagent.
1357//
1458// If the cache directory cannot be determined, it falls back to a directory
1559// under the system temporary directory.
1660func GetCacheDir () string {
17- cacheDir , err := os .UserCacheDir ()
18- if err != nil {
19- return filepath .Clean (filepath .Join (os .TempDir (), ".cagent-cache" ))
20- }
21- return filepath .Clean (filepath .Join (cacheDir , "cagent" ))
61+ return cacheDirOverride .get (func () string {
62+ cacheDir , err := os .UserCacheDir ()
63+ if err != nil {
64+ return filepath .Clean (filepath .Join (os .TempDir (), ".cagent-cache" ))
65+ }
66+ return filepath .Clean (filepath .Join (cacheDir , "cagent" ))
67+ })
2268}
2369
2470// GetConfigDir returns the user's config directory for cagent.
2571//
72+ // If an override has been set via [SetConfigDir] it is returned instead.
73+ //
2674// If the home directory cannot be determined, it falls back to a directory
2775// under the system temporary directory. This is a best-effort fallback and
2876// not intended to be a security boundary.
2977func GetConfigDir () string {
30- homeDir , err := os .UserHomeDir ()
31- if err != nil {
32- // Fallback to temp directory
33- return filepath .Clean (filepath .Join (os .TempDir (), ".cagent-config" ))
34- }
35- return filepath .Clean (filepath .Join (homeDir , ".config" , "cagent" ))
78+ return configDirOverride .get (func () string {
79+ homeDir , err := os .UserHomeDir ()
80+ if err != nil {
81+ return filepath .Clean (filepath .Join (os .TempDir (), ".cagent-config" ))
82+ }
83+ return filepath .Clean (filepath .Join (homeDir , ".config" , "cagent" ))
84+ })
3685}
3786
3887// GetDataDir returns the user's data directory for cagent (caches, content, logs).
3988//
89+ // If an override has been set via [SetDataDir] it is returned instead.
90+ //
4091// If the home directory cannot be determined, it falls back to a directory
4192// under the system temporary directory.
4293func GetDataDir () string {
43- homeDir , err := os .UserHomeDir ()
44- if err != nil {
45- return filepath .Clean (filepath .Join (os .TempDir (), ".cagent" ))
46- }
47- return filepath .Clean (filepath .Join (homeDir , ".cagent" ))
94+ return dataDirOverride .get (func () string {
95+ homeDir , err := os .UserHomeDir ()
96+ if err != nil {
97+ return filepath .Clean (filepath .Join (os .TempDir (), ".cagent" ))
98+ }
99+ return filepath .Clean (filepath .Join (homeDir , ".cagent" ))
100+ })
48101}
49102
50103// GetHomeDir returns the user's home directory.
0 commit comments