Merge pull request #67 from aktech/add-no-cache-option-pull-image

Add `--no-cache` option in lume pull
This commit is contained in:
f-trycua
2025-03-24 13:03:38 -07:00
committed by GitHub
6 changed files with 49 additions and 34 deletions

View File

@@ -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
```

View File

@@ -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)
}
}
}

View File

@@ -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)

View File

@@ -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")

View File

@@ -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 {
}
}
}
}
}

View File

@@ -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
}
}