190 lines
5.1 KiB
Swift
190 lines
5.1 KiB
Swift
import ConfigurationClient
|
|
import Dependencies
|
|
import DependenciesMacros
|
|
import FileClient
|
|
import Foundation
|
|
import PlaybookClient
|
|
import ShellClient
|
|
|
|
public extension CliClient {
|
|
|
|
func runCommand(
|
|
quiet: Bool,
|
|
shell: ShellCommand.Shell,
|
|
_ args: [String]
|
|
) async throws {
|
|
try await runCommand(.init(arguments: args, quiet: quiet, shell: shell))
|
|
}
|
|
|
|
func runCommand(
|
|
quiet: Bool,
|
|
shell: ShellCommand.Shell,
|
|
_ args: String...
|
|
) async throws {
|
|
try await runCommand(quiet: quiet, shell: shell, args)
|
|
}
|
|
|
|
func installDependencies(
|
|
quiet: Bool = false,
|
|
shell: String? = nil,
|
|
extraArgs: [String]? = nil
|
|
) async throws {
|
|
@Dependency(\.playbookClient) var playbookClient
|
|
@Dependency(\.configurationClient) var configurationClient
|
|
|
|
var arguments = [
|
|
"brew", "install"
|
|
] + Constants.brewPackages
|
|
|
|
if let extraArgs {
|
|
arguments.append(contentsOf: extraArgs)
|
|
}
|
|
|
|
try await runCommand(
|
|
quiet: quiet,
|
|
shell: shell.orDefault,
|
|
arguments
|
|
)
|
|
|
|
let configuration = try await configurationClient.findAndLoad()
|
|
try await playbookClient.repository.install(configuration)
|
|
}
|
|
|
|
func runPlaybookCommand(
|
|
_ options: PlaybookOptions,
|
|
logging loggingOptions: LoggingOptions
|
|
) async throws {
|
|
try await withLogger(loggingOptions) {
|
|
@Dependency(\.configurationClient) var configurationClient
|
|
@Dependency(\.logger) var logger
|
|
@Dependency(\.playbookClient) var playbookClient
|
|
|
|
let configuration = try await configurationClient.ensuredConfiguration(options.configuration)
|
|
logger.trace("Configuration: \(configuration)")
|
|
|
|
let playbookDirectory = try await playbookClient.repository.directory(configuration)
|
|
let playbookPath = "\(playbookDirectory)/\(Constants.playbookFileName)"
|
|
logger.trace("Playbook path: \(playbookPath)")
|
|
|
|
let inventoryPath = ensuredInventoryPath(
|
|
options.inventoryFilePath,
|
|
configuration: configuration,
|
|
playbookDirectory: playbookDirectory
|
|
)
|
|
logger.trace("Inventory path: \(inventoryPath)")
|
|
|
|
var arguments = [
|
|
Constants.playbookCommand, playbookPath,
|
|
"--inventory", inventoryPath
|
|
] + options.arguments
|
|
|
|
if let defaultArgs = configuration.args {
|
|
arguments.append(contentsOf: defaultArgs)
|
|
}
|
|
|
|
if configuration.useVaultArgs, let vaultArgs = configuration.vault.args {
|
|
arguments.append(contentsOf: vaultArgs)
|
|
}
|
|
|
|
logger.trace("Running playbook command with arguments: \(arguments)")
|
|
|
|
try await runCommand(
|
|
quiet: options.quiet,
|
|
shell: options.shell.orDefault,
|
|
arguments
|
|
)
|
|
}
|
|
}
|
|
|
|
func runVaultCommand(
|
|
_ options: VaultOptions,
|
|
logging loggingOptions: LoggingOptions
|
|
) async throws {
|
|
try await withLogger(loggingOptions) {
|
|
@Dependency(\.configurationClient) var configurationClient
|
|
@Dependency(\.fileClient) var fileClient
|
|
@Dependency(\.logger) var logger
|
|
|
|
let configuration = try await configurationClient.ensuredConfiguration(options.configuration)
|
|
logger.trace("Configuration: \(configuration)")
|
|
|
|
let vaultFilePath = try await fileClient.ensuredVaultFilePath(options.vaultFilePath)
|
|
logger.trace("Vault file: \(vaultFilePath)")
|
|
|
|
var arguments = [
|
|
Constants.vaultCommand
|
|
] + options.arguments
|
|
|
|
if let defaultArgs = configuration.vault.args {
|
|
arguments.append(contentsOf: defaultArgs)
|
|
}
|
|
|
|
if arguments.contains("encrypt"),
|
|
!arguments.contains("--encrypt-vault-id"),
|
|
let id = configuration.vault.encryptId
|
|
{
|
|
arguments.append(contentsOf: ["--encrypt-vault-id", id])
|
|
}
|
|
|
|
arguments.append(vaultFilePath)
|
|
|
|
logger.trace("Running vault command with arguments: \(arguments)")
|
|
|
|
try await runCommand(
|
|
quiet: options.quiet,
|
|
shell: options.shell.orDefault,
|
|
arguments
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
@_spi(Internal)
|
|
public extension ConfigurationClient {
|
|
func ensuredConfiguration(_ optionalConfig: Configuration?) async throws -> Configuration {
|
|
guard let config = optionalConfig else {
|
|
return try await findAndLoad()
|
|
}
|
|
return config
|
|
}
|
|
}
|
|
|
|
@_spi(Internal)
|
|
public extension Optional where Wrapped == String {
|
|
var orDefault: ShellCommand.Shell {
|
|
guard let shell = self else { return .zsh(useDashC: true) }
|
|
return .custom(path: shell, useDashC: true)
|
|
}
|
|
}
|
|
|
|
@_spi(Internal)
|
|
public func ensuredInventoryPath(
|
|
_ optionalInventoryPath: String?,
|
|
configuration: Configuration,
|
|
playbookDirectory: String
|
|
) -> String {
|
|
guard let path = optionalInventoryPath else {
|
|
guard let path = configuration.playbook?.inventory else {
|
|
return "\(playbookDirectory)/\(Constants.inventoryFileName)"
|
|
}
|
|
return path
|
|
}
|
|
return path
|
|
}
|
|
|
|
@_spi(Internal)
|
|
public extension FileClient {
|
|
|
|
func ensuredVaultFilePath(_ optionalPath: String?) async throws -> String {
|
|
guard let path = optionalPath else {
|
|
guard let url = try await findVaultFileInCurrentDirectory() else {
|
|
throw CliClientError.vaultFileNotFound
|
|
}
|
|
return url.cleanFilePath
|
|
}
|
|
return path
|
|
}
|
|
}
|
|
|
|
extension ShellCommand.Shell: @retroactive @unchecked Sendable {}
|