Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/internal/config/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,18 @@ func initPaths() *Paths {
// - Otherwise uses ~/.local/share/dtvem (XDG default)
// - This is the standard location for user-specific data files on Linux
//
// macOS: Uses ~/.dtvem
// macOS: Uses ~/.dtvem by default
// - macOS has its own conventions (~/Library/Application Support) but many CLI tools
// use dotfiles in home directory for better discoverability and Unix compatibility
// - ~/.dtvem is more familiar to users coming from tools like nvm, pyenv, rbenv
// - Optionally respects $XDG_DATA_HOME if set (for users who prefer XDG consistency)
//
// Windows: Uses %USERPROFILE%\.dtvem
// Windows: Uses %USERPROFILE%\.dtvem by default
// - Alternatives considered: %LOCALAPPDATA% (C:\Users\<user>\AppData\Local)
// - Chose home directory for consistency with macOS/Linux and better visibility
// - Users expect CLI tool configs in their home directory
// - Easier to locate and backup than buried in AppData
// - Optionally respects $XDG_DATA_HOME if set (for users who prefer XDG consistency)
//
// Override: DTVEM_ROOT environment variable overrides all platform defaults
func getRootDir() string {
Expand All @@ -79,12 +81,17 @@ func getRootDir() string {
return ".dtvem"
}

// On Linux, respect XDG Base Directory specification
// On Linux, always respect XDG Base Directory specification
if runtime.GOOS == constants.OSLinux {
return getXDGDataPath(home)
}

// On macOS and Windows, use ~/.dtvem
// On macOS and Windows, use XDG_DATA_HOME if explicitly set (opt-in)
if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
return filepath.Join(xdgDataHome, "dtvem")
}

// Default for macOS and Windows: ~/.dtvem
return filepath.Join(home, ".dtvem")
}

Expand Down
46 changes: 42 additions & 4 deletions src/internal/config/paths_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ func TestGetRootDir_XDGOnLinux(t *testing.T) {
}
}

func TestGetRootDir_NonLinux(t *testing.T) {
// On non-Linux platforms, verify that ~/.dtvem is used regardless of XDG
func TestGetRootDir_NonLinux_WithXDG(t *testing.T) {
// On non-Linux platforms, verify that XDG_DATA_HOME is respected when set
if runtime.GOOS == constants.OSLinux {
t.Skip("This test only runs on non-Linux platforms")
}
Expand All @@ -409,15 +409,53 @@ func TestGetRootDir_NonLinux(t *testing.T) {

// Clear DTVEM_ROOT and set XDG_DATA_HOME
_ = os.Unsetenv("DTVEM_ROOT")
_ = os.Setenv("XDG_DATA_HOME", "/should/be/ignored")
customXDG := "/custom/xdg/data"
_ = os.Setenv("XDG_DATA_HOME", customXDG)
resetPathsForTesting()

result := getRootDir()
expected := filepath.Join(customXDG, "dtvem")

if result != expected {
t.Errorf("getRootDir() on %s should use XDG_DATA_HOME when set, got %q, want %q",
runtime.GOOS, result, expected)
}
}

func TestGetRootDir_NonLinux_WithoutXDG(t *testing.T) {
// On non-Linux platforms, verify that ~/.dtvem is used when XDG_DATA_HOME is not set
if runtime.GOOS == constants.OSLinux {
t.Skip("This test only runs on non-Linux platforms")
}

// Save original environment
originalRoot := os.Getenv("DTVEM_ROOT")
originalXDG := os.Getenv("XDG_DATA_HOME")
defer func() {
if originalRoot != "" {
_ = os.Setenv("DTVEM_ROOT", originalRoot)
} else {
_ = os.Unsetenv("DTVEM_ROOT")
}
if originalXDG != "" {
_ = os.Setenv("XDG_DATA_HOME", originalXDG)
} else {
_ = os.Unsetenv("XDG_DATA_HOME")
}
resetPathsForTesting()
}()

// Clear both DTVEM_ROOT and XDG_DATA_HOME
_ = os.Unsetenv("DTVEM_ROOT")
_ = os.Unsetenv("XDG_DATA_HOME")
resetPathsForTesting()

result := getRootDir()
home, _ := os.UserHomeDir()
expected := filepath.Join(home, ".dtvem")

if result != expected {
t.Errorf("getRootDir() on %s should ignore XDG_DATA_HOME, got %q, want %q",
t.Errorf("getRootDir() on %s without XDG_DATA_HOME should use ~/.dtvem, got %q, want %q",
runtime.GOOS, result, expected)
}
}
Expand Down