import ArgumentParser import CliClient import Dependencies import Foundation import Logging import Rainbow import ShellClient func runPlaybook( commandName: String, globals: GlobalOptions, configuration: Configuration? = nil, extraArgs: [String], _ args: [String] ) async throws { try await withSetupLogger(commandName: commandName, globals: globals) { @Dependency(\.cliClient) var cliClient @Dependency(\.logger) var logger logger.debug("Begin run playbook: \(globals)") let configuration = try cliClient.ensuredConfiguration(configuration) logger.debug("Configuration: \(configuration)") let playbookDir = try ensureString( globals: globals, configuration: configuration, globalsKeyPath: \.playbookDir, configurationKeyPath: \.playbookDir ) let playbook = "\(playbookDir)/\(Constants.playbookFileName)" let inventory = (try? ensureString( globals: globals, configuration: configuration, globalsKeyPath: \.inventoryPath, configurationKeyPath: \.inventoryPath )) ?? "\(playbookDir)/\(Constants.inventoryFileName)" let defaultArgs = (configuration.defaultPlaybookArgs ?? []) + (configuration.defaultVaultArgs ?? []) try await cliClient.runCommand( quiet: globals.quietOnlyPlaybook ? true : globals.quiet, shell: globals.shellOrDefault, [ "ansible-playbook", playbook, "--inventory", inventory ] + args + extraArgs + defaultArgs ) } } func runPlaybook( commandName: String, globals: GlobalOptions, configuration: Configuration? = nil, extraArgs: [String], _ args: String... ) async throws { try await runPlaybook( commandName: commandName, globals: globals, configuration: configuration, extraArgs: extraArgs, args ) } extension CliClient { func ensuredConfiguration(_ configuration: Configuration?) throws -> Configuration { guard let configuration else { return try loadConfiguration() } return configuration } } extension BasicGlobalOptions { var shellOrDefault: ShellCommand.Shell { guard let shell else { return .zsh(useDashC: true) } return .custom(path: shell, useDashC: true) } } func ensureString( globals: GlobalOptions, configuration: Configuration, globalsKeyPath: KeyPath, configurationKeyPath: KeyPath ) throws -> String { if let global = globals[keyPath: globalsKeyPath] { return global } guard let configuration = configuration[keyPath: configurationKeyPath] else { throw RunPlaybookError.playbookNotFound } return configuration } enum RunPlaybookError: Error { case playbookNotFound case configurationError }