resolve config directory dynamically following a priority order

This commit is contained in:
2026-07-12 14:49:25 +02:00
parent 8315b8a6e3
commit a6a7f80cce
11 changed files with 133 additions and 40 deletions
+56 -7
View File
@@ -136,10 +136,10 @@ private struct TestPayload: Codable, Equatable {
@MainActor
@Test func computeRunsInConfigDirectory() async throws {
// Block commands execute with the config root (~/.config/phbar) as their
// working directory, so a block from any set resolves relative paths the
// same way. Guards against the config dir being absent in sandboxed CIs.
guard FileManager.default.fileExists(atPath: PHBlock.configDirectory.path) else { return }
// Block commands execute with the resolved config root (see `PHPaths`) as
// their working directory, so a block from any set resolves relative paths
// the same way. Guards against the config dir being absent in sandboxed CIs.
guard FileManager.default.fileExists(atPath: PHPaths.configDirectory.path) else { return }
let blocks = try PHBlock.load(from: """
[[block]]
@@ -148,9 +148,9 @@ private struct TestPayload: Codable, Equatable {
let output = await blocks[0].compute()
// Resolve symlinks on both sides: `~/.config/phbar` is commonly a
// symlink into a dotfiles repo, and `pwd` reports the physical path.
let expected = PHBlock.configDirectory.resolvingSymlinksInPath().path
// Resolve symlinks on both sides: the config dir is commonly a symlink into
// a dotfiles repo, and `pwd` reports the physical path.
let expected = PHPaths.configDirectory.resolvingSymlinksInPath().path
#expect(output == expected)
}
@@ -655,4 +655,53 @@ private func makeBlocksConfigDir() throws -> URL {
#expect(frame.height == 30)
}
// MARK: - PHPaths (config directory cascade)
@Test func pathsCandidatesIncludeAbsoluteXdgFirst() {
let home = FileManager.default.homeDirectoryForCurrentUser
let candidates = PHPaths.configDirectoryCandidates(environment: ["XDG_CONFIG_HOME": "/custom/xdg"])
#expect(candidates.count == 3)
#expect(candidates[0].path == "/custom/xdg/phbar")
#expect(candidates[1].path == home.appending(path: ".config/phbar").path)
#expect(candidates[2].path == home.appending(path: ".phbar").path)
}
@Test func pathsCandidatesOmitRelativeXdg() {
let home = FileManager.default.homeDirectoryForCurrentUser
let candidates = PHPaths.configDirectoryCandidates(environment: ["XDG_CONFIG_HOME": "relative/path"])
#expect(candidates.count == 2)
#expect(candidates[0].path == home.appending(path: ".config/phbar").path)
#expect(candidates[1].path == home.appending(path: ".phbar").path)
}
@Test func pathsCandidatesOmitEmptyXdg() {
let candidates = PHPaths.configDirectoryCandidates(environment: ["XDG_CONFIG_HOME": ""])
#expect(candidates.count == 2)
}
@Test func pathsCandidatesOmitXdgWhenUnset() {
let candidates = PHPaths.configDirectoryCandidates(environment: [:])
#expect(candidates.count == 2)
}
@Test func pathsResolvePicksFirstExistingCandidate() throws {
// An existing XDG-rooted dir takes priority over ~/.config/phbar because
// it sorts first in the candidate list.
let xdgRoot = FileManager.default.temporaryDirectory.appending(path: "phbar_xdg_\(UUID().uuidString)")
let xdgConfig = xdgRoot.appending(path: "phbar")
try FileManager.default.createDirectory(at: xdgConfig, withIntermediateDirectories: true)
defer { try? FileManager.default.removeItem(at: xdgRoot) }
let resolved = PHPaths.resolveConfigDirectory(environment: ["XDG_CONFIG_HOME": xdgRoot.path])
#expect(resolved == xdgConfig)
}
@Test func pathsConfigDirectoryMatchesResolve() {
// The cached static agrees with a fresh resolve against the live process env.
#expect(PHPaths.configDirectory == PHPaths.resolveConfigDirectory())
}