cocoapods-binary-cache icon indicating copy to clipboard operation
cocoapods-binary-cache copied to clipboard

[Idea] Centralized Cache

Open savage7 opened this issue 3 years ago • 1 comments

I really love your plugin and its a massive time saver :blush:

I just want to share my basic idea which would lead to a massive change in the architecture and workflow of the plugin. On the other hand I could bring use a centralized cache :)

I would be nice I you could share your thoughts on this.

Workaround for Realm

I had some trouble with Realm (https://github.com/grab/cocoapods-binary-cache/issues/57). While I was not able to resolve these issues I reworked them by creating a "binary pod" of Realm.

I prebuilt it myself (which is pretty easy but a manual task...) and put it on a interal git repo, than I created a Podspec which uses the internal podspec repo together with the offical cdn repo. By this the official Realm/RealmSwift Pod is overruled with my internal binary version. The clou: I also use RxRealm, which depends on RealmSwift. By overriding the dependency with a binary version, the pod resolution still works. This "workaround" made me thinking, if we could create a more global, not project specific binary cache. The global cache could work more like a maven repository.

A few preconditions for this, for making the cache relatively stable:

  • host xcframeworks
  • build all archs
  • build with library evolution support

I've built my binary repo with this basic scheme, mirroring the podspec repo: PodName/Version/PodName.xcframework.zip

i.e: Realm/10.5.1/Realm.xcframeworks.zip RealmSwift/10.5.1/RealmSwift.xcframework.zip

I created Podspecs like these:

Pod::Spec.new do |s|
  s.name         = 'Realm'
  s.version      = '10.5.1'
 ....
  s.platform = :ios, '11.0'
  s.source = { git: 'binary_pods.git' }
  s.ios.vendored_frameworks = "#{s.name}/#{s.version}/#{s.name}.xcframework"
end

In the Podfile there are two ways to use this: pod 'Realm', '10.5.1', source: 'cocoapods_binary_specs.git' or

source: 'cocoapods_binary_specs.git'
pod 'Realm', '10.5.1'

However this will trigger a warning, that i.e. the Realm pod is found multiple sources. This can be silenced with by setting warn_for_multiple_pod_sources.

This is just a basic example, but it shows how we could basicly overwrite any source code dependency with a binary verison.

Basic proposal

Currently we have a binary cache per project, which cannot be versioned. Cached artifacts, cannot be shared. We have nothing like a "maven repository". I want to keep the changes to the podfile minimal by only adding a new source (no explicit pod_binary).

pod binary prebuild --push behavior: option 1, prebuild all pods:

  • builds all dependencies as xcframeworks for a specific Podfile
  • searches all pods and find dependencies
  • tries to build every pod

option 2, prebuild a single pod: pod binary prebuild --push Resolver:1.4.0 find a pod and build that exact version. also build all dependencies of the pod.

  • binaries are added versioned (like Realm/10.5.1/Realm.xcframeworks.zip) to the central cache
  • create binary Podspecs and push them to cocoapods_binary_specs.git
  • add transitive dependencies to the generated binary Podspecs

Usage

  • Podfile has an additional source i.e. source: 'cocoapods_binary_specs.git'
  • now "binary_pod" function would be used explicitly
  • cocoapods_binary_pods would not integrate the xcframework itself, since the specs from cocoapods_binary_specs are used

savage7 avatar Jan 31 '21 10:01 savage7

Hi @savage7, You brought up a very interesting idea. And it is actually similar to one of our items for improvements in the long term:

  • The cache frameworks are hosted somewhere else, in a store (like CDN). This store can be shared across projects depending on your needs.
  • The cache_repo git repo only contains metadata and files other than prebuilt frameworks, just enough for cache validation. This helps reduce the time to fetch cache because only cache-hit frameworks should be fetched.

So, I'd imagine it shall develop into that form in the long run.

However, I think we need to emphasize that the prebuilt frameworks are still specific to the project because those frameworks are built with a specific configuration (Debug/Release), project build settings, and very much affected by the custom build settings (if set) by Podfile pre_install/post_install hooks. For example, if the pre_install/post_install hook in Podfile sets a framework as static like this:

pre_install do |installer|
  installer.pods_project.targets.each do |target|
    make_static(target)
  end
end

Then the prebuilt framework should be a static framework, and hence, cannot be used in other projects that require it to be dynamic.

Therefore, the idea of a centralized cache store could be adopted but please keep in mind the constraint above for the global cache setup.

trinhngocthuyen avatar Feb 03 '21 04:02 trinhngocthuyen