spotify / XCRemoteCache

Other
830 stars 53 forks source link

Question: Share pod cache between project xcodeproj #69

Closed dwirandyh closed 2 years ago

dwirandyh commented 2 years ago

Hi there I have tried xcremotecache, and the result is awesome so i would like to know that is it possible to share cahce between xcodeproj in same repository with modular project structure?

For example i have movie project in the movie project structure

- Movie.xcodeproj
- Movie.xcworkspace
- Podfile
- Pods
   - Alamofire (4.0.0) 
- Module/User
   - User.xcodeproj
   - User.xcworkspace
   - Podfile
   - Pods
      - Alamofire (4.0.0) 
- Module/TVShow
   - TVShow.xcodeproj 
   - TVShow.xcworkspace
   - Podfile
   - Pods
      - Alamofire (4.0.0) 

Is it possible to share cache that has generated from Movie.xcodeproj/.xcworkspace (Scheme: Movie) to be used by User.xcodeproj/.xcworkspace (Scheme: User) especially for third pary library in pod directory e.g Alamofire that has same version?


What i have tried:

Thank you in advance

polac24 commented 2 years ago

This is an interesting question. It will work: the same Alamofire artifact (zip) is shared between Movie, User and TVShow. Note that a producer does not reuse previously generated products thus building Alamofire will happen there 3 times.

I tried the scenario you provided and I get [RC] Cached build for Alamofire target in the User project. Here are my Podfiles:

XCRemoteCacheDemoCocoaPods/Podfile:

plugin 'cocoapods-xcremotecache'

xcremotecache({
  'cache_addresses' => ['http://localhost:8080/cache/pods'], 
  'primary_repo' => '.',
  'mode' => 'producer',
  'final_target' => 'XCRemoteCacheDemoCocoaPods',
  'exclude_targets' => ['Firebase', 'FirebaseAnalytics', 'GoogleAppMeasurement'],
})

target 'XCRemoteCacheDemoCocoaPods' do
  use_frameworks!

  pod 'Firebase/Analytics'
  pod 'ReactiveSwift'
  pod 'Alamofire'
end

XCRemoteCacheDemoCocoaPods/User/Podfile:

plugin 'cocoapods-xcremotecache'

xcremotecache({
  'cache_addresses' => ['http://localhost:8080/cache/pods'], 
  'primary_repo' => '.',
  'mode' => 'consumer',
  'exclude_targets' => ['Firebase', 'FirebaseAnalytics', 'GoogleAppMeasurement'],
})

target 'User' do
  use_frameworks!

  pod 'Alamofire'
end
dwirandyh commented 2 years ago

Hi @polac24 I have tried it in my sample project here and it works, https://github.com/dwirandyh/xcremotecache-modular-example User project use cached that is genereted from MovieApp target. but when i try to implement in my real project it doesn't work the logs always showing [RC] Disabled remote cache for TargetName (e.g Alamofire). When the cache was created for the first time, I immediately tried to use it in my consumer project inside 1 repository

May i know how xcremotecache knows whether the generated cache can be used or not?

polac24 commented 2 years ago

XCRemoteCache's producer generates a json file that lists all files to create a hash (md5 for now). More details here. If you want to inspect which files are added to a list, check producer's DerivedData, e.g. ../DerivedData/XCRemoteCacheDemoCocoaPods/Build/Intermediates.noindex/Pods.build/Debug-iphonesimulator/Alamofire.build/xccache/produced/{somehash}.json Files listed in dependencies are hashed using md5 and if the final hash is equal rawFingerprint, most likely it will be reused (unless the context is different, e.g. configuration).

I would suggest checking if none of files in dependencies are absolute - all of them should start with $(...). Also, compare if both Alamofire projects's json (producer for Movie and TVShow) are identical, especially their fileKey.

Here you can find source files for the fingerprinting logic: https://github.com/spotify/XCRemoteCache/tree/master/Sources/XCRemoteCache/Fingerprint

dwirandyh commented 2 years ago

HI @polac24 after i try to inspect .json file that stored in remove cache server, i found that for third party pods target dependencies start with $(...)

{
  "inputs": [],
  "generationCommit": "13a0bdaf485197e36f6d71a01160ca80ff0e8a24",
  "pluginsKeys": {},
  "targetName": "Alamofire",
  "platform": "iphonesimulator",
  "configuration": "Debug",
  "rawFingerprint": "ebdff9d94e509e5d57a2cfe9c4f902b8",
  "fileKey": "782c29195e310a8ada7bf97d6c350580",
  "dependencies": [
    "$(SRCROOT)/Alamofire/Source/AFError.swift",
    "$(SRCROOT)/Alamofire/Source/Alamofire.swift",
    "$(SRCROOT)/Alamofire/Source/AlamofireExtended.swift",
    "$(SRCROOT)/Alamofire/Source/AuthenticationInterceptor.swift",
    "$(SRCROOT)/Alamofire/Source/CachedResponseHandler.swift",
    "$(SRCROOT)/Alamofire/Source/Combine.swift",
    "$(SRCROOT)/Alamofire/Source/Concurrency.swift",
    "$(SRCROOT)/Alamofire/Source/DispatchQueue+Alamofire.swift",
    "$(SRCROOT)/Alamofire/Source/EventMonitor.swift",
    "$(SRCROOT)/Alamofire/Source/HTTPHeaders.swift",
    "$(SRCROOT)/Alamofire/Source/HTTPMethod.swift",
    "$(SRCROOT)/Alamofire/Source/MultipartFormData.swift",
    "$(SRCROOT)/Alamofire/Source/MultipartUpload.swift",
    "$(SRCROOT)/Alamofire/Source/NetworkReachabilityManager.swift",
    "$(SRCROOT)/Alamofire/Source/Notifications.swift",
    "$(SRCROOT)/Alamofire/Source/OperationQueue+Alamofire.swift",
    "$(SRCROOT)/Alamofire/Source/ParameterEncoder.swift",
    "$(SRCROOT)/Alamofire/Source/ParameterEncoding.swift",
    "$(SRCROOT)/Alamofire/Source/Protected.swift",
    "$(SRCROOT)/Alamofire/Source/RedirectHandler.swift",
    "$(SRCROOT)/Alamofire/Source/Request.swift",
    "$(SRCROOT)/Alamofire/Source/RequestInterceptor.swift",
    "$(SRCROOT)/Alamofire/Source/RequestTaskMap.swift",
    "$(SRCROOT)/Alamofire/Source/Response.swift",
    "$(SRCROOT)/Alamofire/Source/ResponseSerialization.swift",
    "$(SRCROOT)/Alamofire/Source/Result+Alamofire.swift",
    "$(SRCROOT)/Alamofire/Source/RetryPolicy.swift",
    "$(SRCROOT)/Alamofire/Source/ServerTrustEvaluation.swift",
    "$(SRCROOT)/Alamofire/Source/Session.swift",
    "$(SRCROOT)/Alamofire/Source/SessionDelegate.swift",
    "$(SRCROOT)/Alamofire/Source/StringEncoding+Alamofire.swift",
    "$(SRCROOT)/Alamofire/Source/URLConvertible+URLRequestConvertible.swift",
    "$(SRCROOT)/Alamofire/Source/URLEncodedFormEncoder.swift",
    "$(SRCROOT)/Alamofire/Source/URLRequest+Alamofire.swift",
    "$(SRCROOT)/Alamofire/Source/URLSessionConfiguration+Alamofire.swift",
    "$(SRCROOT)/Alamofire/Source/Validation.swift",
    "$(SRCROOT)/Target Support Files/Alamofire/Alamofire-dummy.m",
    "$(SRCROOT)/Target Support Files/Alamofire/Alamofire-prefix.pch",
    "$(BUILD_DIR)/Debug-iphonesimulator/Alamofire/Alamofire.framework/Headers/Alamofire-umbrella.h"
  ],
  "xcode": "13A1030d"
}

But for development pod or podspec (e.g TVShow, User, etc) there are some dependency that use absolute path

{
  "inputs": [],
  "generationCommit": "13a0bdaf485197e36f6d71a01160ca80ff0e8a24",
  "pluginsKeys": {},
  "targetName": "User",
  "platform": "iphonesimulator",
  "configuration": "Debug",
  "rawFingerprint": "7332d6dffff9edcf1ab959f5f1e6ad27",
  "fileKey": "3c111562299c524b00881c4fec3f4df3",
  "dependencies": [
    "$(BUILD_DIR)/Debug-iphonesimulator/Alamofire/Alamofire.framework/Headers/Alamofire-Swift.h",
    "$(BUILD_DIR)/Debug-iphonesimulator/Alamofire/Alamofire.framework/Headers/Alamofire-umbrella.h",
    "$(BUILD_DIR)/Debug-iphonesimulator/Alamofire/Alamofire.framework/Modules/Alamofire.swiftmodule/x86_64-apple-ios-simulator.swiftmodule.md5",
    "$(BUILD_DIR)/Debug-iphonesimulator/Alamofire/Alamofire.framework/Modules/module.modulemap",
    "/Users/dwi.herdinanto/Research/xcremotecache/xcremotecache-modular-example/MovieApp/Modules/User/User/Dummy.swift",
    "$(BUILD_DIR)/Debug-iphonesimulator/User/User.framework/Headers/SettingsViewController.h",
    "/Users/dwi.herdinanto/Research/xcremotecache/xcremotecache-modular-example/MovieApp/Modules/User/User/SettingsViewController.m",
    "/Users/dwi.herdinanto/Research/xcremotecache/xcremotecache-modular-example/MovieApp/Modules/User/User/UserViewController.swift",
    "$(SRCROOT)/Target Support Files/User/User-dummy.m",
    "$(BUILD_DIR)/Debug-iphonesimulator/User/User.framework/Headers/User-umbrella.h"
  ],
  "xcode": "13A1030d"
}

I think something is wrong here

polac24 commented 2 years ago

Thanks for the extensive logs @dwirandyh. I think #87 fixes that. As this is still in an experimental phase, an extra config in Podfile is required for now.

dwirandyh commented 2 years ago

Great @polac24 i have try it, and it works and all dependencies start with $(...).

But i think i found a another bug, please kindly to check my issue here: #89

vasvf commented 2 years ago

I fixed the same issue with 'out_of_band_mappings' => {"MAIN_REPO_MODULES" => "#{Dir.pwd}/Modules"} in Podfile, without any additional code changes.

polac24 commented 2 years ago

Fixed in #87