From 558054464c1cb5d8e0bb00aea44a16497a9be982 Mon Sep 17 00:00:00 2001 From: Michael Housh Date: Tue, 17 Dec 2024 14:38:52 -0500 Subject: [PATCH] feat: Create backups of configuration when the force option is not used. --- .../ConfigurationClient.swift | 21 ++++++++++++------- Sources/ConfigurationClient/Constants.swift | 2 +- Sources/FileClient/FileClient.swift | 8 +++++++ justfile | 6 ++++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Sources/ConfigurationClient/ConfigurationClient.swift b/Sources/ConfigurationClient/ConfigurationClient.swift index d04c157..e3bc307 100644 --- a/Sources/ConfigurationClient/ConfigurationClient.swift +++ b/Sources/ConfigurationClient/ConfigurationClient.swift @@ -231,10 +231,10 @@ struct LiveConfigurationClient { let fileUrl = URL(filePath: expandedPath) - if !options.force { - guard !fileManager.fileExists(fileUrl) else { - throw ConfigurationError.fileExists(path: file.path) - } + let exists = fileManager.fileExists(fileUrl) + + if !options.force, exists { + try await createBackup(file.url) } let fileDirectory = fileUrl.deletingLastPathComponent() @@ -245,6 +245,8 @@ struct LiveConfigurationClient { try await fileManager.createDirectory(fileDirectory) } + // TODO: The hpa file needs to be copied somewhere on the system during install and + // not use bundle, as it only works if the tool was built on the users system. if case .toml = file { // In the case of toml, we copy the internal resource that includes // usage comments in the file. @@ -290,9 +292,7 @@ struct LiveConfigurationClient { 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) + try await createBackup(file.url) } let data: Data @@ -308,6 +308,13 @@ struct LiveConfigurationClient { try await fileManager.write(data, file.url) } + private func createBackup(_ url: URL) async throws { + let backupUrl = url.appendingPathExtension("back") + logger.warning("File exists, creating a backup of the existing file at: \(backupUrl.cleanFilePath)") + try await fileManager.copy(url, backupUrl) + try await fileManager.delete(url) + } + private func findInDirectory(_ directory: URL) async -> File? { for file in validFileNames { let url = directory.appending(path: file) diff --git a/Sources/ConfigurationClient/Constants.swift b/Sources/ConfigurationClient/Constants.swift index 689794a..9030021 100644 --- a/Sources/ConfigurationClient/Constants.swift +++ b/Sources/ConfigurationClient/Constants.swift @@ -14,7 +14,7 @@ public enum HPAKey { public static let resourceFileName = "hpa" public static let resourceFileExtension = "toml" public static let defaultFileName = "config.toml" - public static let defaultFileNameWithoutExtension = "config.toml" + public static let defaultFileNameWithoutExtension = "config" } extension [String: String] { diff --git a/Sources/FileClient/FileClient.swift b/Sources/FileClient/FileClient.swift index 1dbea4a..6619b8a 100644 --- a/Sources/FileClient/FileClient.swift +++ b/Sources/FileClient/FileClient.swift @@ -23,6 +23,9 @@ public struct FileClient: Sendable { /// Create a directory at the given location. public var createDirectory: @Sendable (URL) async throws -> Void + /// Delete the item at the given location. + public var delete: @Sendable (URL) async throws -> Void + /// Check if a file exists at the given location. public var fileExists: @Sendable (URL) -> Bool = { _ in true } @@ -57,6 +60,7 @@ extension FileClient: DependencyKey { return .init( copy: { try await manager.copy($0, to: $1) }, createDirectory: { try await manager.creatDirectory($0) }, + delete: { try await manager.delete($0) }, fileExists: { manager.fileExists(at: $0) }, findVaultFile: { try await manager.findVaultFile(in: $0) }, homeDirectory: { manager.homeDirectory() }, @@ -79,6 +83,10 @@ struct LiveFileClient: Sendable { try manager.createDirectory(at: url, withIntermediateDirectories: true) } + func delete(_ url: URL) async throws { + try manager.removeItem(at: url) + } + func fileExists(at url: URL) -> Bool { manager.fileExists(atPath: url.cleanFilePath) } diff --git a/justfile b/justfile index c57be4f..c7e7e86 100644 --- a/justfile +++ b/justfile @@ -1,4 +1,6 @@ docker_image_name := "swift-hpa" +install_path := "~/.local/share/bin/hpa" +completion_path := "~/.local/share/zsh/completions/_hpa" build mode="debug": swift build -c {{mode}} @@ -37,3 +39,7 @@ update-version: --allow-writing-to-package-directory \ update-version \ hpa + +install: (build "release") + @cp .build/release/hpa {{install_path}} + @{{install_path}} --generate-completion-script zsh > {{completion_path}}