feat: Adds generate-config command.

This commit is contained in:
2024-11-29 20:32:32 -05:00
parent 84b002c997
commit 505f7d8013
8 changed files with 143 additions and 30 deletions

View File

@@ -0,0 +1,170 @@
import ArgumentParser
import CliClient
import Dependencies
import Foundation
import Logging
struct CreateCommand: AsyncParsableCommand {
static let commandName = "create"
static let configuration = CommandConfiguration.playbookCommandConfiguration(
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(\.cliClient) var cliClient
@Dependency(\.logger) var logger
let encoder = cliClient.encoder()
let configuration = try cliClient.loadConfiguration()
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)")
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.templateDir
let templateRepo = command.repo ?? configuration.templateRepo
let version = (command.branch ?? configuration.templateRepoVersion) ?? "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
}