in Sources/PackageRegistry/RegistryDownloadsManager.swift [133:235]
func downloadAndPopulateCache(
package: PackageIdentity,
version: Version,
packagePath: AbsolutePath,
observabilityScope: ObservabilityScope,
delegateQueue: DispatchQueue,
callbackQueue: DispatchQueue,
completion: @escaping (Result<FetchDetails, Error>) -> Void
) {
if let cachePath = self.cachePath {
do {
let relativePath = try package.downloadPath(version: version)
let cachedPacakgePath = cachePath.appending(relativePath)
try self.initializeCacheIfNeeded(cachePath: cachePath)
try self.fileSystem.withLock(on: cachedPacakgePath, type: .exclusive) {
// download the package into the cache unless already exists
if try self.fileSystem.validPackageDirectory(cachedPacakgePath) {
// extra validation to defend from racy edge cases?
if self.fileSystem.exists(packagePath) {
throw StringError("\(packagePath) already exists unexpectedly")
}
// copy the package from the cache into the package path.
try self.fileSystem.createDirectory(packagePath.parentDirectory, recursive: true)
try self.fileSystem.copy(from: cachedPacakgePath, to: packagePath)
completion(.success(.init(fromCache: true, updatedCache: false)))
} else {
// it is possible that we already created the directory before from failed attempts, so clear leftover data if present.
try? self.fileSystem.removeFileTree(cachedPacakgePath)
// download the package from the registry
self.registryClient.downloadSourceArchive(
package: package,
version: version,
fileSystem: self.fileSystem,
destinationPath: cachedPacakgePath,
checksumAlgorithm: self.checksumAlgorithm,
progressHandler: updateDownloadProgress,
observabilityScope: observabilityScope,
callbackQueue: callbackQueue
) { result in
completion(result.tryMap {
// extra validation to defend from racy edge cases?
if self.fileSystem.exists(packagePath) {
throw StringError("\(packagePath) already exists unexpectedly")
}
// copy the package from the cache into the package path.
try self.fileSystem.createDirectory(packagePath.parentDirectory, recursive: true)
try self.fileSystem.copy(from: cachedPacakgePath, to: packagePath)
return FetchDetails(fromCache: true, updatedCache: true)
})
}
}
}
} catch {
// download without populating the cache in the case of an error.
observabilityScope.emit(warning: "skipping cache due to an error: \(error)")
// it is possible that we already created the directory from failed attempts, so clear leftover data if present.
try? self.fileSystem.removeFileTree(packagePath)
//try self.provider.fetch(repository: handle.repository, to: repositoryPath, progressHandler: updateFetchProgress(progress:))
self.registryClient.downloadSourceArchive(
package: package,
version: version,
fileSystem: self.fileSystem,
destinationPath: packagePath,
checksumAlgorithm: self.checksumAlgorithm,
progressHandler: updateDownloadProgress,
observabilityScope: observabilityScope,
callbackQueue: callbackQueue
) { result in
completion(result.map{ FetchDetails(fromCache: false, updatedCache: false) })
}
}
} else {
// it is possible that we already created the directory from failed attempts, so clear leftover data if present.
try? self.fileSystem.removeFileTree(packagePath)
// download without populating the cache when no `cachePath` is set.
self.registryClient.downloadSourceArchive(
package: package,
version: version,
fileSystem: self.fileSystem,
destinationPath: packagePath,
checksumAlgorithm: self.checksumAlgorithm,
progressHandler: updateDownloadProgress,
observabilityScope: observabilityScope,
callbackQueue: callbackQueue
) { result in
completion(result.map{ FetchDetails(fromCache: false, updatedCache: false) })
}
}
// utility to update progress
func updateDownloadProgress(downloaded: Int64, total: Int64?) -> Void {
delegateQueue.async {
self.delegate?.fetching(
package: package,
version: version,
downloaded: downloaded,
total: total
)
}
}
}