117 lines
2.9 KiB
Swift
117 lines
2.9 KiB
Swift
import Dependencies
|
|
import DependenciesMacros
|
|
import Foundation
|
|
import ShellClient
|
|
|
|
public extension DependencyValues {
|
|
var cliClient: CliClient {
|
|
get { self[CliClient.self] }
|
|
set { self[CliClient.self] = newValue }
|
|
}
|
|
}
|
|
|
|
@DependencyClient
|
|
public struct CliClient: Sendable {
|
|
public var decoder: @Sendable () -> JSONDecoder = { .init() }
|
|
public var encoder: @Sendable () -> JSONEncoder = { .init() }
|
|
public var loadConfiguration: @Sendable () throws -> Configuration
|
|
public var runCommand: @Sendable ([String], Bool, ShellCommand.Shell) async throws -> Void
|
|
public var createConfiguration: @Sendable (_ path: String, _ json: Bool) throws -> Void
|
|
|
|
public func runCommand(
|
|
quiet: Bool,
|
|
shell: ShellCommand.Shell,
|
|
_ args: [String]
|
|
) async throws {
|
|
try await runCommand(args, quiet, shell)
|
|
}
|
|
|
|
public func runCommand(
|
|
quiet: Bool,
|
|
shell: ShellCommand.Shell,
|
|
_ args: String...
|
|
) async throws {
|
|
try await runCommand(args, quiet, shell)
|
|
}
|
|
}
|
|
|
|
extension CliClient: DependencyKey {
|
|
|
|
public static func live(
|
|
decoder: JSONDecoder = .init(),
|
|
encoder: JSONEncoder = .init(),
|
|
env: [String: String]
|
|
) -> Self {
|
|
@Dependency(\.fileClient) var fileClient
|
|
@Dependency(\.logger) var logger
|
|
|
|
return .init {
|
|
decoder
|
|
} encoder: {
|
|
encoder
|
|
} loadConfiguration: {
|
|
let url = try findConfigurationFiles(env: env)
|
|
var env = env
|
|
|
|
logger.trace("Loading configuration from: \(url)")
|
|
try fileClient.loadFile(url, &env, decoder)
|
|
|
|
return try .fromEnv(env, encoder: encoder, decoder: decoder)
|
|
|
|
} runCommand: { args, quiet, shell in
|
|
@Dependency(\.asyncShellClient) var shellClient
|
|
if !quiet {
|
|
try await shellClient.foreground(.init(
|
|
shell: shell,
|
|
environment: ProcessInfo.processInfo.environment,
|
|
in: nil,
|
|
args
|
|
))
|
|
}
|
|
try await shellClient.background(.init(
|
|
shell: shell,
|
|
environment: ProcessInfo.processInfo.environment,
|
|
in: nil,
|
|
args
|
|
))
|
|
} createConfiguration: { path, json in
|
|
|
|
// Early out if a file exists at the path already.
|
|
guard !fileClient.fileExists(path) else {
|
|
throw CliClientError.fileExistsAtPath(path)
|
|
}
|
|
|
|
var path = path
|
|
let data: Data
|
|
|
|
if !json {
|
|
// Write the default env template.
|
|
data = Data(Configuration.fileTemplate.utf8)
|
|
} else {
|
|
if !path.contains(".json") {
|
|
path += ".json"
|
|
}
|
|
data = try jsonEncoder.encode(Configuration.mock)
|
|
}
|
|
|
|
try fileClient.write(path, data)
|
|
}
|
|
}
|
|
|
|
public static var liveValue: CliClient {
|
|
.live(env: ProcessInfo.processInfo.environment)
|
|
}
|
|
|
|
public static let testValue: CliClient = Self()
|
|
}
|
|
|
|
enum CliClientError: Error {
|
|
case fileExistsAtPath(String)
|
|
}
|
|
|
|
private let jsonEncoder: JSONEncoder = {
|
|
var encoder = JSONEncoder()
|
|
encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes]
|
|
return encoder
|
|
}()
|