-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[SR-12851] System-wide cache of SwiftPM dependencies #2985
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
[SR-12851] System-wide cache of SwiftPM dependencies #2985
Conversation
7bd4512
to
e2c5fc3
Compare
3f5a8c6
to
40a74e5
Compare
@swift-ci please smoke test |
Great, thank you! I have yet to actually review the code, but did try out a SwiftPM with your diff for a bit myself and it seems to be working nicely. In terms of speedup, I'm seeing a fresh |
The tests are also using the local cache. We might need another change to swift-tools-support to modify I should also look into exclusively caching remote dependencies and excluding local dependencies. |
try self.provider.fetch(repository: handle.repository, to: repositoryPath) | ||
let cache = try await { self.cacheManager?.lookup(repository: handle.repository, completion: $0) } | ||
|
||
try self.provider.fetch(repository: cache.repository, to: repositoryPath) |
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.
I think we should look into whether a straight up copy might be faster than performing a fetch here.
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.
That's a good idea, and should also eliminate the need to reset the remote to point back to the original URL later.
If that were done in a way that used no-copy cloning on file systems that support it (e.g. APFS), that could be really fast since the bare repository typically has few but large files (typically mainly a single pack).
This is great, I have three high-level asks:
|
BTW, the self-hosted tests are still using a vendored copy of TSC. This is something I am working on getting rid off, but we're not quite there, yet. So for now, you would need to update the vendored copy with the lock changes, simply by copying those files over. |
One more thing, it's great that we are using the cache directory as determined by Foundation for storage, but could we also add a symlink from |
ah I see |
Should I open a separate PR for that? |
There is no symlink function in TSC or am I missing something. If not I can open a quick PR for that. |
If an error occurs due to a corrupt cache or if we cannot create the cache directory for some reason, should we try recovering from that by just performing a "normal" fetch without the cache and print a warning about the error? |
Since we are using an approach which keeps the per-project cache, the only place I can imagine where something could go wrong would be right here: try fileSystem.withLock(on: cachedRepositoryPath, type: .exclusive) {
// Fetch the repository into the cache.
try self.provider.fetch(repository: handle.repository, to: cachedRepositoryPath, update: update)
// Copy the repository from the cache into the repository path.
try self.provider.copy(from: cachedRepositoryPath, to: repositoryPath)
} Since our |
@swift-ci please smoke test |
Thanks for the additional changes! I'll review them later today. I don't know the answers to the questions yet, but will address them when I take a look. |
forgot to push my last commit. Test should be fine now. |
Isn't there still a conflict in |
Yes, I think Thanks @tgymnich for your continued iterations on this! To answer a few of the questions:
|
5e40d6a
to
39b3eb2
Compare
@tgymnich this looks great, looking forward to getting it merged soon |
@swift-ci please smoke test |
Looks like there's still an issue with the |
Ah, the issue is a missing dependency in the CMake configuration. Since
|
Done in #3070 |
@swift-ci please smoke tes |
@swift-ci please smoke test |
|
||
@available(*, deprecated) | ||
func fetchingDidFinish(handle: RepositoryManager.RepositoryHandle, fetchDetails: RepositoryManager.FetchDetails?, error: Swift.Error?) { | ||
fetchingDidFinish(handle: handle, error: error) |
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.
Great, thank you, this looks good!
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.
Looks good to me. Thanks!
amazing work @tgymnich 🙇♂️ ❤️ can't wait to get this merged and use it in our day-to-day workflows 🥳 |
You are welcome 😊. Thank you all for your reviews and helpful comments. |
Determining if a git repository exists by checking if |
This comment has been minimized.
This comment has been minimized.
I went ahead and added some integration tests for caching in |
@swift-ci please smoke test |
Thanks for the additional changes, @tgymnich. For the controlling whether local packages are cached, it might be better to use a more general parameter than something specifically intended for unit tests embedded in the general code. If the parameter has a sensible default value, then it could be left to the unit test to look at the environment variable to decide whether to enable the behavior. Just a thought, but that would make the general code a bit cleaner. |
I think caching of local packages makes only sense in the context of unit tests. I see only two ways of enabling this behavior from within |
Right, I agree that it doesn't make sense as an external-facing feature, I was just talking about how the main code paths check for this condition. We can always refine this in a separate PR, though. I'll take another quick look but as far as I am concerned this is ready to merge. Any objections? Thanks for all your work on this! Can't wait to use this! |
👍🏼 let's refine this later. For me this is ready to be merged as well. |
Fantastic. Thanks for your work on this! |
this is fantastic 🥳 ❤️ |
This is great 🎉 Thank you @tgymnich! |
* implemented caching * fixed packages with a path ending in “/” * fetching a repo creates an alias for the fetched repository under a new RepositorySpecifier * added purge-cache and --cache-path options * temporarily fix tests until FileSystem has locks * added documentation and some refactoring * remove unnecessary extension * remove unnecessary import * use file lock provided by FileSystem * added -skip-cache flag * using copy instead of fetch * using repository provider instead of repository manager to fetch the cached repo * added fetchDetail to delegate methods * remove func setURL(remote: String, url: String) throws * fixed unit tests by making RepositoryProvider aware of copy * fix newlines * fix lock * extract function initalizeCacheIfNeeded * update comments * remove duplicate code * remove newlines * re-add old comments and move repositoryPath back down * move isCache to the top * converted FetchDetails into a struct * use FileSystem.swiftPMCacheDirectory * add symlink to cache directory in .swiftpm * add some comments * create .swiftpm directory * don't cache local packages * added default implementations * automatically infer update parameter for fetch * deprecated old delegate methods * add Basics to SourceControl * use a more reliable way to determine if a git repository exists * open repository before fetching * added tests for repository manager * rename cacheLocalPackages
I reworked my approach from PR #2835 to not only operate on
GitRepository
but on any kind of repository from withinRepository Manager
.SR-12851
This PR requires the Lock Improvements in swift-tools-support-core to be merged.