From 75c503ccd464d2e4ee91298f2429ee441223355d Mon Sep 17 00:00:00 2001 From: Alberto De Bortoli Date: Sat, 24 Jan 2026 00:11:10 +0100 Subject: [PATCH] Remove EnrichedTool --- .../LucaCore/Core/Installer/Installer.swift | 18 +++++------ .../PermissionManager/PermissionManager.swift | 4 +-- .../PermissionManaging.swift | 2 +- .../LucaCore/Core/SymLinker/SymLinker.swift | 8 ++--- .../LucaCore/Core/SymLinker/SymLinking.swift | 2 +- Sources/LucaCore/Models/Tool.swift | 28 +++------------- Tests/Core/PermissionManagerTests.swift | 15 +++++---- Tests/Core/SymLinkerTests.swift | 32 +++++++++---------- 8 files changed, 45 insertions(+), 64 deletions(-) diff --git a/Sources/LucaCore/Core/Installer/Installer.swift b/Sources/LucaCore/Core/Installer/Installer.swift index 77aec26..1ca8e96 100644 --- a/Sources/LucaCore/Core/Installer/Installer.swift +++ b/Sources/LucaCore/Core/Installer/Installer.swift @@ -87,7 +87,7 @@ public struct Installer { let installationDestination = fileManager.toolsFolder .appending(components: tool.name, tool.version) let binaryPath = try binaryFinder.findBinary(atPath: installationDestination.path) - let enrichedTool = EnrichedTool( + let resolvedTool = Tool( name: tool.name, version: tool.version, url: tool.url, @@ -96,8 +96,8 @@ public struct Installer { checksum: tool.checksum, algorithm: tool.algorithm ) - try permissionManager.setExecutablePermission(for: enrichedTool) - let symLink = try symLinker.setSymLink(for: enrichedTool) + try permissionManager.setExecutablePermission(for: resolvedTool) + let symLink = try symLinker.setSymLink(for: resolvedTool) printer.printFormatted("\(.raw("🔗 Recreated symlink at \(symLink.path)"))") printer.printFormatted("\(.primary("🙌 Tool \(tool.name) version \(tool.version) installed for the current project."))") @@ -151,7 +151,7 @@ public struct Installer { installationDestination: installationDestination ) - let enrichedTool = EnrichedTool( + let resolvedTool = Tool( name: tool.name, version: tool.version, url: tool.url, @@ -160,11 +160,11 @@ public struct Installer { checksum: tool.checksum, algorithm: tool.algorithm ) - try permissionManager.setExecutablePermission(for: enrichedTool) + try permissionManager.setExecutablePermission(for: resolvedTool) printer.printFormatted("\(.raw("💾 Installed \(tool.name) version \(tool.version) at \(installationDestination.path)"))") - let symLink = try symLinker.setSymLink(for: enrichedTool) + let symLink = try symLinker.setSymLink(for: resolvedTool) printer.printFormatted("\(.raw("🔗 Created symlink to \(symLink.path)"))") } @@ -184,7 +184,7 @@ public struct Installer { installationDestination: installationDestination ) - let enrichedTool = EnrichedTool( + let resolvedTool = Tool( name: tool.name, version: tool.version, url: tool.url, @@ -193,11 +193,11 @@ public struct Installer { checksum: nil, algorithm: nil ) - try permissionManager.setExecutablePermission(for: enrichedTool) + try permissionManager.setExecutablePermission(for: resolvedTool) printer.printFormatted("\(.raw("💾 Installed \(tool.name) version \(tool.version) at \(installationDestination.path)"))") - let symLink = try symLinker.setSymLink(for: enrichedTool) + let symLink = try symLinker.setSymLink(for: resolvedTool) printer.printFormatted("\(.raw("🔗 Created symlink to \(symLink.path)"))") } diff --git a/Sources/LucaCore/Core/PermissionManager/PermissionManager.swift b/Sources/LucaCore/Core/PermissionManager/PermissionManager.swift index 4bbc7bd..99c53a6 100644 --- a/Sources/LucaCore/Core/PermissionManager/PermissionManager.swift +++ b/Sources/LucaCore/Core/PermissionManager/PermissionManager.swift @@ -24,10 +24,10 @@ struct PermissionManager: PermissionManaging { self.fileManager = fileManager } - func setExecutablePermission(for tool: EnrichedTool) throws { + func setExecutablePermission(for tool: Tool) throws { let destinationFile = fileManager.toolsFolder .appending(components: tool.name, tool.version) - .appending(components: tool.desiredBinaryName ?? tool.binaryPath) + .appending(path: tool.effectiveBinaryPath) guard fileManager.fileExists(atPath: destinationFile.path) else { throw PermissionManagerError.missingFile(destinationFile.path) diff --git a/Sources/LucaCore/Core/PermissionManager/PermissionManaging.swift b/Sources/LucaCore/Core/PermissionManager/PermissionManaging.swift index 0fa1f23..94d1a6c 100644 --- a/Sources/LucaCore/Core/PermissionManager/PermissionManaging.swift +++ b/Sources/LucaCore/Core/PermissionManager/PermissionManaging.swift @@ -3,5 +3,5 @@ import Foundation protocol PermissionManaging { - func setExecutablePermission(for tool: EnrichedTool) throws + func setExecutablePermission(for tool: Tool) throws } diff --git a/Sources/LucaCore/Core/SymLinker/SymLinker.swift b/Sources/LucaCore/Core/SymLinker/SymLinker.swift index f9b7c5c..90c0487 100644 --- a/Sources/LucaCore/Core/SymLinker/SymLinker.swift +++ b/Sources/LucaCore/Core/SymLinker/SymLinker.swift @@ -24,16 +24,16 @@ struct SymLinker: SymLinking { // MARK: - Internal @discardableResult - func setSymLink(for tool: EnrichedTool) throws -> URL { + func setSymLink(for tool: Tool) throws -> URL { let symLinkFile = fileManager.activeFolder - .appending(component: tool.binaryName) + .appending(component: tool.expectedBinaryName) let destinationFile = fileManager.toolsFolder .appending(components: tool.name, tool.version) - .appending(components: tool.desiredBinaryName ?? tool.binaryPath) + .appending(path: tool.effectiveBinaryPath) if !fileManager.fileExists(atPath: destinationFile.path) { - throw SymLinkerError.missingBinaryFile(binaryName: tool.binaryName, expectedLocation: destinationFile.path) + throw SymLinkerError.missingBinaryFile(binaryName: tool.expectedBinaryName, expectedLocation: destinationFile.path) } if symLinkExists(atPath: symLinkFile.path) { try fileManager.removeItem(at: symLinkFile) diff --git a/Sources/LucaCore/Core/SymLinker/SymLinking.swift b/Sources/LucaCore/Core/SymLinker/SymLinking.swift index 0ee83cb..2de181e 100644 --- a/Sources/LucaCore/Core/SymLinker/SymLinking.swift +++ b/Sources/LucaCore/Core/SymLinker/SymLinking.swift @@ -3,5 +3,5 @@ import Foundation protocol SymLinking { - func setSymLink(for tool: EnrichedTool) throws -> URL + func setSymLink(for tool: Tool) throws -> URL } diff --git a/Sources/LucaCore/Models/Tool.swift b/Sources/LucaCore/Models/Tool.swift index 6df8cb8..ca2ef0c 100644 --- a/Sources/LucaCore/Models/Tool.swift +++ b/Sources/LucaCore/Models/Tool.swift @@ -28,30 +28,10 @@ extension Tool { if let binaryPath { return URL(fileURLWithPath: binaryPath).lastPathComponent } return name } -} - -struct EnrichedTool: Codable { - /// Logical name of the tool (used for directory hierarchy). - let name: String - /// Version string (used to build folder names and allow side‑by‑side installs). - let version: String - /// Remote URL to an archive containing the tool or an executable file. - let url: URL - /// Path (possibly nested) to the binary inside the unzipped archive. - let binaryPath: String - /// Name of the binary stored locally. Requires `url` to point to an executable file, ignored otherwise. - let desiredBinaryName: String? - /// The checksum hash of asset associated with the tool. - let checksum: String? - /// The algorithm used to generate the checksum. - let algorithm: ChecksumAlgorithm? - /// Basename of the binary derived from `binaryPath` if available, otherwise falls back to `name`. - var binaryName: String { - if let desiredBinaryName { - return desiredBinaryName - } - return URL(fileURLWithPath: binaryPath) - .lastPathComponent + /// Resolves the path to the binary file within the tool's installation directory. + /// Priority: desiredBinaryName > binaryPath > name. + var effectiveBinaryPath: String { + desiredBinaryName ?? binaryPath ?? name } } diff --git a/Tests/Core/PermissionManagerTests.swift b/Tests/Core/PermissionManagerTests.swift index 4e6da78..9bf3cfc 100644 --- a/Tests/Core/PermissionManagerTests.swift +++ b/Tests/Core/PermissionManagerTests.swift @@ -13,7 +13,7 @@ struct PermissionManagerTests { let permissionManagerFileManager = PermissionManagerFileManagerMock(fileManager: fileManager) let sut = PermissionManager(fileManager: permissionManagerFileManager) - let tool = EnrichedTool( + let tool = Tool( name: "ToggleGen", version: "1.0.0", url: URL(string: "https://example.com")!, @@ -25,7 +25,7 @@ struct PermissionManagerTests { let binaryPath = permissionManagerFileManager.toolsFolder .appending(components: tool.name, tool.version) - .appending(component: tool.binaryPath) + .appending(path: tool.effectiveBinaryPath) try fileManager.createDirectory(at: binaryPath.deletingLastPathComponent(), withIntermediateDirectories: true) #expect(fileManager.createFile(atPath: binaryPath.path, contents: Data())) @@ -41,11 +41,7 @@ struct PermissionManagerTests { let permissionManagerFileManager = PermissionManagerFileManagerMock(fileManager: fileManager) let sut = PermissionManager(fileManager: permissionManagerFileManager) - let filePath = permissionManagerFileManager.toolsFolder - .appending(components: "ToggleGen", "1.0.0", "bin/ToggleGen") - .path - - let tool = EnrichedTool( + let tool = Tool( name: "ToggleGen", version: "1.0.0", url: URL(string: "https://example.com")!, @@ -55,6 +51,11 @@ struct PermissionManagerTests { algorithm: nil ) + let filePath = permissionManagerFileManager.toolsFolder + .appending(components: tool.name, tool.version) + .appending(path: tool.effectiveBinaryPath) + .path + #expect(throws: PermissionManager.PermissionManagerError.missingFile(filePath)) { try sut.setExecutablePermission(for: tool) } diff --git a/Tests/Core/SymLinkerTests.swift b/Tests/Core/SymLinkerTests.swift index 1d13b15..8dfa369 100644 --- a/Tests/Core/SymLinkerTests.swift +++ b/Tests/Core/SymLinkerTests.swift @@ -10,7 +10,7 @@ struct SymLinkerTests { @Test func createSymLink_toolExists_binaryPathSpecified() throws { - let tool = EnrichedTool( + let tool = Tool( name: "ToggleGen", version: "1.0.0", url: URL(string: "https://example.com")!, @@ -24,14 +24,14 @@ struct SymLinkerTests { let toolFilePath = symLinkFileManager.toolsFolder .appending(components: tool.name, "1.0.0") - .appending(components: tool.binaryPath) + .appending(path: tool.effectiveBinaryPath) try fileManager.createDirectory(at: toolFilePath.deletingLastPathComponent(), withIntermediateDirectories: true) fileManager.createFile(atPath: toolFilePath.path, contents: Data()) let sut = SymLinker(fileManager: symLinkFileManager) let symLinkPath = symLinkFileManager.activeFolder - .appending(component: tool.binaryName) + .appending(component: tool.expectedBinaryName) .path #expect(!symLinkExists(atPath: symLinkPath)) @@ -44,7 +44,7 @@ struct SymLinkerTests { @Test func createSymLink_toolExists_desiredBinaryNameSpecified() throws { let desiredBinaryName = "togglegen" - let tool = EnrichedTool( + let tool = Tool( name: "ToggleGen", version: "1.0.0", url: URL(string: "https://example.com")!, @@ -58,14 +58,14 @@ struct SymLinkerTests { let toolFilePath = symLinkFileManager.toolsFolder .appending(components: tool.name, "1.0.0") - .appending(components: desiredBinaryName) + .appending(component: desiredBinaryName) try fileManager.createDirectory(at: toolFilePath.deletingLastPathComponent(), withIntermediateDirectories: true) fileManager.createFile(atPath: toolFilePath.path, contents: Data()) let sut = SymLinker(fileManager: symLinkFileManager) let symLinkPath = symLinkFileManager.activeFolder - .appending(component: tool.binaryName) + .appending(component: tool.expectedBinaryName) .path #expect(!symLinkExists(atPath: symLinkPath)) @@ -77,7 +77,7 @@ struct SymLinkerTests { @Test func createSymLink_toolExists_nestedBinaryPathSpecified() throws { - let tool = EnrichedTool( + let tool = Tool( name: "ToggleGen", version: "1.0.0", url: URL(string: "https://example.com")!, @@ -91,14 +91,14 @@ struct SymLinkerTests { let toolFilePath = symLinkFileManager.toolsFolder .appending(components: tool.name, "1.0.0") - .appending(components: tool.binaryPath) + .appending(path: tool.effectiveBinaryPath) try fileManager.createDirectory(at: toolFilePath.deletingLastPathComponent(), withIntermediateDirectories: true) fileManager.createFile(atPath: toolFilePath.path, contents: Data()) let sut = SymLinker(fileManager: symLinkFileManager) let symLinkPath = symLinkFileManager.activeFolder - .appending(component: tool.binaryName) + .appending(component: tool.expectedBinaryName) .path #expect(!symLinkExists(atPath: symLinkPath)) @@ -110,7 +110,7 @@ struct SymLinkerTests { @Test func createSymLink_symLinkExists() throws { - let tool = EnrichedTool( + let tool = Tool( name: "ToggleGen", version: "1.0.0", url: URL(string: "https://example.com")!, @@ -126,13 +126,13 @@ struct SymLinkerTests { .appending(components: tool.name, "1.0.0") try fileManager.createDirectory(at: toolFolderPath, withIntermediateDirectories: true) let toolFilePath = toolFolderPath - .appending(components: tool.binaryPath) + .appending(path: tool.effectiveBinaryPath) fileManager.createFile(atPath: toolFilePath.path, contents: Data()) let sut = SymLinker(fileManager: symLinkFileManager) let symLinkPath = symLinkFileManager.activeFolder - .appending(component: tool.binaryName) + .appending(component: tool.expectedBinaryName) .path try sut.setSymLink(for: tool) @@ -143,7 +143,7 @@ struct SymLinkerTests { @Test func createSymLink_toolDoesNotExist() throws { - let tool = EnrichedTool( + let tool = Tool( name: "ToggleGen", version: "1.0.0", url: URL(string: "https://example.com")!, @@ -158,18 +158,18 @@ struct SymLinkerTests { let sut = SymLinker(fileManager: symLinkFileManager) let symLinkPath = symLinkFileManager.activeFolder - .appending(component: tool.binaryName) + .appending(component: tool.expectedBinaryName) .path #expect(!symLinkExists(atPath: symLinkPath)) let expectedDestination = symLinkFileManager.toolsFolder .appending(components: tool.name, tool.version) - .appending(components: tool.binaryPath) + .appending(path: tool.effectiveBinaryPath) #expect( throws: SymLinker.SymLinkerError.missingBinaryFile( - binaryName: tool.binaryName, + binaryName: tool.expectedBinaryName, expectedLocation: expectedDestination.path ) ) {