feat: Reorganizes files

This commit is contained in:
2024-11-30 09:21:27 -05:00
parent ed3f752694
commit 2c551e33d3
12 changed files with 212 additions and 113 deletions

View File

@@ -56,7 +56,7 @@ extension CliClient: DependencyKey {
logger.trace("Loading configuration from: \(url)")
try fileClient.loadFile(url, &env, decoder)
return try .fromEnv(env, encoder: encoder, decoder: decoder)
return try .fromEnv(env)
} runCommand: { args, quiet, shell in
@Dependency(\.asyncShellClient) var shellClient

View File

@@ -10,9 +10,9 @@ public struct Configuration: Codable {
public let templateRepo: String?
public let templateRepoVersion: String?
public let templateDir: String?
public let defaultPlaybookArgs: String?
public let defaultPlaybookArgs: [String]?
private enum CodingKeys: String, CodingKey {
fileprivate enum CodingKeys: String, CodingKey {
case playbookDir = "HPA_PLAYBOOK_DIR"
case inventoryPath = "HPA_DEFAULT_INVENTORY"
case templateRepo = "HPA_TEMPLATE_REPO"
@@ -22,23 +22,26 @@ public struct Configuration: Codable {
}
public static func fromEnv(
_ env: [String: String],
encoder: JSONEncoder = .init(),
decoder: JSONDecoder = .init()
_ env: [String: String]
) throws -> Self {
@Dependency(\.logger) var logger
logger.trace("Creating configuration from env...")
// logger.debug("\(env)")
let hpaValues = env.reduce(into: [String: String]()) { partial, next in
if next.key.contains("HPA") {
partial[next.key] = next.value
}
}
let hpaValues: [String: String] = env.filter { $0.key.contains("HPA") }
logger.debug("HPA env vars: \(hpaValues)")
let data = try encoder.encode(env)
return try decoder.decode(Configuration.self, from: data)
let defaultArgs: [String]? = hpaValues.value(key: .defaultPlaybookArgs)
.flatMap { $0.split(separator: ",").map(String.init) }
return Configuration(
playbookDir: hpaValues.value(key: .playbookDir),
inventoryPath: hpaValues.value(key: .inventoryPath),
templateRepo: hpaValues.value(key: .templateRepo),
templateRepoVersion: hpaValues.value(key: .templateRepoVersion),
templateDir: hpaValues.value(key: .templateDir),
defaultPlaybookArgs: defaultArgs
)
}
static var mock: Self {
@@ -48,7 +51,7 @@ public struct Configuration: Codable {
templateRepo: "https://git.example.com/consult-template.git",
templateRepoVersion: "main",
templateDir: "/path/to/local/template",
defaultPlaybookArgs: "--vault-id=myId@$SCRIPTS/vault-gopass-client"
defaultPlaybookArgs: ["--vault-id=myId@$SCRIPTS/vault-gopass-client"]
)
}
@@ -77,3 +80,9 @@ public struct Configuration: Codable {
"""
}
}
extension [String: String] {
fileprivate func value(key codingKey: Configuration.CodingKeys) -> String? {
self[codingKey.rawValue]
}
}

View File

@@ -13,7 +13,6 @@ public extension DependencyValues {
@_spi(Internal)
@DependencyClient
public struct FileClient: Sendable {
public var contentsOfDirectory: @Sendable (URL) throws -> [URL]
public var loadFile: @Sendable (URL, inout [String: String], JSONDecoder) throws -> Void
public var homeDir: @Sendable () -> URL = { URL(string: "~/")! }
public var isDirectory: @Sendable (URL) -> Bool = { _ in false }
@@ -29,7 +28,6 @@ extension FileClient: DependencyKey {
public static func live(fileManager: FileManager = .default) -> Self {
let client = LiveFileClient(fileManager: fileManager)
return Self(
contentsOfDirectory: { try client.contentsOfDirectory(url: $0) },
loadFile: { try client.loadFile(at: $0, into: &$1, decoder: $2) },
homeDir: { client.homeDir },
isDirectory: { client.isDirectory(url: $0) },
@@ -64,10 +62,6 @@ private struct LiveFileClient: @unchecked Sendable {
fileManager.isReadableFile(atPath: path(for: url))
}
func contentsOfDirectory(url: URL) throws -> [URL] {
try fileManager.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
}
func fileExists(at path: String) -> Bool {
fileManager.fileExists(atPath: path)
}
@@ -76,7 +70,7 @@ private struct LiveFileClient: @unchecked Sendable {
@Dependency(\.logger) var logger
logger.trace("Begin load file for: \(path(for: url))")
if url.absoluteString.contains(".json") {
if url.absoluteString.hasSuffix(".json") {
// Handle json file.
let data = try Data(contentsOf: url)
let dict = (try? decoder.decode([String: String].self, from: data)) ?? [:]

View File

@@ -12,49 +12,45 @@ public func findConfigurationFiles(
logger.debug("Begin find configuration files.")
logger.trace("Env: \(env)")
let homeDir = fileClient.homeDir()
// Check for environment variable pointing to a directory that the
// the configuration lives.
if let configHome = env["HPA_CONFIG_HOME"] {
let url = URL(filePath: configHome).appending(path: "config")
if fileClient.isReadable(url) {
logger.debug("Found configuration from hpa config home env var.")
return url
}
if let pwd = env["PWD"],
let url = fileClient.checkUrl(.file(pwd, ".hparc"))
{
logger.debug("Found configuration in current working directory.")
return url
}
// Check home directory for a `.hparc` file.
let url = homeDir.appending(path: ".hparc")
if fileClient.isReadable(url) {
logger.debug("Found configuration in home directory")
// Check for environment variable pointing to a file that the
// the configuration lives.
if let configFile = env["HPA_CONFIG_FILE"],
let url = fileClient.checkUrl(.file(configFile))
{
logger.debug("Found configuration from hpa config file env var.")
return url
}
// Check for environment variable pointing to a directory that the
// the configuration lives.
if let pwd = env["PWD"] {
let url = URL(filePath: "\(pwd)").appending(path: ".hparc")
if fileClient.isReadable(url) {
logger.debug("Found configuration in current working directory.")
return url
}
if let configHome = env["HPA_CONFIG_HOME"],
let url = fileClient.checkUrl(.directory(configHome))
{
logger.debug("Found configuration from hpa config home env var.")
return url
}
// Check home directory for a `.hparc` file.
if let url = fileClient.checkUrl(.file(fileClient.homeDir().appending(path: ".hparc"))) {
logger.debug("Found configuration in home directory")
return url
}
// Check in xdg config home, under an hpa-playbook directory.
if let xdgConfigHome = env["XDG_CONFIG_HOME"] {
logger.debug("XDG Config Home: \(xdgConfigHome)")
let url = URL(filePath: "\(xdgConfigHome)")
.appending(path: "hpa-playbook")
.appending(path: "config")
if let xdgConfigHome = env["XDG_CONFIG_HOME"],
let url = fileClient.checkUrl(.directory(xdgConfigHome, "hpa-playbook"))
{
logger.debug("XDG Config url: \(url.absoluteString)")
if fileClient.isReadable(url) {
return url
}
return url
}
// We could not find configuration in any usual places.
@@ -68,3 +64,46 @@ func path(for url: URL) -> String {
enum ConfigurationError: Error {
case configurationNotFound
}
private extension FileClient {
enum ConfigurationUrlCheck {
case file(URL)
case directory(URL)
static func file(_ path: String) -> Self { .file(URL(filePath: path)) }
static func file(_ paths: String...) -> Self {
var url = URL(filePath: paths[0])
url = paths.dropFirst().reduce(into: url) { $0.append(path: $1) }
return .file(url)
}
static func directory(_ path: String) -> Self { .directory(URL(filePath: path)) }
static func directory(_ paths: String...) -> Self {
var url = URL(filePath: paths[0])
url = paths.dropFirst().reduce(into: url) { $0.append(path: $1) }
return .directory(url)
}
}
func checkUrl(_ check: ConfigurationUrlCheck) -> URL? {
switch check {
case let .file(url):
if isReadable(url) { return url }
return nil
case let .directory(url):
return findConfigurationInDirectory(url)
}
}
func findConfigurationInDirectory(_ url: URL) -> URL? {
for file in ["config", "config.json"] {
let fileUrl = url.appending(path: file)
if isReadable(fileUrl) {
return fileUrl
}
}
return nil
}
}