-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add multiple cache storages feature #156
Merged
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
6d35c14
Add multiple cache storages feature
ikesyo 5953d6c
Pass storages to `CacheSystem.cacheFrameworks`
ikesyo a24f7c9
Refactor to remove isProducingCacheEnabled
ikesyo d7bd9ff
Refactor to remove isConsumingCacheEnabled
ikesyo e7b20c5
Improve logging
ikesyo 0f1c98a
debugging
ikesyo 8750153
Add test case for storages cache mode
ikesyo 8c7c16e
Update `build-pipeline.md` for `.storages` cache mode
ikesyo f6cbef1
debugging
ikesyo 413bb12
Add StorageConfig struct
ikesyo c3d9efa
Address naming convention issues
ikesyo 25f5fcb
Replace `case storage` with static func
ikesyo 82ec106
Replace `case disabled` with static func
ikesyo 086970f
Merge branch 'main' into multiple-cache-storages
ikesyo 7434f6b
Rename to LocalDiskCacheStorage
ikesyo a451614
Introduce ProjectCacheStorage
ikesyo c22ed6f
Replace `case project` with static func (using ProjectCacheStorage)
ikesyo 0006fbb
Introduce CachePolicy and replace CacheMode with an array of CachePolicy
ikesyo 4d8abab
Update documentation
ikesyo 76ae5af
Avoid direct usages of `type(of: storage)`
ikesyo ff1d483
Make LocalDiskCacheStorage and ProjectCacheStorage internal
ikesyo 4712f89
Use some over any for arguments
ikesyo 3d333e6
[CI] macos-15 image is required to use Xcode 16
ikesyo 0c81a2e
Add info log when a cache is not found when restoring as well as `.su…
ikesyo d71053b
Fix format
ikesyo ed52625
Use some over any for arguments
ikesyo 4de26b5
Add inline comment
ikesyo bced0e2
Reduce duplication
ikesyo dfe443c
Revert "Reduce duplication"
ikesyo acdd251
Reduce duplication
ikesyo afafa8d
Revert "debugging"
ikesyo 2720cde
Add `[Runner.Options.CachePolicy].disabled`
ikesyo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -108,7 +108,6 @@ struct CacheSystem: Sendable { | |
static let defaultParalellNumber = 8 | ||
private let pinsStore: PinsStore | ||
private let outputDirectory: URL | ||
private let storage: (any CacheStorage)? | ||
private let fileSystem: any FileSystem | ||
|
||
struct CacheTarget: Hashable, Sendable { | ||
|
@@ -139,18 +138,23 @@ struct CacheSystem: Sendable { | |
init( | ||
pinsStore: PinsStore, | ||
outputDirectory: URL, | ||
storage: (any CacheStorage)?, | ||
fileSystem: any FileSystem = localFileSystem | ||
) { | ||
self.pinsStore = pinsStore | ||
self.outputDirectory = outputDirectory | ||
self.storage = storage | ||
self.fileSystem = fileSystem | ||
} | ||
|
||
func cacheFrameworks(_ targets: Set<CacheTarget>) async { | ||
let chunked = targets.chunks(ofCount: storage?.parallelNumber ?? CacheSystem.defaultParalellNumber) | ||
func cacheFrameworks(_ targets: Set<CacheTarget>, to storages: [any CacheStorage]) async { | ||
for storage in storages { | ||
await cacheFrameworks(targets, to: storage) | ||
} | ||
} | ||
|
||
private func cacheFrameworks(_ targets: Set<CacheTarget>, to storage: some CacheStorage) async { | ||
let chunked = targets.chunks(ofCount: storage.parallelNumber ?? CacheSystem.defaultParalellNumber) | ||
|
||
let storageName = storage.displayName | ||
for chunk in chunked { | ||
await withTaskGroup(of: Void.self) { group in | ||
for target in chunk { | ||
|
@@ -159,10 +163,10 @@ struct CacheSystem: Sendable { | |
let frameworkPath = outputDirectory.appendingPathComponent(frameworkName) | ||
do { | ||
logger.info( | ||
"🚀 Cache \(frameworkName) to cache storage", | ||
"🚀 Cache \(frameworkName) to cache storage: \(storageName)", | ||
metadata: .color(.green) | ||
) | ||
try await cacheFramework(target, at: frameworkPath) | ||
try await cacheFramework(target, at: frameworkPath, to: storage) | ||
} catch { | ||
logger.warning("⚠️ Can't create caches for \(frameworkPath.path)") | ||
} | ||
|
@@ -173,10 +177,10 @@ struct CacheSystem: Sendable { | |
} | ||
} | ||
|
||
private func cacheFramework(_ target: CacheTarget, at frameworkPath: URL) async throws { | ||
private func cacheFramework(_ target: CacheTarget, at frameworkPath: URL, to storage: any CacheStorage) async throws { | ||
let cacheKey = try await calculateCacheKey(of: target) | ||
|
||
try await storage?.cacheFramework(frameworkPath, for: cacheKey) | ||
try await storage.cacheFramework(frameworkPath, for: cacheKey) | ||
} | ||
|
||
func generateVersionFile(for target: CacheTarget) async throws { | ||
|
@@ -210,8 +214,8 @@ struct CacheSystem: Sendable { | |
case failed(LocalizedError?) | ||
case noCache | ||
} | ||
func restoreCacheIfPossible(target: CacheTarget) async -> RestoreResult { | ||
guard let storage = storage else { return .noCache } | ||
|
||
func restoreCacheIfPossible(target: CacheTarget, storage: some CacheStorage) async -> RestoreResult { | ||
do { | ||
let cacheKey = try await calculateCacheKey(of: target) | ||
if try await storage.existsValidCache(for: cacheKey) { | ||
|
@@ -225,12 +229,6 @@ struct CacheSystem: Sendable { | |
} | ||
} | ||
|
||
private func fetchArtifacts(target: CacheTarget, to destination: URL) async throws { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was unused. |
||
guard let storage = storage else { return } | ||
let cacheKey = try await calculateCacheKey(of: target) | ||
try await storage.fetchArtifacts(for: cacheKey, to: destination) | ||
} | ||
|
||
func calculateCacheKey(of target: CacheTarget) async throws -> SwiftPMCacheKey { | ||
let targetName = target.buildProduct.target.name | ||
let pin = try retrievePin(package: target.buildProduct.package) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,37 +3,33 @@ import ScipioStorage | |
import PackageGraph | ||
import TSCBasic | ||
|
||
public struct LocalCacheStorage: CacheStorage { | ||
struct LocalDiskCacheStorage: CacheStorage { | ||
private let fileSystem: any FileSystem | ||
|
||
public var parallelNumber: Int? { nil } | ||
var parallelNumber: Int? { nil } | ||
|
||
enum Error: Swift.Error { | ||
case cacheDirectoryIsNotFound | ||
} | ||
|
||
public enum CacheDirectory: Sendable { | ||
case system | ||
case custom(URL) | ||
} | ||
|
||
private let cacheDirectroy: CacheDirectory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 Directroy |
||
private let baseURL: URL? | ||
|
||
public init(cacheDirectory: CacheDirectory = .system, fileSystem: FileSystem = localFileSystem) { | ||
self.cacheDirectroy = cacheDirectory | ||
/// - Parameters: | ||
/// - baseURL: The base url for the local disk cache. When it is nil, the system cache directory (`~/Library/Caches`) will be used. | ||
init(baseURL: URL?, fileSystem: FileSystem = localFileSystem) { | ||
self.baseURL = baseURL | ||
self.fileSystem = fileSystem | ||
} | ||
|
||
private func buildBaseDirectoryPath() throws -> URL { | ||
let cacheDir: URL | ||
switch cacheDirectroy { | ||
case .system: | ||
if let baseURL { | ||
cacheDir = baseURL | ||
} else { | ||
guard let systemCacheDir = fileSystem.cachesDirectory else { | ||
throw Error.cacheDirectoryIsNotFound | ||
} | ||
cacheDir = systemCacheDir.asURL | ||
case .custom(let customPath): | ||
cacheDir = customPath | ||
} | ||
return cacheDir.appendingPathComponent("Scipio") | ||
} | ||
|
@@ -51,7 +47,7 @@ public struct LocalCacheStorage: CacheStorage { | |
.appendingPathComponent(xcFrameworkFileName(for: cacheKey)) | ||
} | ||
|
||
public func existsValidCache(for cacheKey: some CacheKey) async -> Bool { | ||
func existsValidCache(for cacheKey: some CacheKey) async -> Bool { | ||
do { | ||
let xcFrameworkPath = try cacheFrameworkPath(for: cacheKey) | ||
return fileSystem.exists(xcFrameworkPath.absolutePath) | ||
|
@@ -60,7 +56,7 @@ public struct LocalCacheStorage: CacheStorage { | |
} | ||
} | ||
|
||
public func cacheFramework(_ frameworkPath: URL, for cacheKey: some CacheKey) async { | ||
func cacheFramework(_ frameworkPath: URL, for cacheKey: some CacheKey) async { | ||
do { | ||
let destination = try cacheFrameworkPath(for: cacheKey) | ||
let directoryPath = destination.deletingLastPathComponent() | ||
|
@@ -72,7 +68,7 @@ public struct LocalCacheStorage: CacheStorage { | |
} | ||
} | ||
|
||
public func fetchArtifacts(for cacheKey: some CacheKey, to destinationDir: URL) async throws { | ||
func fetchArtifacts(for cacheKey: some CacheKey, to destinationDir: URL) async throws { | ||
let source = try cacheFrameworkPath(for: cacheKey) | ||
let destination = destinationDir.appendingPathComponent(xcFrameworkFileName(for: cacheKey)) | ||
try fileSystem.copy(from: source.absolutePath, to: destination.absolutePath) | ||
|
10 changes: 10 additions & 0 deletions
10
Sources/ScipioKit/Producer/Cache/ProjectCacheStorage.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import Foundation | ||
import ScipioStorage | ||
|
||
/// The pseudo cache storage for "project cache policy", which treats built frameworks under the project's output directory (e.g. `XCFrameworks`) | ||
/// as valid caches but does not saving / restoring anything. | ||
struct ProjectCacheStorage: CacheStorage { | ||
func existsValidCache(for cacheKey: some ScipioStorage.CacheKey) async throws -> Bool { false } | ||
func fetchArtifacts(for cacheKey: some ScipioStorage.CacheKey, to destinationDir: URL) async throws {} | ||
func cacheFramework(_ frameworkPath: URL, for cacheKey: some ScipioStorage.CacheKey) async throws {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import ScipioStorage | ||
|
||
extension CacheStorage { | ||
/// The display name of the cache storage used for logging purpose | ||
var displayName: String { | ||
// TODO: Define the property as CacheStorage's requirement in scipio-cache-storage | ||
"\(type(of: self))" | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to the introduction of cache policies, storages may be different on when saving caches and when restoring caches. So removed the property and passes by arguments instead.