125 lines · 4.4 KB · Swift
RawDownload
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    }}