feat: Adding documentation comments.
All checks were successful
CI / Run Tests (push) Successful in 2m17s
All checks were successful
CI / Run Tests (push) Successful in 2m17s
This commit is contained in:
@@ -110,15 +110,33 @@ public struct CommandClient: Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents logger setup options used when running commands.
|
||||
///
|
||||
/// This set's up metadata tags and keys appropriately for the command being run,
|
||||
/// which can aid in debugging.
|
||||
///
|
||||
public struct LoggingOptions: Equatable, Sendable {
|
||||
|
||||
/// The command name / key that the logger is running for.
|
||||
public let commandName: String
|
||||
|
||||
/// The log level.
|
||||
public let logLevel: Logger.Level
|
||||
|
||||
/// Create the logging options.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - commandName: The command name / key that the logger is running for.
|
||||
/// - logLevel: The log level.
|
||||
public init(commandName: String, logLevel: Logger.Level) {
|
||||
self.commandName = commandName
|
||||
self.logLevel = logLevel
|
||||
}
|
||||
|
||||
/// Perform an operation with a setup logger.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - operation: The operation to perform with the setup logger.
|
||||
@discardableResult
|
||||
public func withLogger<T>(
|
||||
operation: @Sendable @escaping () async throws -> T
|
||||
|
||||
@@ -52,11 +52,34 @@ public struct Configuration: Codable, Equatable, Sendable {
|
||||
)
|
||||
}
|
||||
|
||||
/// Configuration options for running `pandoc` commands that generate files from
|
||||
/// a templated directory.
|
||||
///
|
||||
/// ## NOTE: Most of these can also be set by the template repository variables.
|
||||
///
|
||||
///
|
||||
public struct Generate: Codable, Equatable, Sendable {
|
||||
|
||||
/// Specifiy the name of the build directory, generally `.build`.
|
||||
public let buildDirectory: String?
|
||||
|
||||
/// Specifiy the files used in the `pandoc` command to generate a final output file.
|
||||
///
|
||||
/// - SeeAlso: `pandoc --help`
|
||||
public let files: [String]?
|
||||
|
||||
/// Specifiy the files used in the `pandoc` command to include in the header.
|
||||
///
|
||||
/// - SeeAlso: `pandoc --help`
|
||||
public let includeInHeader: [String]?
|
||||
|
||||
/// The default name of the output file, this does not require the file extension as we will
|
||||
/// add it based on the command that is called. Generally this is 'Report'.
|
||||
///
|
||||
public let outputFileName: String?
|
||||
|
||||
/// The default pdf engine to use when generating pdf files using `pandoc`. Generally
|
||||
/// this is 'xelatex'.
|
||||
public let pdfEngine: String?
|
||||
|
||||
public init(
|
||||
@@ -73,8 +96,10 @@ public struct Configuration: Codable, Equatable, Sendable {
|
||||
self.pdfEngine = pdfEngine
|
||||
}
|
||||
|
||||
/// Represents the default configuration for generating files using `pandoc`.
|
||||
public static let `default` = Self.mock
|
||||
|
||||
/// Represents mock configuration for generating files using `pandoc`.
|
||||
public static var mock: Self {
|
||||
.init(
|
||||
buildDirectory: ".build",
|
||||
@@ -86,10 +111,22 @@ public struct Configuration: Codable, Equatable, Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration options for the ansible-hpa-playbook. The playbook is
|
||||
/// the primary driver of templating files, generating repository templates, and building
|
||||
/// projects.
|
||||
///
|
||||
/// ## NOTE: These are generally only used for local development of the playbook.
|
||||
///
|
||||
///
|
||||
public struct Playbook: Codable, Equatable, Sendable {
|
||||
|
||||
/// The directory location of the ansible playbook.
|
||||
public let directory: String?
|
||||
|
||||
/// The inventory file name / location.
|
||||
public let inventory: String?
|
||||
|
||||
/// The playbook version, branch, or tag.
|
||||
public let version: String?
|
||||
|
||||
public init(
|
||||
@@ -105,9 +142,28 @@ public struct Configuration: Codable, Equatable, Sendable {
|
||||
public static var mock: Self { .init() }
|
||||
}
|
||||
|
||||
/// Configuration settings for the user's template repository or directory.
|
||||
///
|
||||
/// A template is what is used to create projects for a user. Generally they setup
|
||||
/// their own template by customizing the default template to their needs. This template
|
||||
/// can then be stored as a git repository or on the local file system.
|
||||
///
|
||||
/// The template will hold variables and files that are used to generate the final output
|
||||
/// files using `pandoc`. Generally the template will hold files that may only need setup once,
|
||||
/// such as header files, footer files, and definitions.
|
||||
///
|
||||
/// The project directory contains dynamic variables / files that need edited in order
|
||||
/// to generate the final output. This allows the project directory to remain smaller so the user
|
||||
/// can more easily focus on the tasks required to generate the final output files.
|
||||
public struct Template: Codable, Equatable, Sendable {
|
||||
|
||||
/// A url of the template when it is a remote git repository.
|
||||
public let url: String?
|
||||
|
||||
/// The version, branch, or tag of the remote repository.
|
||||
public let version: String?
|
||||
|
||||
/// The local directory that contains the template on the local file system.
|
||||
public let directory: String?
|
||||
|
||||
public init(
|
||||
@@ -129,8 +185,23 @@ public struct Configuration: Codable, Equatable, Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for `ansible-vault` commands. Ansible vault is used to encrypt and
|
||||
/// decrypt sensitive data. This allows for variables, such as customer name and address
|
||||
/// to be stored along with the project in an encrypted file so that it is safer to store them.
|
||||
///
|
||||
/// These may also be used in general `ansible-playbook` commands if the `useVaultArgs` is set
|
||||
/// to `true` in a users configuration.
|
||||
///
|
||||
public struct Vault: Codable, Equatable, Sendable {
|
||||
|
||||
/// A list of arguments / options that get passed to the `ansible-vault` command.
|
||||
///
|
||||
/// - SeeAlso: `ansible-vault --help`
|
||||
public let args: [String]?
|
||||
|
||||
/// An id that is used during encrypting `ansible-vault` files.
|
||||
///
|
||||
/// - SeeAlso: `ansible-vault encrypt --help`
|
||||
public let encryptId: String?
|
||||
|
||||
public init(
|
||||
|
||||
@@ -6,24 +6,57 @@ import Foundation
|
||||
import ShellClient
|
||||
|
||||
public extension DependencyValues {
|
||||
|
||||
/// Interacts with the user's configuration.
|
||||
var configurationClient: ConfigurationClient {
|
||||
get { self[ConfigurationClient.self] }
|
||||
set { self[ConfigurationClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents actions that can be taken on user's configuration files.
|
||||
///
|
||||
///
|
||||
@DependencyClient
|
||||
public struct ConfigurationClient: Sendable {
|
||||
|
||||
/// Find the user's configuration, searches in the current directory and default
|
||||
/// locations where configuration can be stored. An error is thrown if no configuration
|
||||
/// is found.
|
||||
public var find: @Sendable () async throws -> File
|
||||
|
||||
/// Generate a configuration file for the user.
|
||||
public var generate: @Sendable (GenerateOptions) async throws -> String
|
||||
|
||||
/// Load a configuration file from the given file location. If the file is
|
||||
/// not provided then we return an empty configuraion item.
|
||||
public var load: @Sendable (File?) async throws -> Configuration
|
||||
|
||||
/// Write the configuration to the given file, optionally forcing an overwrite of
|
||||
/// the file.
|
||||
///
|
||||
/// ## NOTE: This uses the `fileClient.write` under the hood, so if you need to control
|
||||
/// what happens during tests, then you can customize the behavior of the fileClient.
|
||||
///
|
||||
var write: @Sendable (File, Configuration, Bool) async throws -> Void
|
||||
|
||||
/// Find the user's configuration and load it.
|
||||
public func findAndLoad() async throws -> Configuration {
|
||||
let file = try? await find()
|
||||
return try await load(file)
|
||||
}
|
||||
|
||||
/// Write the configuration to the given file, optionally forcing an overwrite of
|
||||
/// the file. If a file already exists and force is not supplied then we will create
|
||||
/// a backup of the existing file.
|
||||
///
|
||||
/// ## NOTE: This uses the `fileClient.write` under the hood, so if you need to control
|
||||
/// what happens during tests, then you can customize the behavior of the fileClient.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - configuration: The configuration to save.
|
||||
/// - file: The file location and type to save.
|
||||
/// - force: Force overwritting if a file already exists.
|
||||
public func write(
|
||||
_ configuration: Configuration,
|
||||
to file: File,
|
||||
@@ -60,15 +93,12 @@ extension ConfigurationClient: DependencyKey {
|
||||
|
||||
public static func live(environment: [String: String]) -> Self {
|
||||
let liveClient = LiveConfigurationClient(environment: environment)
|
||||
return .init {
|
||||
try await liveClient.find()
|
||||
} generate: {
|
||||
try await liveClient.generate($0)
|
||||
} load: { file in
|
||||
try await liveClient.load(file: file)
|
||||
} write: { file, configuration, force in
|
||||
try await liveClient.write(configuration, to: file, force: force)
|
||||
}
|
||||
return .init(
|
||||
find: { try await liveClient.find() },
|
||||
generate: { try await liveClient.generate($0) },
|
||||
load: { try await liveClient.load(file: $0) },
|
||||
write: { try await liveClient.write($1, to: $0, force: $2) }
|
||||
)
|
||||
}
|
||||
|
||||
public static var liveValue: Self {
|
||||
@@ -221,10 +251,12 @@ struct LiveConfigurationClient {
|
||||
to file: File,
|
||||
force: Bool
|
||||
) async throws {
|
||||
if !force {
|
||||
guard !fileManager.fileExists(file.url) else {
|
||||
throw ConfigurationError.fileExists(path: file.path)
|
||||
}
|
||||
let exists = fileManager.fileExists(file.url)
|
||||
|
||||
if !force, exists {
|
||||
let backupUrl = file.url.appendingPathExtension(".back")
|
||||
logger.warning("File exists, creating a backup of the existing file at: \(backupUrl.cleanFilePath)")
|
||||
try await fileManager.copy(file.url, backupUrl)
|
||||
}
|
||||
|
||||
let data: Data
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/// Represents keys in the environment that can be used to locate a user's
|
||||
/// configuration file.
|
||||
@_spi(Internal)
|
||||
public enum EnvironmentKey {
|
||||
static let xdgConfigHome = "XDG_CONFIG_HOME"
|
||||
@@ -5,6 +7,7 @@ public enum EnvironmentKey {
|
||||
static let hpaConfigFile = "HPA_CONFIG_FILE"
|
||||
}
|
||||
|
||||
/// Represents keys that are used internally for directory names, file names, etc.
|
||||
@_spi(Internal)
|
||||
public enum HPAKey {
|
||||
public static let configDirName = "hpa"
|
||||
|
||||
@@ -2,11 +2,21 @@ import FileClient
|
||||
import Foundation
|
||||
|
||||
/// Represents a file location and type on disk for a configuration file.
|
||||
///
|
||||
/// Currently the supported formats are `json` or `toml`. Toml is the default /
|
||||
/// preferred format because it allows comments in the file and is easy to understand.
|
||||
///
|
||||
public enum File: Equatable, Sendable {
|
||||
|
||||
case json(URL)
|
||||
case toml(URL)
|
||||
|
||||
/// Attempts to create a file with the given url.
|
||||
///
|
||||
/// ## NOTE: There are no checks on if a file / path actually exists or not.
|
||||
///
|
||||
/// If the file does not have a suffix of `json` or `toml` then
|
||||
/// we will return `nil`.
|
||||
public init?(_ url: URL) {
|
||||
if url.cleanFilePath.hasSuffix("json") {
|
||||
self = .json(url)
|
||||
@@ -17,18 +27,17 @@ public enum File: Equatable, Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to create a file with the given path.
|
||||
///
|
||||
/// ## NOTE: There are no checks on if a file / path actually exists or not.
|
||||
///
|
||||
/// If the file does not have a suffix of `json` or `toml` then
|
||||
/// we will return `nil`.
|
||||
public init?(_ path: String) {
|
||||
self.init(URL(filePath: path))
|
||||
}
|
||||
|
||||
public static func json(_ path: String) -> Self {
|
||||
.json(URL(filePath: path))
|
||||
}
|
||||
|
||||
public static func toml(_ path: String) -> Self {
|
||||
.toml(URL(filePath: path))
|
||||
}
|
||||
|
||||
/// Get the url of the file.
|
||||
public var url: URL {
|
||||
switch self {
|
||||
case let .json(url): return url
|
||||
@@ -36,10 +45,14 @@ public enum File: Equatable, Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the path string of the file.
|
||||
public var path: String {
|
||||
url.cleanFilePath
|
||||
}
|
||||
|
||||
/// Represents the default file path for a user's configuration.
|
||||
///
|
||||
/// Which is `~/.config/hpa/config.toml`
|
||||
public static var `default`: Self {
|
||||
let fileUrl = FileManager.default
|
||||
.homeDirectoryForCurrentUser
|
||||
|
||||
Reference in New Issue
Block a user