-
Notifications
You must be signed in to change notification settings - Fork 2k
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
scanner: refactor RevListsShas into type #1595
Conversation
// MatchesNameAndType returns whether or not the receiving *Ref "r" has the same | ||
// name and type as the "other" *Ref. Nil *Refs are invalid values and thus do | ||
// not possess equality. | ||
func (r *Ref) MatchesNameAndType(other *Ref) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any (valid) situation where Name & Type are equal but Sha is not? Since we never modify refs I don't think so. In which case the struct equality operator is enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for bringing this up. I can't think of any legal situations where this would/could happen off-hand, so I simplified the behavior in cf8fac1.
return rev, ok | ||
} | ||
|
||
func (c *RevCache) Cache(sha, name string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this a little confusing since sha->name would logically be a multi-map (shas can have multiple refs pointing at them).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// | ||
// If there was an error encountered before beginning to scan, it will be | ||
// returned by itself, with two nil channels. | ||
func (r *RevListScanner) Scan(left, right string) (<-chan string, <-chan error, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StringChannelWrapper has a more convenient interface for handling strings and errors rather than separate channels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Realise the scanner methods predated this but might be worth taking advantage of)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was debating whether or not to use the *XChannelWrappertypes when I was refactoring this. IMHO, I think passing the channels around directly and using the
tools.CollectErrsFromChan` method is more lightweight than a new type, so I am going to leave this as-is for now.
This will become less of a sore spot a few more PRs down the line.
@sinbad thanks for the review! I pushed some more changes out to address your comments 👍 |
Moving things to a new package gives us another opportunity to examine the interface. The Also, I don't think a revlistScanner := newRevListScanner("origin", ScanRefsMode)
revlistScanner.SkipDeletedBlobs = true
revlistScanner.Scan(left, right) If |
Actually, ignore the last part. I think we still need |
I don't think that these types need to be exported. To keep these PRs small, I think it makes sense to export the same functions that exist in I did, however, make the |
Can you provide some example of how this will work, and why a type is needed? The type shares all of the same properties of |
I thought about this some more and had another question.
Sure. When I started this refactor, the presence of the My first inclination was to extract a 2-3 smaller, static functions, and call those, but I hit another smell of passing that Since there is code from the I think having three types (one that scans refs, one that does the batch check, and one that converts blobs into LFS pointers) is a good idea in that each is isolated in their concern, and doesn't have access to data that they don't need. This makes the types easily testable, and compose-able, which I think is a solid step forward. |
I see
One upside, is if the three types end up with similar method names, they won't need prefixes to keep them apart: revListScannerScan()
catFileBatchScan()
(*revListScanner) Scan()
(*catFileBatch) Scan() If you really want to add the types, go for it. I was just asking a question. Some times I wish I would've gotten more questions about types I've written. If you do keep this, I still think
If you do that, then you'll need a public Scan function with 3 positional args: scanner.Scan(scanner.ScanAllMode, "origin", false) Positional args, especially for optional ones like |
Thanks again for this feedback 👍 . I didn't do a great job of articulating what I'm going for in this series of PRs, which I think can make it difficult to look at each by itself. I did my best at responding to some of your questions below. My inclination is to merge this PR and introduce the type after changing the name of
I may be misunderstanding you, but my thinking is that the type could be made private so the entrypoint to this API is simple. More importantly, the caller doesn't have to concern him or herself with the implementation, or existence, of the
I think in either case we'd have to change a lot of the internals of the code, but I agree that this isn't a likely thing to happen in the near future.
I definitely agree. In the final iteration of this series of PRs, I'm imagining that something like |
I'm referring to |
Hi, all. I wanted to post a quick update after I've given some thought to this PR over the weekend. First of all, I'd like to thank @technoweenie and @sinbad for their feedback, and for asking hard questions. My goal with this series of PRs was for them to be small, and easily digestible in pieces. I failed, however, to clearly articulate my vision and reasoning behind removing/adding some code in both the comments and PR description. I will try and further articulate my vision in the future. For now, I am going to close this PR. My thinking here is that we have code in I think this allows us to keep the simple code that we already have while making small, incremental changes moving us towards our goals. My new plan, going forward, is:
Once again, I really do appreciate the feedback, and can't wait to get cracking on the rest of the PRs in this series. 🤘 |
The RevListScanner structure of the "git" package is constructed by the NewRevListScanner() function, which takes a ScanRefsOptions structure as an argument. The git.ScanRefsOptions structure encapsulates the large number of flags and other fields which a caller may potentially set for the "git rev-list" scanning operation. The "lfs" package also has a similar ScanRefsOptions structure, which is used by the various Scan*() methods of the GitScanner structure to pass optional flags and fields to the internal functions which implement the scanning operations. However, unlike the "git" package, this ScanRefsOptions structure is not used when constructing a GitScanner, and is moreover never used outside of the "lfs" package. We can therefore remove this structure in favour of a more conventional set of internal elements encapsulated directly in the GitScanner structure. This simplifies the signatures of many of the internal scan*() functions and helps clarify what parts of the GitScanner structure actually need to be exported. As part of this change, we also create a new, dedicated and un-exported nameMap structure, which holds the map of Git object SHAs to their pathspecs, as populated during scan operations. It is then utilized in the existing lockableNameSet structure, whose Check() method is called by the runCatFileBatch() and runCatFileBatchCheck() functions to collect the pathspecs of files locked by other users. Note that the intent to remove the ScanRefsOptions structure from the "lfs" package was discussed in several PRs in 2016, and in particular, this commit's changes achieve some of the goals of the never-merged PR git-lfs#1595, but without introducing an entirely generic "scanner" package. See also: git-lfs#1670 (comment)
The RevListScanner structure of the "git" package is constructed by the NewRevListScanner() function, which takes a ScanRefsOptions structure as an argument. The git.ScanRefsOptions structure encapsulates the large number of flags and other fields which a caller may potentially set for the "git rev-list" scanning operation. The "lfs" package also has a similar ScanRefsOptions structure, which is used by the various Scan*() methods of the GitScanner structure to pass optional flags and fields to the internal functions which implement the scanning operations. However, unlike the "git" package, this ScanRefsOptions structure is not used when constructing a GitScanner, and is moreover never used outside of the "lfs" package. We can therefore remove this structure in favour of a more conventional set of internal elements encapsulated directly in the GitScanner structure. This simplifies the signatures of many of the internal scan*() functions and helps clarify what parts of the GitScanner structure actually need to be exported. As part of this change, we also create a new, dedicated and un-exported nameMap structure, which holds the map of Git object SHAs to their pathspecs, as populated during scan operations. It is then utilized in the existing lockableNameSet structure, whose Check() method is called by the runCatFileBatch() and runCatFileBatchCheck() functions to collect the pathspecs of files locked by other users. Note that the intent to remove the ScanRefsOptions structure from the "lfs" package was discussed in several PRs in 2016, and in particular, this commit's changes achieve some of the goals of the never-merged PR git-lfs#1595, but without introducing an entirely generic "scanner" package. See also: git-lfs#1670 (comment)
The RevListScanner structure of the "git" package is constructed by the NewRevListScanner() function, which takes a ScanRefsOptions structure as an argument. The git.ScanRefsOptions structure encapsulates the large number of flags and other fields which a caller may potentially set for the "git rev-list" scanning operation. The "lfs" package also has a similar ScanRefsOptions structure, which is used by the various Scan*() methods of the GitScanner structure to pass optional flags and fields to the internal functions which implement the scanning operations. However, unlike the "git" package, this ScanRefsOptions structure is not used when constructing a GitScanner, and is moreover never used outside of the "lfs" package. We can therefore remove this structure in favour of a more conventional set of internal elements encapsulated directly in the GitScanner structure. This simplifies the signatures of many of the internal scan*() functions and helps clarify what parts of the GitScanner structure actually need to be exported. As part of this change, we also create a new, dedicated and un-exported nameMap structure, which holds the map of Git object SHAs to their pathspecs, as populated during scan operations. It is then utilized in the existing lockableNameSet structure, whose Check() method is called by the runCatFileBatch() and runCatFileBatchCheck() functions to collect the pathspecs of files locked by other users. Note that the intent to remove the ScanRefsOptions structure from the "lfs" package was discussed in several PRs in 2016, and in particular, this commit's changes achieve some of the goals of the never-merged PR git-lfs#1595, but without introducing an entirely generic "scanner" package. See also: git-lfs#1670 (comment)
The RevListScanner structure of the "git" package is constructed by the NewRevListScanner() function, which takes a ScanRefsOptions structure as an argument. The git.ScanRefsOptions structure encapsulates the large number of flags and other fields which a caller may potentially set for the "git rev-list" scanning operation. The "lfs" package also has a similar ScanRefsOptions structure, which is used by the various Scan*() methods of the GitScanner structure to pass optional flags and fields to the internal functions which implement the scanning operations. However, unlike the "git" package, this ScanRefsOptions structure is not used when constructing a GitScanner, and is moreover never used outside of the "lfs" package. We can therefore remove this structure in favour of a more conventional set of internal elements encapsulated directly in the GitScanner structure. This simplifies the signatures of many of the internal scan*() functions and helps clarify what parts of the GitScanner structure actually need to be exported. As part of this change, we also create a new, dedicated and un-exported nameMap structure, which holds the map of Git object SHAs to their pathspecs, as populated during scan operations. It is then utilized in the existing lockableNameSet structure, whose Check() method is called by the runCatFileBatch() and runCatFileBatchCheck() functions to collect the pathspecs of files locked by other users. Note that the intent to remove the ScanRefsOptions structure from the "lfs" package was discussed in several PRs in 2016, and in particular, this commit's changes achieve some of the goals of the never-merged PR git-lfs#1595, but without introducing an entirely generic "scanner" package. See also: git-lfs#1670 (comment)
The RevListScanner structure of the "git" package is constructed by the NewRevListScanner() function, which takes a ScanRefsOptions structure as an argument. The git.ScanRefsOptions structure encapsulates the large number of flags and other fields which a caller may potentially set for the "git rev-list" scanning operation. The "lfs" package also has a similar ScanRefsOptions structure, which is used by the various Scan*() methods of the GitScanner structure to pass optional flags and fields to the internal functions which implement the scanning operations. However, unlike the "git" package, this ScanRefsOptions structure is not used when constructing a GitScanner, and is moreover never used outside of the "lfs" package. We can therefore remove this structure in favour of a more conventional set of internal elements encapsulated directly in the GitScanner structure. This simplifies the signatures of many of the internal scan*() functions and helps clarify what parts of the GitScanner structure actually need to be exported. As part of this change, we also create a new, dedicated and un-exported nameMap structure, which holds the map of Git object SHAs to their pathspecs, as populated during scan operations. It is then utilized in the existing lockableNameSet structure, whose Check() method is called by the runCatFileBatch() and runCatFileBatchCheck() functions to collect the pathspecs of files locked by other users. Note that the intent to remove the ScanRefsOptions structure from the "lfs" package was discussed in several PRs in 2016, and in particular, this commit's changes achieve some of the goals of the never-merged PR git-lfs#1595, but without introducing an entirely generic "scanner" package. See also: git-lfs#1670 (comment)
This pull-request refactors the original implementation of the
RevListShas
method into a type that retains the same behavior.This is done such that we can easily manipulate a channel of revs coming out of this function. That is not made use of (yet), but will become the case in a subsequent PR.
/cc @technoweenie @rubyist @sinbad @sschuberth @larsxschneider