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
Refactor API client #779
Comments
I've previously (#378) had a go at abstracting the APIs to add SSH as usable for a complete API round-trip. That needs completely revisiting now but were you happy with the general principles? If so I could take this on at the same time as revisiting SSH. |
I think your interface is too big. Of course, this was before the batch API was finalized and all that. But I'd like to see something like: type ApiContext interface {
// Get the endpoint this context was constructed from
Endpoint() Endpoint
// Close the context & any resources it's using
Close() error
Upload(objects []*ObjectResource) ([]*ObjectResource, *WrappedError)
Download(objects []*ObjectResource) ([]*ObjectResource, *WrappedError)
} I don't know if we'll need |
Yeah, most of that is because of the previous need to support individual objects as well as batches. Whether we need That would be fine, but I think there needs to be the potential to abstract the actual upload and download as well, so they don't necessarily have to be across HTTP (but can be - so you can have an SSH API that gives back HTTP upload/download links or ones which use the SSH pipe). That suggests an interface like this: type ApiContext interface {
// Get the endpoint this context was constructed from
Endpoint() Endpoint
// Close the context & any resources it's using
Close() error
// Perform API request for upload/download & return resources / errors related to that batch
RequestUpload(pointers []*Pointer) ([]*ObjectResource, *WrappedError)
RequestDownload(pointers []*Pointer) ([]*ObjectResource, *WrappedError)
// Perform the actual upload/download - async completion
Upload(objects []*ObjectResource, c chan *TransferResult) (error)
Download(objects []*ObjectResource, c chan *TransferResult) (error)
} |
Scratch that, I think we need 2 separate interfaces, one for the API and one for the content operations (actual upload/downloads). A package (say core has one for HTTP, one for SSH initially) can provide both implementations if they want. Also it should be perfectly acceptable to call the API over SSH and download over HTTP or vice versa. I'd still like to call the API functions I think in both cases the implementation should be derived from the protocol of the link - for the API interface that's from the LFS URL, and for the content provider that's from the resource URLs. So the SSH API could return HTTP links for example, and custom protocols could be used to extend to other systems if required later (just like in browsers). |
Do we really need the second interface? All the commands should care about is whether their objects were uploaded or downloaded. It shouldn't matter to them if that requires a single batch API request and individual content requests, multiple (legacy) API and content requests, or a single SSH connection. I suppose one benefit of this is that an SSH API adapter could take advantage of the existing batch transfer code for HTTP downloads. Is that what you're thinking? |
2 reasons - firstly there are cases where you need to know if an object is on the remote, without actually downloading it, for example:
Secondly, the API and content transfer are orthogonal sets of operations. Just because you're using SSH to access the API doesn't mean you have to use it for the content; you could be using SSH to authenticate with your Git repo but S3 for content storage. Or HTTP API and SCP to some custom content host. There's no reason to make an implementation of the interface implement the NxM matrix of all combinations of API serving and upload/download route. Separating the API & content transfer interfaces achieves both with one approach. |
This seems more like a case for
The HTTP and SSH API objects can share code internally. but I don't think any of this should be exposed to the I do like the idea of having a separate API context object for each major Git remote type: HTTPS, SSH, maybe even |
Yep, which is why I think they're a separate interface. In practice the server side of the API may be checking the content store unless it caches info but the client only talks to the API.
Sorry if I wasn't clear on that, but yeah I had no intention of the split being visible to the code in the What I meant was that the abstraction of the protocols should be separate between the LFS API and the content transfers. The choice of implementation would always need to be fronted anyway by utilities which picked the correct path to use, but internally those 2 interfaces, one for the LFS API and one for the content transfers, would be a bit more flexible. Without exposing any of that to the regular commands.
Yeah, multi-stage approach makes sense, simply moving existing code mostly as-is first then refactoring as a second stage. I think we were talking about 2 different things, you about the facade that In that case, I think the initial step is a |
@sinbad: Sounds good. I didn't think about the client being a concrete object, and only using LFS API/Content API interfaces internally.
👍 |
See: #1839. |
There's a lot of cruft in the
lfs
package for dealing with both LFS APIs. This can make it difficult to follow the code path, and really difficult to add support for alternate protocols. This is what I'd like to see:DownloadObjects()
andUploadObjects()
.github.com/github/git-lfs/client
.git lfs fetch
,git lfs pull
, andgit lfs smudge
.The text was updated successfully, but these errors were encountered: