Gitscanner callbacks#1725
Conversation
…leted(), ScanRefRange(), and ScanLeftToRemote()
ttaylorr
left a comment
There was a problem hiding this comment.
Looking good, I just left a few comments that I'd love to 👂 your 💭 's on.
commands/command_checkout.go
Outdated
| // use new gitscanner so mapping has all the scanned pointers before continuing | ||
| mapping := make(map[string][]*lfs.WrappedPointer) | ||
| chgitscanner := lfs.NewGitScanner(nil) | ||
| err = chgitscanner.ScanTree(ref.Sha, func(p *lfs.WrappedPointer, err error) { |
There was a problem hiding this comment.
Do you think this callback should be moved into the line above since (I think) we're leaning towards getting rid of the per-operation callbacks?
| tempgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) { | ||
| if err != nil { | ||
| if multiErr != nil { | ||
| multiErr = fmt.Errorf("%v\n%v", multiErr, err) |
There was a problem hiding this comment.
What do you think about extracting this into a function in the errors package? I'd prefer to use errors.Wrap(), but I think it defaults to "Error" if err is nil.
package errors
func CombineErrors(e1, e2 error) error {
if e1 == nil {
return e2
}
return fmt.Errorf("%v\n%v", e1, e2)
}There's probably a pretty cool opportunity to do something like:
func CombineErrors(car error, cdr ...error) error { ... }but I don't think we need it.
There was a problem hiding this comment.
Coming back to this, if CombineErrors were to go in the errors package, I think it'd be better to just call it errors.Combine.
There was a problem hiding this comment.
Yeah, we could probably expose the inner errors somehow too. I'll experiment with this in another PR.
There was a problem hiding this comment.
I added errors.Combine in my original locking PR so 👍 (although it only concatenated with a line break as you're doing here, nothing smart like storing inner errors)
commands/command_fetch.go
Outdated
| var pointers []*lfs.WrappedPointer | ||
|
|
||
| tempgitscanner := lfs.NewGitScanner(nil) | ||
| err := tempgitscanner.ScanPreviousVersions(ref, since, func(p *lfs.WrappedPointer, err error) { |
There was a problem hiding this comment.
Same comment here about inlining the callback to the above line (and then shortening this if statement to not leak the err variable).
| return false, err | ||
| for _, oid := range corruptOids { | ||
| badFile := filepath.Join(badDir, oid) | ||
| if err := os.Rename(lfs.LocalMediaPathReadOnly(oid), badFile); err != nil { |
There was a problem hiding this comment.
Huh, I didn't know you could rename like this!
There was a problem hiding this comment.
How else do you rename?
There was a problem hiding this comment.
Ha, I definitely meant to type "move" in my original comment. I thought there was a os.MoveFile function, but I was mistaken 😅
|
|
||
| if ok { | ||
| Print("Git LFS fsck OK") | ||
| recalculatedOid := hex.EncodeToString(oidHash.Sum(nil)) |
There was a problem hiding this comment.
Oh man, this is so much better than
fmt.Sprintf("%x", oidHash.Sum(nil))| pointers = append(pointers, p) | ||
| } | ||
|
|
||
| if err := g.ScanLeftToRemote(ref, cb); err != nil { |
There was a problem hiding this comment.
Are we OK to do this if multiErr != nil?
There was a problem hiding this comment.
Yes. If this returns an error, the command that ScanLeftToRemote() attempts to spin up errored, so the callback potentially sets multiErr is never called.
There was a problem hiding this comment.
Awesome, thanks for the explanation 👍
lfs/gitscanner.go
Outdated
| return cb, nil | ||
| } | ||
|
|
||
| return nil, errors.New("No callback given") |
There was a problem hiding this comment.
We talked about this in 🍖 -space, but this would be a good candidate to extract to a sentinel value if you want to keep the firstGitScannerCallback business 👍
lfs/gitscanner.go
Outdated
|
|
||
| // CallbackMissing returns a boolean indicating whether the error is reporting | ||
| // that a GitScanner is missing a required GitScannerCallback. | ||
| func CallbackMissing(err error) bool { |
There was a problem hiding this comment.
I dig IsCallbackMissing instead of just CallbackMissing.
There was a problem hiding this comment.
It was a 50/50 toss-up for me, but your recommendation made it a 51/49 split :)
|
It feels a little odd to me to supply the callback in |
|
Part of the point in the git scanner redesign is spawning the That said, I do think passing the callback on the constructor is pretty strange from an API perspective. There's still time before the API is finalized a |
This changes the
gitscannerAPI to use callbacks, instead of returning aPointerChannelWrapper. See the fsck command for an ideal usage of it:You can now pass a callback to
NewGitScanner()for all the.Scan*()funcs, or pass a callback to individual functions if you want those pointers to be handled differently.Unfortunately, this introduces some ugly code in the core push/pull/checkout related commands. A lot of code still expects to receive a
[]*lfs.WrappedPointerafter the scan has completed. This cleanup will have to happen in future PRs. The main blockers are the progress meter and transfer queues need to accept a stream of pointers.My hunch is that the transfer queue is all ready setup for this, but our use of it prefers receiving a
[]*lfs.WrappedPointer. However, the progress meter definitely expects to receive the total number and size of the pointers up front. Since this process is becoming async, updating the progress meter stuff is my next target.