spotify / XCRemoteCache

Other
830 stars 53 forks source link

Support Github actions cache API backend (feature request) #68

Open itsbalamurali opened 2 years ago

itsbalamurali commented 2 years ago

It would be great if the project can add support for the GitHub actions cache API backend, which would make it usable on Github actions without needing an external remote caching server.

Docs: https://github.com/tonistiigi/go-actions-cache/blob/master/api.md

cerupcat commented 1 year ago

Any movement on this or ideas on how we can help get this up and running?

polac24 commented 1 year ago

I looked again on that idea and seems that it would be quite easy to implement it, even the exposed API is a bit weird.

My ideas is that you create a new implementation of the NetworkClient protocol: https://github.com/spotify/XCRemoteCache/blob/b439674378a29d4d2bafd0983f851e0f0f2c630a/Sources/XCRemoteCache/Network/NetworkClient.swift#L37-L43

As a starting point, CachedNetworkClient could be a good example to see how to implement the composite that uses a different underlying API. So you would need to create an adapter.

Here is a sketchy pseudo-code:

 class GitHubActionCacheNetworkClient { 
 init(urlTranslator: GitHubActionCacheURLTranslator, networkClient: NetworkClien){
///
}
     func fileExists(_ url: URL, completion: @escaping (Result<Bool, NetworkClientError>) -> Void)  {
   let translatedUrl = urlTranslator.translate(url: url)
   networkClient.fetch(translatedUrl) {
      // if .success -> call completion(true)
    }
    }
     func fetch(_ url: URL, completion: @escaping (Result<Data, NetworkClientError>) -> Void){
      let translatedUrl = urlTranslator.translate(url: url)
       networkClient.fetch(translatedUrl) { result
           // if success
           networkClient.fetch(result.archiveLocation, completion: completion)
       }
     }
     func download(_ url: URL, to location: URL, completion: @escaping (Result<Void, NetworkClientError>) -> Void) {
      let translatedUrl = urlTranslator.translate(url: url)
       networkClient.fetch(translatedUrl, completion: completion)
       networkClient.fetch(translatedUrl) { result
           // if success
           networkClient.download(result.archiveLocation, to: location, completion: completion)
       }
     }
     func upload(_ file: URL, as url: URL, completion: @escaping (Result<Data, NetworkClientError>) -> Void) {
           let translatedUrl = urlTranslator.translate(url: url)
           // Some kind of a hack - store the request body to a file
          file.write(JSONSerializer....)
           networkClient.upload(file, as:translatedUrl) { result in
              // if success
              // networkClient doesn't have PATCH, so that would need to be added 
              networkClient.patch(result.location) { result2 in
                /// if success
                networkClient.post(result.location, completion: completion)
              }
           }
     }
     /// Creates an empty file at the remote location 
     func create(_ url: URL, completion: @escaping (Result<Void, NetworkClientError>) -> Void)  {
         let translatedUrl = urlTranslator.translate(url: url)
          // Some kind of a hack - store the request body to a file
          file.write(JSONSerializer....)
         networkClient.upload(translatedUrl) { result in
              // if success
              // Warning: networkClient doesn't have PATCH, so that would need to be added 
              networkClient.upload(file) {
                // if success
                   networkClient.create(result.location, completion: completion)
               }
           }
    }

To implement the above, one new method and one modification to NetworkClient would be required:

Notes:

cerupcat commented 1 year ago

Thanks @polac24, that's helpful. I'll look into it a bit.

cerupcat commented 1 year ago

I wasn't able to get anywhere with this. Anyone have bandwidth on getting this working if it's low lift?