Skip to content

Commit da89cf7

Browse files
committed
feat(config): support XDG_DATA_HOME on Windows and macOS
When XDG_DATA_HOME is explicitly set, dtvem will now use $XDG_DATA_HOME/dtvem as the root directory on Windows and macOS, matching the existing Linux behavior. This is opt-in only - when XDG_DATA_HOME is not set, the default ~/.dtvem is still used. Closes #202
1 parent 4339f80 commit da89cf7

2 files changed

Lines changed: 53 additions & 8 deletions

File tree

src/internal/config/paths.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,18 @@ func initPaths() *Paths {
5454
// - Otherwise uses ~/.local/share/dtvem (XDG default)
5555
// - This is the standard location for user-specific data files on Linux
5656
//
57-
// macOS: Uses ~/.dtvem
57+
// macOS: Uses ~/.dtvem by default
5858
// - macOS has its own conventions (~/Library/Application Support) but many CLI tools
5959
// use dotfiles in home directory for better discoverability and Unix compatibility
6060
// - ~/.dtvem is more familiar to users coming from tools like nvm, pyenv, rbenv
61+
// - Optionally respects $XDG_DATA_HOME if set (for users who prefer XDG consistency)
6162
//
62-
// Windows: Uses %USERPROFILE%\.dtvem
63+
// Windows: Uses %USERPROFILE%\.dtvem by default
6364
// - Alternatives considered: %LOCALAPPDATA% (C:\Users\<user>\AppData\Local)
6465
// - Chose home directory for consistency with macOS/Linux and better visibility
6566
// - Users expect CLI tool configs in their home directory
6667
// - Easier to locate and backup than buried in AppData
68+
// - Optionally respects $XDG_DATA_HOME if set (for users who prefer XDG consistency)
6769
//
6870
// Override: DTVEM_ROOT environment variable overrides all platform defaults
6971
func getRootDir() string {
@@ -79,12 +81,17 @@ func getRootDir() string {
7981
return ".dtvem"
8082
}
8183

82-
// On Linux, respect XDG Base Directory specification
84+
// On Linux, always respect XDG Base Directory specification
8385
if runtime.GOOS == constants.OSLinux {
8486
return getXDGDataPath(home)
8587
}
8688

87-
// On macOS and Windows, use ~/.dtvem
89+
// On macOS and Windows, use XDG_DATA_HOME if explicitly set (opt-in)
90+
if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
91+
return filepath.Join(xdgDataHome, "dtvem")
92+
}
93+
94+
// Default for macOS and Windows: ~/.dtvem
8895
return filepath.Join(home, ".dtvem")
8996
}
9097

src/internal/config/paths_test.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ func TestGetRootDir_XDGOnLinux(t *testing.T) {
384384
}
385385
}
386386

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

410410
// Clear DTVEM_ROOT and set XDG_DATA_HOME
411411
_ = os.Unsetenv("DTVEM_ROOT")
412-
_ = os.Setenv("XDG_DATA_HOME", "/should/be/ignored")
412+
customXDG := "/custom/xdg/data"
413+
_ = os.Setenv("XDG_DATA_HOME", customXDG)
414+
resetPathsForTesting()
415+
416+
result := getRootDir()
417+
expected := filepath.Join(customXDG, "dtvem")
418+
419+
if result != expected {
420+
t.Errorf("getRootDir() on %s should use XDG_DATA_HOME when set, got %q, want %q",
421+
runtime.GOOS, result, expected)
422+
}
423+
}
424+
425+
func TestGetRootDir_NonLinux_WithoutXDG(t *testing.T) {
426+
// On non-Linux platforms, verify that ~/.dtvem is used when XDG_DATA_HOME is not set
427+
if runtime.GOOS == constants.OSLinux {
428+
t.Skip("This test only runs on non-Linux platforms")
429+
}
430+
431+
// Save original environment
432+
originalRoot := os.Getenv("DTVEM_ROOT")
433+
originalXDG := os.Getenv("XDG_DATA_HOME")
434+
defer func() {
435+
if originalRoot != "" {
436+
_ = os.Setenv("DTVEM_ROOT", originalRoot)
437+
} else {
438+
_ = os.Unsetenv("DTVEM_ROOT")
439+
}
440+
if originalXDG != "" {
441+
_ = os.Setenv("XDG_DATA_HOME", originalXDG)
442+
} else {
443+
_ = os.Unsetenv("XDG_DATA_HOME")
444+
}
445+
resetPathsForTesting()
446+
}()
447+
448+
// Clear both DTVEM_ROOT and XDG_DATA_HOME
449+
_ = os.Unsetenv("DTVEM_ROOT")
450+
_ = os.Unsetenv("XDG_DATA_HOME")
413451
resetPathsForTesting()
414452

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

419457
if result != expected {
420-
t.Errorf("getRootDir() on %s should ignore XDG_DATA_HOME, got %q, want %q",
458+
t.Errorf("getRootDir() on %s without XDG_DATA_HOME should use ~/.dtvem, got %q, want %q",
421459
runtime.GOOS, result, expected)
422460
}
423461
}

0 commit comments

Comments
 (0)