import Dependencies import Foundation import ShellClient @_spi(Internal) public func findConfigurationFiles( env: [String: String] = ProcessInfo.processInfo.environment ) throws -> URL { @Dependency(\.logger) var logger @Dependency(\.fileClient) var fileClient logger.debug("Begin find configuration files.") logger.trace("Env: \(env)") // Check for environment variable pointing to a directory that the // the configuration lives. if let pwd = env["PWD"], let url = fileClient.checkUrl(.file(pwd, ".hparc")) { logger.debug("Found configuration in current working directory.") return url } // 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 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"], let url = fileClient.checkUrl(.directory(xdgConfigHome, "hpa-playbook")) { logger.debug("XDG Config url: \(url.absoluteString)") return url } // We could not find configuration in any usual places. throw ConfigurationError.configurationNotFound } func path(for url: URL) -> String { url.absoluteString.replacing("file://", with: "") } 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 } }