From 475b5159646a359134d10e444e79c83fbab688a8 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Mon, 24 Mar 2025 19:01:34 +0000 Subject: [PATCH 1/2] add --no-cache option in lume pull --- libs/lume/src/Commands/Pull.swift | 9 ++- .../ImageContainerRegistry.swift | 57 +++++++++++-------- libs/lume/src/LumeController.swift | 4 +- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/libs/lume/src/Commands/Pull.swift b/libs/lume/src/Commands/Pull.swift index 3993e66a..98d74eed 100644 --- a/libs/lume/src/Commands/Pull.swift +++ b/libs/lume/src/Commands/Pull.swift @@ -17,12 +17,15 @@ struct Pull: AsyncParsableCommand { @Option(help: "Organization to pull from. Defaults to trycua") var organization: String = "trycua" - + + @Flag(help: "Pull image without creating .cache. Defaults to false") + var noCache: Bool = false + init() {} @MainActor func run() async throws { let vmController = LumeController() - try await vmController.pullImage(image: image, name: name, registry: registry, organization: organization) + try await vmController.pullImage(image: image, name: name, registry: registry, organization: organization, noCache: noCache) } -} \ No newline at end of file +} diff --git a/libs/lume/src/ContainerRegistry/ImageContainerRegistry.swift b/libs/lume/src/ContainerRegistry/ImageContainerRegistry.swift index 0f6ba1e8..d2028827 100644 --- a/libs/lume/src/ContainerRegistry/ImageContainerRegistry.swift +++ b/libs/lume/src/ContainerRegistry/ImageContainerRegistry.swift @@ -240,7 +240,7 @@ class ImageContainerRegistry: @unchecked Sendable { } } - func pull(image: String, name: String?) async throws { + func pull(image: String, name: String?, noCache: Bool = false) async throws { // Validate home directory let home = Home() try home.validateHomeDirectory() @@ -287,27 +287,32 @@ class ImageContainerRegistry: @unchecked Sendable { try? FileManager.default.removeItem(at: tempVMDir) } - // Check if we have a valid cached version + // Check if we have a valid cached version and noCache is false Logger.info("Checking cache for manifest ID: \(manifestId)") - if validateCache(manifest: manifest, manifestId: manifestId) { + if !noCache && validateCache(manifest: manifest, manifestId: manifestId) { Logger.info("Using cached version of image") try await copyFromCache(manifest: manifest, manifestId: manifestId, to: tempVMDir) } else { // Clean up old versions of this repository before setting up new cache - try cleanupOldVersions(currentManifestId: manifestId, image: imageName) + if !noCache { + try cleanupOldVersions(currentManifestId: manifestId, image: imageName) + } - Logger.info("Cache miss or invalid cache, setting up new cache") - // Setup new cache directory - try setupImageCache(manifestId: manifestId) + if noCache { + Logger.info("Skipping cache setup due to noCache option") + } else { + Logger.info("Cache miss or invalid cache, setting up new cache") + // Setup new cache directory + try setupImageCache(manifestId: manifestId) + // Save new manifest + try saveManifest(manifest, manifestId: manifestId) - // Save new manifest - try saveManifest(manifest, manifestId: manifestId) - - // Save image metadata - try saveImageMetadata( - image: imageName, - manifestId: manifestId - ) + // Save image metadata + try saveImageMetadata( + image: imageName, + manifestId: manifestId + ) + } // Create temporary directory for new downloads let tempDownloadDir = FileManager.default.temporaryDirectory.appendingPathComponent( @@ -375,12 +380,12 @@ class ImageContainerRegistry: @unchecked Sendable { let cachedLayer = getCachedLayerPath( manifestId: manifestId, digest: layer.digest) - if FileManager.default.fileExists(atPath: cachedLayer.path) { + if !noCache && FileManager.default.fileExists(atPath: cachedLayer.path) { try FileManager.default.copyItem(at: cachedLayer, to: outputURL) await progress.addProgress(Int64(layer.size)) } else { - // Check if this layer is already being downloaded - if isDownloading(layer.digest) { + // Check if this layer is already being downloaded and we're not skipping cache + if !noCache && isDownloading(layer.digest) { try await waitForExistingDownload( layer.digest, cachedLayer: cachedLayer) if FileManager.default.fileExists(atPath: cachedLayer.path) { @@ -391,8 +396,9 @@ class ImageContainerRegistry: @unchecked Sendable { } // Start new download - markDownloadStarted(layer.digest) - defer { markDownloadComplete(layer.digest) } + if !noCache { + markDownloadStarted(layer.digest) + } try await self.downloadLayer( repository: "\(self.organization)/\(imageName)", @@ -404,11 +410,14 @@ class ImageContainerRegistry: @unchecked Sendable { progress: progress ) - // Cache the downloaded layer - if FileManager.default.fileExists(atPath: cachedLayer.path) { - try FileManager.default.removeItem(at: cachedLayer) + // Cache the downloaded layer if not in noCache mode + if !noCache { + if FileManager.default.fileExists(atPath: cachedLayer.path) { + try FileManager.default.removeItem(at: cachedLayer) + } + try FileManager.default.copyItem(at: outputURL, to: cachedLayer) + markDownloadComplete(layer.digest) } - try FileManager.default.copyItem(at: outputURL, to: cachedLayer) } return Int64(layer.size) diff --git a/libs/lume/src/LumeController.swift b/libs/lume/src/LumeController.swift index 91e82287..9350d007 100644 --- a/libs/lume/src/LumeController.swift +++ b/libs/lume/src/LumeController.swift @@ -316,7 +316,7 @@ final class LumeController { } @MainActor - public func pullImage(image: String, name: String?, registry: String, organization: String) + public func pullImage(image: String, name: String?, registry: String, organization: String, noCache: Bool = false) async throws { do { @@ -336,7 +336,7 @@ final class LumeController { let imageContainerRegistry = ImageContainerRegistry( registry: registry, organization: organization) - try await imageContainerRegistry.pull(image: image, name: vmName) + try await imageContainerRegistry.pull(image: image, name: vmName, noCache: noCache) Logger.info("Setting new VM mac address") From 41fb099b8eea19fbb3543cacf3526e9ee6e0bafc Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Mon, 24 Mar 2025 19:08:22 +0000 Subject: [PATCH 2/2] update API endpoint and api docs --- libs/lume/docs/API-Reference.md | 3 ++- libs/lume/src/Server/Handlers.swift | 4 ++-- libs/lume/src/Server/Requests.swift | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libs/lume/docs/API-Reference.md b/libs/lume/docs/API-Reference.md index 569f919a..71447b36 100644 --- a/libs/lume/docs/API-Reference.md +++ b/libs/lume/docs/API-Reference.md @@ -151,7 +151,8 @@ curl --connect-timeout 6000 \ "image": "macos-sequoia-vanilla:latest", "name": "my-vm-name", "registry": "ghcr.io", - "organization": "trycua" + "organization": "trycua", + "noCache": false }' \ http://localhost:3000/lume/pull ``` diff --git a/libs/lume/src/Server/Handlers.swift b/libs/lume/src/Server/Handlers.swift index affecfd4..3fe03565 100644 --- a/libs/lume/src/Server/Handlers.swift +++ b/libs/lume/src/Server/Handlers.swift @@ -225,7 +225,7 @@ extension Server { do { let vmController = LumeController() - try await vmController.pullImage(image: request.image, name: request.name, registry: request.registry, organization: request.organization) + try await vmController.pullImage(image: request.image, name: request.name, registry: request.registry, organization: request.organization, noCache: request.noCache) return HTTPResponse( statusCode: .ok, headers: ["Content-Type": "application/json"], @@ -322,4 +322,4 @@ extension Server { } } } -} \ No newline at end of file +} diff --git a/libs/lume/src/Server/Requests.swift b/libs/lume/src/Server/Requests.swift index e3f86a61..3db114e6 100644 --- a/libs/lume/src/Server/Requests.swift +++ b/libs/lume/src/Server/Requests.swift @@ -37,9 +37,10 @@ struct PullRequest: Codable { let name: String? var registry: String var organization: String + var noCache: Bool enum CodingKeys: String, CodingKey { - case image, name, registry, organization + case image, name, registry, organization, noCache } init(from decoder: Decoder) throws { @@ -48,6 +49,7 @@ struct PullRequest: Codable { name = try container.decodeIfPresent(String.self, forKey: .name) registry = try container.decodeIfPresent(String.self, forKey: .registry) ?? "ghcr.io" organization = try container.decodeIfPresent(String.self, forKey: .organization) ?? "trycua" + noCache = try container.decodeIfPresent(Bool.self, forKey: .noCache) ?? false } } @@ -91,4 +93,4 @@ struct SetVMRequest: Codable { struct CloneRequest: Codable { let name: String let newName: String -} \ No newline at end of file +}