chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import Foundation
|
||||
|
||||
public enum CodexBarConfigStoreError: LocalizedError {
|
||||
case invalidURL
|
||||
case decodeFailed(String)
|
||||
case encodeFailed(String)
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidURL:
|
||||
"Invalid CodexBar config path."
|
||||
case let .decodeFailed(details):
|
||||
"Failed to decode CodexBar config: \(details)"
|
||||
case let .encodeFailed(details):
|
||||
"Failed to encode CodexBar config: \(details)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct CodexBarConfigStore: @unchecked Sendable {
|
||||
public static let pathEnvironmentKey = "CODEXBAR_CONFIG"
|
||||
public static let xdgConfigHomeEnvironmentKey = "XDG_CONFIG_HOME"
|
||||
|
||||
public let fileURL: URL
|
||||
private let fileManager: FileManager
|
||||
|
||||
public init(fileURL: URL = Self.defaultURL(), fileManager: FileManager = .default) {
|
||||
self.fileURL = fileURL
|
||||
self.fileManager = fileManager
|
||||
}
|
||||
|
||||
public func load() throws -> CodexBarConfig? {
|
||||
guard self.fileManager.fileExists(atPath: self.fileURL.path) else { return nil }
|
||||
let data = try Data(contentsOf: self.fileURL)
|
||||
let decoder = JSONDecoder()
|
||||
do {
|
||||
let decoded = try decoder.decode(CodexBarConfig.self, from: data)
|
||||
return decoded.normalized()
|
||||
} catch {
|
||||
throw CodexBarConfigStoreError.decodeFailed(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
public func loadOrCreateDefault() throws -> CodexBarConfig {
|
||||
if let existing = try self.load() {
|
||||
return existing
|
||||
}
|
||||
let config = CodexBarConfig.makeDefault()
|
||||
try self.save(config)
|
||||
return config
|
||||
}
|
||||
|
||||
public func save(_ config: CodexBarConfig) throws {
|
||||
let normalized = config.normalized()
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
|
||||
let data: Data
|
||||
do {
|
||||
data = try encoder.encode(normalized)
|
||||
} catch {
|
||||
throw CodexBarConfigStoreError.encodeFailed(error.localizedDescription)
|
||||
}
|
||||
let directory = self.fileURL.deletingLastPathComponent()
|
||||
if !self.fileManager.fileExists(atPath: directory.path) {
|
||||
try self.fileManager.createDirectory(at: directory, withIntermediateDirectories: true)
|
||||
}
|
||||
try data.write(to: self.fileURL, options: [.atomic])
|
||||
try self.applySecurePermissionsIfNeeded()
|
||||
}
|
||||
|
||||
public func deleteIfPresent() throws {
|
||||
guard self.fileManager.fileExists(atPath: self.fileURL.path) else { return }
|
||||
try self.fileManager.removeItem(at: self.fileURL)
|
||||
}
|
||||
|
||||
public static func defaultURL(
|
||||
home: URL = FileManager.default.homeDirectoryForCurrentUser,
|
||||
environment: [String: String] = ProcessInfo.processInfo.environment,
|
||||
fileManager: FileManager = .default) -> URL
|
||||
{
|
||||
if let override = environment[pathEnvironmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!override.isEmpty
|
||||
{
|
||||
let expanded = (override as NSString).expandingTildeInPath
|
||||
return URL(fileURLWithPath: expanded)
|
||||
}
|
||||
|
||||
if let xdgConfigHome = environment[xdgConfigHomeEnvironmentKey]?
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!xdgConfigHome.isEmpty
|
||||
{
|
||||
let expanded = (xdgConfigHome as NSString).expandingTildeInPath
|
||||
if (expanded as NSString).isAbsolutePath {
|
||||
return URL(fileURLWithPath: expanded, isDirectory: true)
|
||||
.appendingPathComponent("codexbar", isDirectory: true)
|
||||
.appendingPathComponent("config.json")
|
||||
}
|
||||
}
|
||||
|
||||
let xdgDefault = home
|
||||
.appendingPathComponent(".config", isDirectory: true)
|
||||
.appendingPathComponent("codexbar", isDirectory: true)
|
||||
.appendingPathComponent("config.json")
|
||||
if fileManager.fileExists(atPath: xdgDefault.path) {
|
||||
return xdgDefault
|
||||
}
|
||||
|
||||
let legacy = home
|
||||
.appendingPathComponent(".codexbar", isDirectory: true)
|
||||
.appendingPathComponent("config.json")
|
||||
if fileManager.fileExists(atPath: legacy.path) {
|
||||
return legacy
|
||||
}
|
||||
|
||||
return xdgDefault
|
||||
}
|
||||
|
||||
private func applySecurePermissionsIfNeeded() throws {
|
||||
#if os(macOS) || os(Linux)
|
||||
try self.fileManager.setAttributes([
|
||||
.posixPermissions: NSNumber(value: Int16(0o600)),
|
||||
], ofItemAtPath: self.fileURL.path)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user