Skip to content

Fix config path mismatch: honor documented ~/.config on every OS - #55

Merged
KevinTCoughlin merged 1 commit into
mainfrom
fix/config-path-xdg-migration
Aug 27, 2026
Merged

KevinTCoughlin merged 1 commit into
mainfrom
fix/config-path-xdg-migration

Conversation

@KevinTCoughlin

Copy link
Copy Markdown
Owner

Problem

os.UserConfigDir() resolves to an OS-native directory (e.g. ~/Library/Application Support on macOS, %AppData% on Windows) — not ~/.config. But README.md and the starter-file comments have always documented ~/.config/lazydeck/devices.toml / config.yml.

On macOS/Windows this meant a user hand-editing the documented path had their changes silently ignored, since lazydeck actually read/wrote a different, hidden file.

Fix

  • configDir() now resolves $XDG_CONFIG_HOME/lazydeck, falling back to ~/.config/lazydeck, on every OS.
  • migrateLegacyPath() does a one-time, best-effort migration: if a config already exists at the old OS-native location and nothing exists yet at the documented path, it's moved into place (never overwrites an existing documented-path file), with a one-line stderr notice.
  • Added tests: XDG override, ~/.config fallback, legacy migration, and non-clobbering.
  • README updated to explain the canonical path and migration behavior.

Testing

go build ./... && go vet ./... && go test ./... all pass.

os.UserConfigDir() resolves to an OS-native directory (e.g. "~/Library/
Application Support" on macOS, %AppData% on Windows) that never matched
the ~/.config/lazydeck path this project's README and starter-file
comments have always documented. Users hand-editing the documented path
on macOS/Windows had their changes silently ignored, since lazydeck read
a different, hidden file.

- configDir() now resolves $XDG_CONFIG_HOME/lazydeck, falling back to
  ~/.config/lazydeck, regardless of OS.
- migrateLegacyPath() does a one-time, best-effort migration of any
  config already sitting at the old OS-native location into the
  documented path, printing a one-line stderr notice. It never
  overwrites a file already present at the documented path.
- Added tests for XDG override, ~/.config fallback, legacy migration,
  and non-clobbering of an existing documented-path file.
- Updated README to explain the canonical path and migration behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 27bb5a8d-6d4c-48ff-88b0-3a109a4bff0c
Copilot AI lite review requested due to automatic review settings August 27, 2026 03:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

New tests can be unsafe/flaky on Windows because they don’t fully sandbox the environment variables that control os.UserHomeDir()/os.UserConfigDir(), risking reads/writes (and deletion) in real user config locations during local runs.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR aligns lazydeck’s actual config file location with the long-documented ~/.config/lazydeck path (or $XDG_CONFIG_HOME/lazydeck), adds a one-time migration from Go’s os.UserConfigDir() OS-native location, and updates documentation/tests accordingly.

Changes:

  • Centralized config path resolution to always use $XDG_CONFIG_HOME/lazydeck or ~/.config/lazydeck across all OSes, with legacy migration from os.UserConfigDir().
  • Added migration-focused tests for XDG override, ~/.config fallback, migration behavior, and non-clobbering.
  • Updated README to document the canonical location and migration notice.
File summaries
File Description
README.md Documents the canonical config path and the one-time migration behavior.
internal/config/config.go Implements canonical cross-platform config dir resolution and legacy-path migration.
internal/config/config_test.go Adds tests covering XDG behavior, fallback, migration, and non-overwrite guarantees.
Review details

Suppressed comments (3)

internal/config/config_test.go:323

  • These path-resolution tests assume os.UserHomeDir() will honor HOME, but on Windows it uses USERPROFILE (and os.UserConfigDir uses APPDATA). Without setting those too, this test can be flaky or can accidentally touch real user directories on Windows.
	t.Setenv("XDG_CONFIG_HOME", "")
	home := t.TempDir()
	t.Setenv("HOME", home)

internal/config/config_test.go:345

  • This test sets HOME to a temp dir but still calls os.UserConfigDir(); on Windows that uses APPDATA/LOCALAPPDATA and can create/delete files in the real user profile. Set USERPROFILE/APPDATA/LOCALAPPDATA too so the legacy path is fully sandboxed.
	t.Setenv("XDG_CONFIG_HOME", "")
	home := t.TempDir()
	t.Setenv("HOME", home)

internal/config/config_test.go:403

  • Same sandboxing issue as other tests: setting HOME alone does not reliably redirect os.UserHomeDir/os.UserConfigDir on Windows. Set USERPROFILE/APPDATA/LOCALAPPDATA so this test can't touch or delete real user config during local runs on Windows.
	t.Setenv("XDG_CONFIG_HOME", "")
	home := t.TempDir()
	t.Setenv("HOME", home)

  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/config/config.go
Comment on lines +249 to +251
if _, err := os.Stat(newPath); err == nil {
return
}
Comment on lines +302 to +306
// migrateLegacyPath calls os.UserConfigDir(), which reads $HOME
// directly; isolate it to an empty temp dir so this test can never
// read (and delete) the real user's actual legacy config file.
t.Setenv("HOME", t.TempDir())

@KevinTCoughlin
KevinTCoughlin merged commit 662ef27 into main Aug 27, 2026
13 checks passed
@KevinTCoughlin
KevinTCoughlin deleted the fix/config-path-xdg-migration branch August 27, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants