Skip to content

chore(paths): centralize XDG-aware path resolution#1

Open
ssjoleary wants to merge 3 commits into
mainfrom
maint-xdg-paths
Open

chore(paths): centralize XDG-aware path resolution#1
ssjoleary wants to merge 3 commits into
mainfrom
maint-xdg-paths

Conversation

@ssjoleary
Copy link
Copy Markdown
Contributor

Summary

  • New src/eca_cli/paths.clj centralises XDG-aware path resolution. Adopts the eca-server pattern (eca/src/eca/cache.clj) of env-or-default.
  • Sessions and logs move to $XDG_STATE_HOME/eca/ (default ~/.local/state/eca/). Managed ECA binary stays in $XDG_CACHE_HOME/eca/eca-cli/ (default ~/.cache/eca/eca-cli/).
  • Transparent one-shot migration for eca-cli-sessions.edn: read-both-prefer-new on load; next save writes to the new location.

Tracks the "Outstanding maintenance: production-ready distribution via bbin / XDG paths" item in docs/roadmap.md.

Path table

Item Old New
Sessions ~/.cache/eca/eca-cli-sessions.edn $XDG_STATE_HOME/eca/eca-cli-sessions.edn
Server log ~/.cache/eca/eca-cli.log $XDG_STATE_HOME/eca/eca-cli.log
nREPL log ~/.cache/eca/eca-cli-nrepl.log $XDG_STATE_HOME/eca/eca-cli-nrepl.log
Managed binary ~/.cache/eca/eca-cli/eca $XDG_CACHE_HOME/eca/eca-cli/eca

Out of scope (deliberate)

  • Log rotation / size cap — separate maintenance track.
  • Editor-plugin discovery paths (~/.cache/nvim/eca/eca, ~/.emacs.d/eca/eca) — external, left alone.
  • bb migrate-paths task — read-both-prefer-new is enough.

Test plan

  • bb test — 95 tests, 411 assertions, 0 failures
  • New test/eca_cli/paths_test.clj covers env-var precedence + defaults for cache/state/config
  • test/eca_cli/sessions_test.clj updated with migration scenario (migration-read-old-path-test)
  • clj-kondo: 0 new warnings on changed files

Follow-up

  • test/eca_cli/integration_test.clj:70 still hardcodes ~/.cache/eca/eca-cli-sessions.edn. Out of scope here (integration test wasn't in the change allowlist) but should be updated before next itest run.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Centralizes XDG-aware path resolution for eca-cli, moving mutable runtime artifacts (sessions + logs) under $XDG_STATE_HOME/eca while keeping the managed ECA binary under $XDG_CACHE_HOME/eca. Adds a transparent migration path for sessions by reading the legacy location when the new file is absent.

Changes:

  • Add eca-cli.paths module providing XDG cache/state/config homes and derived file locations.
  • Update sessions persistence to prefer the new state-based sessions file, falling back to the legacy cache-based path on load, and always writing to the new path on save.
  • Redirect server + nREPL logs and managed-binary destination to the new XDG-aware locations; add unit tests for path env-var precedence and the sessions migration scenario.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/eca_cli/paths.clj New centralized XDG-aware path resolution helpers (cache/state/config + derived paths).
src/eca_cli/sessions.clj Switch sessions load/save to new state location with legacy fallback and ensured parent dir creation.
src/eca_cli/server.clj Use new paths for managed binary lookup and default server log file creation.
src/eca_cli/core.clj Move nREPL stdio redirection log to XDG state location and ensure parent dirs exist.
src/eca_cli/upgrade.clj Install/upgrade destination path for managed ECA binary now uses paths/eca-binary.
test/eca_cli/paths_test.clj New tests covering env-var precedence and derived path composition.
test/eca_cli/sessions_test.clj Update tests to use new paths API and add migration test (read legacy, write new).
bb.edn Register new paths test namespace in the bb test runner.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +10 to +57
(with-redefs [paths/getenv (stub-env {"XDG_CACHE_HOME" "/tmp/c"})]
(is (= "/tmp/c" (str (paths/cache-home))))))
(testing "falls back to ~/.cache when unset"
(with-redefs [paths/getenv (stub-env {})]
(is (= (str (System/getProperty "user.home") "/.cache")
(str (paths/cache-home))))))
(testing "empty string is treated as unset"
(with-redefs [paths/getenv (stub-env {"XDG_CACHE_HOME" ""})]
(is (= (str (System/getProperty "user.home") "/.cache")
(str (paths/cache-home)))))))

(deftest state-home-with-env-test
(testing "honours XDG_STATE_HOME when set"
(with-redefs [paths/getenv (stub-env {"XDG_STATE_HOME" "/tmp/s"})]
(is (= "/tmp/s" (str (paths/state-home))))))
(testing "falls back to ~/.local/state when unset"
(with-redefs [paths/getenv (stub-env {})]
(is (= (str (System/getProperty "user.home") "/.local/state")
(str (paths/state-home)))))))

(deftest config-home-with-env-test
(testing "honours XDG_CONFIG_HOME when set"
(with-redefs [paths/getenv (stub-env {"XDG_CONFIG_HOME" "/tmp/cfg"})]
(is (= "/tmp/cfg" (str (paths/config-home))))))
(testing "falls back to ~/.config when unset"
(with-redefs [paths/getenv (stub-env {})]
(is (= (str (System/getProperty "user.home") "/.config")
(str (paths/config-home)))))))

(deftest eca-cache-dir-composition-test
(with-redefs [paths/getenv (stub-env {"XDG_CACHE_HOME" "/tmp/c"})]
(is (= "/tmp/c/eca" (str (paths/eca-cache-dir))))))

(deftest eca-state-dir-composition-test
(with-redefs [paths/getenv (stub-env {"XDG_STATE_HOME" "/tmp/s"})]
(is (= "/tmp/s/eca" (str (paths/eca-state-dir))))))

(deftest sessions-file-under-state-test
(with-redefs [paths/getenv (stub-env {"XDG_STATE_HOME" "/tmp/s"})]
(is (= "/tmp/s/eca/eca-cli-sessions.edn" (str (paths/sessions-file))))))

(deftest log-file-under-state-test
(with-redefs [paths/getenv (stub-env {"XDG_STATE_HOME" "/tmp/s"})]
(is (= "/tmp/s/eca/eca-cli.log" (str (paths/log-file))))
(is (= "/tmp/s/eca/eca-cli-nrepl.log" (str (paths/nrepl-log-file))))))

(deftest eca-binary-under-cache-test
(with-redefs [paths/getenv (stub-env {"XDG_CACHE_HOME" "/tmp/c"})]
Comment thread src/eca_cli/paths.clj Outdated
"XDG-aware path resolution for eca-cli (cache, state, config)."
(:require [clojure.java.io :as io]))

(defn- getenv [k] (System/getenv k))
ssjoleary added 2 commits May 15, 2026 19:38
Addresses PR #1 review: paths/getenv was private (defn-) but tests
referenced it directly in with-redefs, which fails at compile time
on JVM Clojure with "var is not public". Making the seam explicitly
public matches the intent of an injectable env lookup. SCI/Babashka
was permissive about this, masking the latent issue.
Remove redundant File<->String roundtrips and name the log-file candidate
once so the warning message describes the actual path attempted. Extracts
ensure-writable as a context-free mechanism (parent-dir creation +
isDirectory check), separated from the default-log-file policy.
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