114 lines
2.7 KiB
Swift
114 lines
2.7 KiB
Swift
import Dependencies
|
|
import DependenciesMacros
|
|
import Foundation
|
|
import ShellClient
|
|
|
|
public extension DependencyValues {
|
|
|
|
/// Runs shell commands.
|
|
var commandClient: CommandClient {
|
|
get { self[CommandClient.self] }
|
|
set { self[CommandClient.self] = newValue }
|
|
}
|
|
}
|
|
|
|
@DependencyClient
|
|
public struct CommandClient: Sendable {
|
|
|
|
/// Runs a shell command.
|
|
public var runCommand: @Sendable (RunCommandOptions) async throws -> Void
|
|
|
|
/// Runs a shell command.
|
|
public func run(
|
|
quiet: Bool,
|
|
shell: ShellCommand.Shell,
|
|
_ arguments: [String]
|
|
) async throws {
|
|
try await runCommand(.init(arguments: arguments, quiet: quiet, shell: shell))
|
|
}
|
|
|
|
/// Runs a shell command.
|
|
public func run(
|
|
quiet: Bool,
|
|
shell: ShellCommand.Shell,
|
|
_ arguments: String...
|
|
) async throws {
|
|
try await run(quiet: quiet, shell: shell, arguments)
|
|
}
|
|
|
|
public 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
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CommandClient: DependencyKey {
|
|
|
|
public static let testValue: CommandClient = Self()
|
|
|
|
public static var liveValue: CommandClient {
|
|
.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
|
|
))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@_spi(Internal)
|
|
public extension CommandClient {
|
|
|
|
/// Create a command client that can capture the arguments / options.
|
|
///
|
|
/// This is used for testing.
|
|
static func capturing(_ client: CapturingClient) -> Self {
|
|
.init { options in
|
|
await client.set(options)
|
|
}
|
|
}
|
|
|
|
/// Captures the arguments / options passed into the command client's run commands.
|
|
///
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ShellCommand.Shell: @retroactive @unchecked Sendable {}
|