Files
swift-hpa/Sources/FileClient/FileClient.swift

120 lines
3.2 KiB
Swift

import Dependencies
import DependenciesMacros
import Foundation
public extension DependencyValues {
var fileClient: FileClient {
get { self[FileClient.self] }
set { self[FileClient.self] = newValue }
}
}
@DependencyClient
public struct FileClient: Sendable {
public var copy: @Sendable (URL, URL) async throws -> Void
public var createDirectory: @Sendable (URL) async throws -> Void
public var fileExists: @Sendable (URL) -> Bool = { _ in true }
public var findVaultFileInCurrentDirectory: @Sendable () async throws -> URL?
public var homeDirectory: @Sendable () -> URL = { URL(filePath: "~/") }
public var isDirectory: @Sendable (URL) async throws -> Bool
public var load: @Sendable (URL) async throws -> Data
public var write: @Sendable (Data, URL) async throws -> Void
}
extension FileClient: DependencyKey {
public static let testValue: FileClient = Self()
public static var liveValue: Self {
let manager = LiveFileClient()
return .init {
try await manager.copy($0, to: $1)
} createDirectory: {
try await manager.creatDirectory($0)
} fileExists: { url in
manager.fileExists(at: url)
} findVaultFileInCurrentDirectory: {
try await manager.findVaultFileInCurrentDirectory()
} homeDirectory: {
manager.homeDirectory()
} isDirectory: {
manager.isDirectory($0)
} load: { url in
try await manager.load(from: url)
} write: { data, url in
try await manager.write(data, to: url)
}
}
}
struct LiveFileClient: Sendable {
private var manager: FileManager { FileManager.default }
func copy(_ url: URL, to toUrl: URL) async throws {
try manager.copyItem(at: url, to: toUrl)
}
func creatDirectory(_ url: URL) async throws {
try manager.createDirectory(at: url, withIntermediateDirectories: true)
}
func fileExists(at url: URL) -> Bool {
manager.fileExists(atPath: url.cleanFilePath)
}
func findVaultFileInCurrentDirectory() async throws -> URL? {
let urls = try manager.contentsOfDirectory(
at: URL(filePath: "./"),
includingPropertiesForKeys: nil
)
// Check the current directory
if let vault = urls.firstVaultFile { return vault }
let subfolders = urls.filter { isDirectory($0) }
for folder in subfolders {
let files = try manager.contentsOfDirectory(
at: folder,
includingPropertiesForKeys: nil
)
if let vault = files.firstVaultFile { return vault }
}
return nil
}
func homeDirectory() -> URL {
manager.homeDirectoryForCurrentUser
}
func isDirectory(_ url: URL) -> Bool {
var isDirectory: ObjCBool = false
manager.fileExists(atPath: url.cleanFilePath, isDirectory: &isDirectory)
return isDirectory.boolValue
}
func load(from url: URL) async throws -> Data {
try Data(contentsOf: url)
}
func write(_ data: Data, to url: URL) async throws {
try data.write(to: url)
}
}
private extension Array where Element == URL {
var firstVaultFile: URL? {
first { url in
let string = url.absoluteString
return string.hasSuffix("vault.yml") || string.hasSuffix("vault.yaml")
}
}
}
public extension URL {
var cleanFilePath: String {
absoluteString.replacing("file://", with: "")
}
}