1// Package config provides XDG Base Directory specification compliance utilities.
2package config
3
4import (
5 "os"
6 "path/filepath"
7)
8
9const appName = "dumber"
10
11// XDGDirs holds the XDG Base Directory paths for the application.
12type XDGDirs struct {
13 ConfigHome string
14 DataHome string
15 StateHome string
16}
17
18// GetXDGDirs returns the XDG Base Directory paths for dumber.
19// It follows the XDG Base Directory specification:
20// - $XDG_CONFIG_HOME/dumber (default: ~/.config/dumber)
21// - $XDG_DATA_HOME/dumber (default: ~/.local/share/dumber)
22// - $XDG_STATE_HOME/dumber (default: ~/.local/state/dumber)
23func GetXDGDirs() (*XDGDirs, error) {
24 // Development mode: use .dev directory in current working directory
25 if os.Getenv("ENV") == "dev" {
26 cwd, err := os.Getwd()
27 if err != nil {
28 return nil, err
29 }
30 devDir := filepath.Join(cwd, ".dev", appName)
31 return &XDGDirs{
32 ConfigHome: devDir,
33 DataHome: devDir,
34 StateHome: devDir,
35 }, nil
36 }
37
38 homeDir, err := os.UserHomeDir()
39 if err != nil {
40 return nil, err
41 }
42
43 // XDG_CONFIG_HOME
44 configHome := os.Getenv("XDG_CONFIG_HOME")
45 if configHome == "" {
46 configHome = filepath.Join(homeDir, ".config")
47 }
48 configHome = filepath.Join(configHome, appName)
49
50 // XDG_DATA_HOME
51 dataHome := os.Getenv("XDG_DATA_HOME")
52 if dataHome == "" {
53 dataHome = filepath.Join(homeDir, ".local", "share")
54 }
55 dataHome = filepath.Join(dataHome, appName)
56
57 // XDG_STATE_HOME
58 stateHome := os.Getenv("XDG_STATE_HOME")
59 if stateHome == "" {
60 stateHome = filepath.Join(homeDir, ".local", "state")
61 }
62 stateHome = filepath.Join(stateHome, appName)
63
64 return &XDGDirs{
65 ConfigHome: configHome,
66 DataHome: dataHome,
67 StateHome: stateHome,
68 }, nil
69}
70
71// GetConfigDir returns the XDG config directory for dumber.
72func GetConfigDir() (string, error) {
73 dirs, err := GetXDGDirs()
74 if err != nil {
75 return "", err
76 }
77 return dirs.ConfigHome, nil
78}
79
80// GetDataDir returns the XDG data directory for dumber.
81func GetDataDir() (string, error) {
82 dirs, err := GetXDGDirs()
83 if err != nil {
84 return "", err
85 }
86 return dirs.DataHome, nil
87}
88
89// GetStateDir returns the XDG state directory for dumber.
90func GetStateDir() (string, error) {
91 dirs, err := GetXDGDirs()
92 if err != nil {
93 return "", err
94 }
95 return dirs.StateHome, nil
96}
97
98// GetLogDir returns the XDG-compliant log directory for dumber.
99// Logs are stored in XDG_STATE_HOME as per specification.
100func GetLogDir() (string, error) {
101 stateDir, err := GetStateDir()
102 if err != nil {
103 return "", err
104 }
105 return filepath.Join(stateDir, "logs"), nil
106}
107
108// GetConfigFile returns the path to the main configuration file.
109func GetConfigFile() (string, error) {
110 configDir, err := GetConfigDir()
111 if err != nil {
112 return "", err
113 }
114 return filepath.Join(configDir, "config.json"), nil
115}
116
117// GetDatabaseFile returns the path to the database file in the state directory.
118func GetDatabaseFile() (string, error) {
119 stateDir, err := GetStateDir()
120 if err != nil {
121 return "", err
122 }
123 return filepath.Join(stateDir, "history.db"), nil
124}
125
126// GetFilterCacheDir returns the XDG-compliant filter cache directory for dumber.
127// Filter cache is stored in XDG_STATE_HOME as it's transient data that can be regenerated.
128func GetFilterCacheDir() (string, error) {
129 stateDir, err := GetStateDir()
130 if err != nil {
131 return "", err
132 }
133 return filepath.Join(stateDir, "filter-cache"), nil
134}
135
136// GetFilterCacheFile returns the path to the main filter cache file.
137func GetFilterCacheFile() (string, error) {
138 cacheDir, err := GetFilterCacheDir()
139 if err != nil {
140 return "", err
141 }
142 return filepath.Join(cacheDir, "filters.cache"), nil
143}
144
145// EnsureDirectories creates the XDG directories if they don't exist.
146func EnsureDirectories() error {
147 dirs, err := GetXDGDirs()
148 if err != nil {
149 return err
150 }
151
152 // Create all directories with proper permissions
153 directories := []string{
154 dirs.ConfigHome,
155 dirs.DataHome,
156 dirs.StateHome,
157 }
158
159 for _, dir := range directories {
160 if err := os.MkdirAll(dir, dirPerm); err != nil {
161 return err
162 }
163 }
164
165 return nil
166}