Handle the same file name in the fetchBlob method (#258)

With the suggested change, when a file exists, we'll verify whether it
has the same content before skipping it.
This commit is contained in:
Dmitry Kovba
2025-08-15 14:02:22 -04:00
committed by GitHub
parent 54980872d9
commit c3f5816353
@@ -35,6 +35,26 @@ package final class LocalOCILayoutClient: ContentClient {
return c
}
private func calculateFileDigest(at url: URL) throws -> SHA256Digest {
let fileHandle = try FileHandle(forReadingFrom: url)
defer {
try? fileHandle.close()
}
var hasher = SHA256()
let chunkSize = Int(getpagesize()) * 1024
while true {
let chunk = fileHandle.readData(ofLength: chunkSize)
if chunk.isEmpty {
break
}
hasher.update(data: chunk)
}
return hasher.finalize()
}
package func fetch<T: Codable>(name: String, descriptor: Descriptor) async throws -> T {
let c = try await self._fetch(digest: descriptor.digest)
return try c.decode()
@@ -44,7 +64,8 @@ package final class LocalOCILayoutClient: ContentClient {
let c = try await self._fetch(digest: descriptor.digest)
let fileManager = FileManager.default
let filePath = file.absolutePath()
if !fileManager.fileExists(atPath: filePath) {
do {
let src = c.path
try fileManager.copyItem(at: src, to: file)
@@ -53,7 +74,33 @@ package final class LocalOCILayoutClient: ContentClient {
ProgressEvent(event: "add-size", value: fileSize)
])
}
} catch let error as NSError {
guard error.code == NSFileWriteFileExistsError else {
throw error
}
do {
let expectedDigest = try c.digest()
let existingDigest = try calculateFileDigest(at: file)
guard existingDigest.digestString == expectedDigest.digestString else {
throw ContainerizationError(
.internalError,
message:
"File \(filePath) exists but contains different content. Expected digest: \(expectedDigest.digestString), existing digest: \(existingDigest.digestString)"
)
}
if let progress, let fileSize = fileManager.fileSize(atPath: filePath) {
await progress([
ProgressEvent(event: "add-size", value: fileSize)
])
}
} catch {
throw error
}
}
let size = try Int64(c.size())
let digest = try c.digest()
return (size, digest)