232 lines
6.0 KiB
Swift
232 lines
6.0 KiB
Swift
import ConfigurationClient
|
|
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 runCommand: @Sendable (RunCommandOptions) async throws -> Void
|
|
public var generateJSON: @Sendable (GenerateJsonOptions, LoggingOptions, JSONEncoder) async throws -> String
|
|
|
|
public func generateJSON(
|
|
_ options: GenerateJsonOptions,
|
|
logging loggingOptions: LoggingOptions,
|
|
encoder jsonEncoder: JSONEncoder = .init()
|
|
) async throws -> String {
|
|
try await generateJSON(options, loggingOptions, jsonEncoder)
|
|
}
|
|
}
|
|
|
|
public extension CliClient {
|
|
|
|
struct PandocOptions: Equatable, Sendable {
|
|
|
|
let buildDirectory: String?
|
|
let files: [String]?
|
|
let includeInHeader: [String]?
|
|
let outputDirectory: String?
|
|
let outputFileName: String?
|
|
let outputFileType: FileType
|
|
let projectDirectory: String?
|
|
let quiet: Bool
|
|
let shell: String?
|
|
let shouldBuild: Bool
|
|
|
|
public init(
|
|
buildDirectory: String? = nil,
|
|
files: [String]? = nil,
|
|
includeInHeader: [String]? = nil,
|
|
outputDirectory: String? = nil,
|
|
outputFileName: String? = nil,
|
|
outputFileType: FileType,
|
|
projectDirectory: String?,
|
|
quiet: Bool,
|
|
shell: String? = nil,
|
|
shouldBuild: Bool
|
|
) {
|
|
self.buildDirectory = buildDirectory
|
|
self.files = files
|
|
self.includeInHeader = includeInHeader
|
|
self.outputDirectory = outputDirectory
|
|
self.outputFileName = outputFileName
|
|
self.outputFileType = outputFileType
|
|
self.projectDirectory = projectDirectory
|
|
self.quiet = quiet
|
|
self.shell = shell
|
|
self.shouldBuild = shouldBuild
|
|
}
|
|
|
|
// swiftlint:disable nesting
|
|
public enum FileType: Equatable, Sendable {
|
|
case html
|
|
case latex
|
|
case pdf(engine: String?)
|
|
}
|
|
// swiftlint:enable nesting
|
|
}
|
|
|
|
struct GenerateJsonOptions: Equatable, Sendable {
|
|
let templateDirectory: String?
|
|
let templateRepo: String?
|
|
let version: String?
|
|
let useLocalTemplateDirectory: Bool
|
|
|
|
public init(
|
|
templateDirectory: String?,
|
|
templateRepo: String?,
|
|
version: String?,
|
|
useLocalTemplateDirectory: Bool
|
|
) {
|
|
self.templateDirectory = templateDirectory
|
|
self.templateRepo = templateRepo
|
|
self.version = version
|
|
self.useLocalTemplateDirectory = useLocalTemplateDirectory
|
|
}
|
|
}
|
|
|
|
struct LoggingOptions: Equatable, Sendable {
|
|
let commandName: String
|
|
let logLevel: Logger.Level
|
|
|
|
public init(commandName: String, logLevel: Logger.Level) {
|
|
self.commandName = commandName
|
|
self.logLevel = logLevel
|
|
}
|
|
}
|
|
|
|
struct PlaybookOptions: Sendable, Equatable {
|
|
let arguments: [String]
|
|
let configuration: Configuration?
|
|
let inventoryFilePath: String?
|
|
let playbookDirectory: String?
|
|
let quiet: Bool
|
|
let shell: String?
|
|
|
|
public init(
|
|
arguments: [String],
|
|
configuration: Configuration? = nil,
|
|
inventoryFilePath: String? = nil,
|
|
playbookDirectory: String? = nil,
|
|
quiet: Bool,
|
|
shell: String? = nil
|
|
) {
|
|
self.arguments = arguments
|
|
self.configuration = configuration
|
|
self.inventoryFilePath = inventoryFilePath
|
|
self.playbookDirectory = playbookDirectory
|
|
self.quiet = quiet
|
|
self.shell = shell
|
|
}
|
|
}
|
|
|
|
struct RunCommandOptions: Sendable, Equatable {
|
|
public let arguments: [String]
|
|
public let quiet: Bool
|
|
public let shell: ShellCommand.Shell
|
|
|
|
public init(
|
|
arguments: [String],
|
|
quiet: Bool,
|
|
shell: ShellCommand.Shell
|
|
) {
|
|
self.arguments = arguments
|
|
self.quiet = quiet
|
|
self.shell = shell
|
|
}
|
|
}
|
|
|
|
struct VaultOptions: Equatable, Sendable {
|
|
let arguments: [String]
|
|
let configuration: Configuration?
|
|
let quiet: Bool
|
|
let shell: String?
|
|
let vaultFilePath: String?
|
|
|
|
public init(
|
|
arguments: [String],
|
|
configuration: Configuration? = nil,
|
|
quiet: Bool,
|
|
shell: String?,
|
|
vaultFilePath: String? = nil
|
|
) {
|
|
self.arguments = arguments
|
|
self.configuration = configuration
|
|
self.quiet = quiet
|
|
self.shell = shell
|
|
self.vaultFilePath = vaultFilePath
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CliClient: DependencyKey {
|
|
|
|
public static func live(
|
|
env: [String: String]
|
|
) -> Self {
|
|
@Dependency(\.logger) var logger
|
|
|
|
return .init { options in
|
|
@Dependency(\.asyncShellClient) var shellClient
|
|
if !options.quiet {
|
|
try await shellClient.foreground(.init(
|
|
shell: options.shell,
|
|
environment: ProcessInfo.processInfo.environment,
|
|
in: nil,
|
|
options.arguments
|
|
))
|
|
} else {
|
|
try await shellClient.background(.init(
|
|
shell: options.shell,
|
|
environment: ProcessInfo.processInfo.environment,
|
|
in: nil,
|
|
options.arguments
|
|
))
|
|
}
|
|
} generateJSON: { options, loggingOptions, encoder in
|
|
let data = try await createJSONData(options, logging: loggingOptions, encoder: encoder)
|
|
guard let string = String(data: data, encoding: .utf8) else {
|
|
throw CliClientError.encodingError
|
|
}
|
|
return string
|
|
}
|
|
}
|
|
|
|
public static var liveValue: CliClient {
|
|
.live(env: ProcessInfo.processInfo.environment)
|
|
}
|
|
|
|
public static let testValue: CliClient = Self()
|
|
|
|
public static func capturing(_ client: CapturingClient) -> Self {
|
|
.init { options in
|
|
await client.set(options)
|
|
} generateJSON: {
|
|
try await Self().generateJSON($0, $1, $2)
|
|
}
|
|
}
|
|
|
|
public actor CapturingClient: Sendable {
|
|
public private(set) var quiet: Bool?
|
|
public private(set) var shell: ShellCommand.Shell?
|
|
public private(set) var arguments: [String]?
|
|
|
|
public init() {}
|
|
|
|
public func set(
|
|
_ options: RunCommandOptions
|
|
) {
|
|
quiet = options.quiet
|
|
shell = options.shell
|
|
arguments = options.arguments
|
|
}
|
|
}
|
|
}
|