Files
swift-hpa/Sources/hpa/CreateCommand.swift

187 lines
5.2 KiB
Swift

import ArgumentParser
import CliClient
import ConfigurationClient
import Dependencies
import Foundation
import Logging
struct CreateCommand: AsyncParsableCommand {
static let commandName = "create"
static let configuration = CommandConfiguration.playbook(
commandName: commandName,
abstract: "Create a home performance assesment project.",
examples: (
label: "Create Assesment",
example: "\(commandName) /new/assement/path"
)
)
@OptionGroup var globals: GlobalOptions
@Option(
name: .shortAndLong,
help: "The template repository to use."
)
var repo: String?
@Option(
name: .shortAndLong,
help: "The repo branch or version to use."
)
var branch: String?
@Option(
name: .shortAndLong,
help: "Path to local template directory to use.",
completion: .directory
)
var templateDir: String?
@Flag(
name: .shortAndLong,
help: "Force using a local template directory."
)
var localTemplateDir = false
@Argument(
help: "Path to the project directory.",
completion: .directory
)
var projectDir: String
@Argument(
help: "Extra arguments passed to the playbook."
)
var extraArgs: [String] = []
mutating func run() async throws {
try await _run()
}
private func _run() async throws {
try await withSetupLogger(commandName: Self.commandName, globals: globals) {
@Dependency(\.coders) var coders
@Dependency(\.cliClient) var cliClient
@Dependency(\.configurationClient) var configurationClient
@Dependency(\.logger) var logger
let encoder = coders.jsonEncoder()
let configuration = try await configurationClient.findAndLoad()
logger.debug("Configuration: \(configuration)")
let jsonData = try parseOptions(
command: self,
configuration: configuration,
logger: logger,
encoder: encoder
)
guard let jsonString = String(data: jsonData, encoding: .utf8) else {
throw CreateError.encodingError
}
logger.debug("JSON string: \(jsonString)")
let arguments = [
"--tags", "setup-project",
"--extra-vars", "project_dir=\(self.projectDir)",
"--extra-vars", "'\(jsonString)'"
] + extraArgs
try await cliClient.runPlaybookCommand(
globals.playbookOptions(
arguments: arguments,
configuration: configuration
)
)
// try await runPlaybook(
// commandName: Self.commandName,
// globals: self.globals,
// configuration: configuration,
// extraArgs: extraArgs,
// "--tags", "setup-project",
// "--extra-vars", "project_dir=\(self.projectDir)",
// "--extra-vars", "'\(jsonString)'"
// )
}
}
}
private func parseOptions(
command: CreateCommand,
configuration: Configuration,
logger: Logger,
encoder: JSONEncoder
) throws -> Data {
let templateDir = command.templateDir ?? configuration.template.directory
let templateRepo = command.repo ?? configuration.template.url
let version = (command.branch ?? configuration.template.version) ?? "main"
logger.debug("""
(\(command.localTemplateDir), \(String(describing: templateDir)), \(String(describing: templateRepo)))
""")
switch (command.localTemplateDir, templateDir, templateRepo) {
case (true, .none, _):
// User supplied they wanted to use a local template directory, but we could not find
// the path set from command line or in configuration.
throw CreateError.templateDirNotFound
case let (false, _, .some(repo)):
// User did not supply they wanted to use a local template directory, and we found a repo url that was
// either set by the command line or found in the configuration.
logger.debug("Using repo.")
return try encoder.encode(TemplateRepo(repo: repo, version: version))
case let (true, .some(templateDir), _):
// User supplied they wanted to use a local template directory, and we found the template directory
// either set by the command line or in the configuration.
logger.debug("Using template directory.")
return try encoder.encode(TemplateDirJson(path: templateDir))
case let (false, .some(templateDir), _):
// User supplied they did not wanted to use a local template directory, and we found the template directory
// either set by the command line or in the configuration, and no repo was found / handled previously.
logger.debug("Using template directory.")
return try encoder.encode(TemplateDirJson(path: templateDir))
case (_, .none, .none):
// We could not find a repo or template directory.
throw CreateError.templateDirOrRepoNotSpecified
}
}
private struct TemplateDirJson: Encodable {
let template: Template
init(path: String) {
self.template = .init(path: path)
}
struct Template: Encodable {
let path: String
}
}
private struct TemplateRepo: Encodable {
let template: Template
init(repo: String, version: String?) {
self.template = .init(repo: repo, version: version ?? "main")
}
struct Template: Encodable {
let repo: String
let version: String
}
}
enum CreateError: Error {
case encodingError
case templateDirNotFound
case templateDirOrRepoNotSpecified
}