Files
swift-hpa/Sources/PlaybookClient/PlaybookClient.swift

190 lines
5.1 KiB
Swift

import CommandClient
import ConfigurationClient
import Dependencies
import DependenciesMacros
import FileClient
import Foundation
import ShellClient
// TODO: Add update checks and pull for the playbook.
public extension DependencyValues {
var playbookClient: PlaybookClient {
get { self[PlaybookClient.self] }
set { self[PlaybookClient.self] = newValue }
}
}
@DependencyClient
public struct PlaybookClient: Sendable {
public var repository: Repository
public var run: RunPlaybook
}
public extension PlaybookClient {
@DependencyClient
struct Repository: Sendable {
public var install: @Sendable (Configuration?) async throws -> Void
public var directory: @Sendable (Configuration?) async throws -> String
public func install() async throws {
try await install(nil)
}
public func directory() async throws -> String {
try await directory(nil)
}
}
}
public extension PlaybookClient {
@DependencyClient
struct RunPlaybook: Sendable {
public var buildProject: @Sendable (BuildOptions) async throws -> Void
public var createProject: @Sendable (CreateOptions, JSONEncoder?) async throws -> Void
public func createProject(_ options: CreateOptions) async throws {
try await createProject(options, nil)
}
public struct SharedRunOptions: Equatable, Sendable {
public let extraOptions: [String]?
public let inventoryFilePath: String?
public let loggingOptions: LoggingOptions
public let quiet: Bool
public let shell: String?
public init(
extraOptions: [String]? = nil,
inventoryFilePath: String? = nil,
loggingOptions: LoggingOptions,
quiet: Bool = false,
shell: String? = nil
) {
self.extraOptions = extraOptions
self.inventoryFilePath = inventoryFilePath
self.loggingOptions = loggingOptions
self.quiet = quiet
self.shell = shell
}
}
@dynamicMemberLookup
public struct BuildOptions: Equatable, Sendable {
public let projectDirectory: String?
public let shared: SharedRunOptions
public init(
projectDirectory: String? = nil,
shared: SharedRunOptions
) {
self.projectDirectory = projectDirectory
self.shared = shared
}
public init(
extraOptions: [String]? = nil,
inventoryFilePath: String? = nil,
loggingOptions: LoggingOptions,
quiet: Bool = false,
shell: String? = nil,
projectDirectory: String? = nil
) {
self.projectDirectory = projectDirectory
self.shared = .init(
extraOptions: extraOptions,
inventoryFilePath: inventoryFilePath,
loggingOptions: loggingOptions,
quiet: quiet,
shell: shell
)
}
public subscript<T>(dynamicMember keyPath: KeyPath<SharedRunOptions, T>) -> T {
shared[keyPath: keyPath]
}
}
@dynamicMemberLookup
public struct CreateOptions: Equatable, Sendable {
public let projectDirectory: String
public let shared: SharedRunOptions
public let template: Configuration.Template?
public let useLocalTemplateDirectory: Bool
public init(
projectDirectory: String,
shared: SharedRunOptions,
template: Configuration.Template? = nil,
useLocalTemplateDirectory: Bool
) {
self.projectDirectory = projectDirectory
self.shared = shared
self.template = template
self.useLocalTemplateDirectory = useLocalTemplateDirectory
}
public init(
extraOptions: [String]? = nil,
inventoryFilePath: String? = nil,
loggingOptions: LoggingOptions,
projectDirectory: String,
quiet: Bool = false,
shell: String? = nil,
template: Configuration.Template? = nil,
useLocalTemplateDirectory: Bool = false
) {
self.projectDirectory = projectDirectory
self.template = template
self.useLocalTemplateDirectory = useLocalTemplateDirectory
self.shared = .init(
extraOptions: extraOptions,
inventoryFilePath: inventoryFilePath,
loggingOptions: loggingOptions,
quiet: quiet,
shell: shell
)
}
public subscript<T>(dynamicMember keyPath: KeyPath<SharedRunOptions, T>) -> T {
shared[keyPath: keyPath]
}
}
}
}
extension PlaybookClient.Repository: DependencyKey {
public static var liveValue: Self {
.init {
try await installPlaybook(configuration: $0)
} directory: {
try await findDirectory(configuration: $0)
}
}
}
extension PlaybookClient.RunPlaybook: DependencyKey {
public static var liveValue: PlaybookClient.RunPlaybook {
.init(
buildProject: { try await $0.run() },
createProject: { try await $0.run(encoder: $1) }
)
}
}
extension PlaybookClient: DependencyKey {
public static let testValue: PlaybookClient = Self(
repository: Repository(),
run: RunPlaybook()
)
public static var liveValue: PlaybookClient {
.init(
repository: .liveValue,
run: .liveValue
)
}
}