-
Notifications
You must be signed in to change notification settings - Fork 899
Win http fetch #213
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
Win http fetch #213
Conversation
// the data in the git_remote_callbacks structure. If, in the future, libgit2 changes its implementation | ||
// to store a reference to the git_remote_callbacks structure this would introduce a subtle bug | ||
// where the managed layer could move the git_remote_callbacks to a different location in memory, | ||
// but libgit2 would still reference the old address. |
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.
💕 comments like this.
@jamill Wow. That's a very detailed PR. Thanks a lot for this!
It doesn't do this by default. Yet. (@carlosmn ;-) ) A naive implementation could be, once the heads have been fetched, to create a temporary remote targeting the same url and bearing a different refspec (
I'm not sure about Events.. Please give me a couple of days to contemplate your proposal...
|
I've seen it, and I can reproduce it fairly regularly using the libgit2sharp unit tests. I'll do some digging today. |
Found the root cause of the "OID doesn't exist" problem; a fix is pending on libgit2/libgit2#932. This will most likely only happen with REALLY small repos. |
@ben ❤️ |
@ben Thanks!
sure! I will look at "emulating" the tag fetching in C#. The other thing I wanted to ask your thoughts on was the fact that I have encapsulated the entire fetch operation in a basically a single method. The other approach would have been to expose loading the remote, downloading the packfile, updating the reference tips as seperate operations (including managing the lifetime of the remote handle and remote connection between - as they would have to be kept alive for longer than the single call on the public method) |
Great!
I completely agree with this. Let's make the standard operations easy to deal with. |
Even if it's not the primary API, a useful overload might look something like this...
|
+1 on handlers vs events -- makes consuming easier. |
@dahlbyk , @uluhonolulu Thanks for the feedback! I don't mind exposing these callbacks as delegates - I would prefer to only expose one way or the other, but I don't mind if that way is as delegates. |
} | ||
finally | ||
{ | ||
if (remoteHandle != null) |
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 it even valid for remoteHandle
to be null
here?
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 will remove the null check here.
I'll cast my vote for delegates:
vs
Can/should |
I think it seems reasonable that Fetch() would support cancellation - however, I do not see this supported in libgit2's fetch implementation. I think this is something that would be handled at a layer below LibGit2Sharp... |
Is calling |
I see, thanks! Looks like that would cancel the network transfer portion of the fetch (where I would expect the majority of the time is). I like the idea of fetch being cancelable, but I would like think through some of the details a bit more before I would go ahead and implement it. I wouldn't expect the Fetch interface to change much to support cancelation. I will expose the callbacks as delegates instead of events. I had a question about the other part of your API suggestion. The signature of the Fetch method overload that you proposed takes some extra parameters (one for each of the callbacks) and removes the progress reporting parameter (containing the bytes received and the GitIndexerStats). Is the scenario that you have in mind that a caller would only care about the callbacks and not the other progress information? Or, were you suggesting that there should be a flavor of the Fetch method that can take each of the arguments individually as optional parameters. That is, is:
the full signature of the overload, or were you suggesting something more along the lines of:
Thank you again for you feedback. |
My first reaction was to just return the
However, it seems reasonable to assume
Or you could return the |
+1 for Returning FetchProgress seems reasonable if we want to have the Cancel method hanging off it. var progress = repo.Fetch(..);
Button1.Click += () => progress.Cancel(); In that case, C# grammar requires we both return it and use it in the delegate, since we cannot write a lambda for it. Anyway, let's try and write a couple of tests, and see which way is less painful. |
@@ -83,7 +83,10 @@ public void Dispose() | |||
{ | |||
foreach (string directory in directories) | |||
{ | |||
DirectoryHelper.DeleteDirectory(directory); | |||
if (Directory.Exists(directory)) |
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.
Could you please give me some more context about this?
When would this check be required?
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 had hit an issue running the CanCloneARepository(...)
tests where the test would create the SelfCleaningDirectory object and register the temporary directory path for deletion, but the test would fail in Repository.Clone(...)
before the temporary directory actually got created. On cleanup, the test would throw an exception indicating that it could not find the path of the temporary directory (as it does not exist). The end result is that the test reports that it failed to find the path of the temporary directory (which hides the original exception).
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 a lot for your answer. Indeed, that makes sense.
However, I'm afraid this check could hide that something may have went wrong earlier (a wrongly written test for instance). Could you think of a way to let the user know about this not expected state?
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.
For now (especially as the clone is no longer part of the test suite) I will remove this change so we can concentrate on the core Fetch changes.
@dahlbyk, @uluhonolulu Regarding the Fetch method:
|
@ben regarding the |
Regarding the API:
I also agree with @dahlbyk and @uluhonolulu. Let's go down the delegates road :)
When callbacks are involved, usually returning something different from
I'm not even sure this scenario has been tested at the libgit2 level. /cc @carlosmn |
FWIW libgit2/libgit2#890 is trying to tackle this issue (/cc @ben) |
@jamill @ben Provided I do not encounter any regression while running the LibGit2Sharp test suite, I'm going to update vNext very soon with a newer version of libgit2 as soon as libgit2/libgit2#932 is merged. The dedicated libgit2 build and LibGit2Sharp branch are no longer needed as libgit2/libgit2#901 is now merged. /cc @arrbee |
Thanks, so a couple of questions: 1. How to report progressMy understanding of the current state of things is that currently, the best way to get some of the progress information for
However, there is some work going on to make update progress reporting:
With these items, it seems we would not have to query the progress datastructures on a seperate thread for progress. 2. Whether there should be an asynchronous fetch methodFrom the API usage examples above, it seems that an asynchronous version of this method would be nice. In the clone / fetch examples for libgit2 the caller is responsible for running clone / fetch on a background thread. Should LibGit2Sharp follow this pattern? Alternatively, should LibGit2Sharp provide an asynchronous method that will go ahead and run the long running operation on the background thread and return immediately. Even if there was an async version of Fetch, it seems that a synchronous version is needed. Given the above, I propose the following to move forward (in addition to addressing other feedback):
Thoughts? |
👍 Even if I tend to avoid delivering API that will be broken by next version,
👍 as well.
Unfortunately, libgit2/libgit2#932 cannot be merged right now. However, in order to not keep you holding, vNext has been updated with the tip of libgit2 development branch (libgit2/libgit2@411cb01). Please note that a |
👍 from me as well. Thanks for clearing up the difference between the values exposed through |
I'm all for release now, enhance later. |
I'm actually thinking that passing a structure that receives progress info is a Bad Idea. What if the GC moves the structure around on the managed heap during the fetch? The C code wouldn't have a clue, and Bad Things could happen. Given this, we should probably double-down on delegates for reporting progress, which means I'll have to think about how to make that happen with clone. Unfortunately I'm jet-lagged today and speaking at a conference tomorrow morning, so I can't read through @jamill's code to figure out how it should be done. Hopefully I'll have a chance in the next couple of days. |
@ben From a correctness point of view, I think passing structures that receive progress info is OK - The progress structures are pinned by the interop layer during the call to git_remote_download and should not be moved by GC (git_remote_download is synchronous and will not return until fetch is complete). |
The code to auto-follow tags and create them has been merged to libgit2, you'll get that whenever you update the library. As for the indexer calling a callback, there isn't really a unit of measurement where it makes more sense than another to call it. How often should we call it? Per received object? Per received x bytes? |
@carlosmn , @nulltoken Thanks! I will move back on to the main development branch. I will get back to this shortly and update the change based on the feedback. |
I'd go with what's easiest. If they're equally easy, go with the more granular. If it's called more often than a consumer cares for, they can throttle it. |
@jamill |
@nulltoken @dahlbyk @carlosmn @uluhonolulu : I have created a new PR with the changes based off of vNext (I did not see a way to update the branch the PR is based off of - if I missed something, please let me know). Again, thank you everyone for the feedback so far. I have addressed much of it in the new PR. |
Closing this one, as all the love is now redirected to #221 |
An updated Fetch implementation based off of @ben's repository, from suggestions in Pull Request #206. This includes a basic test for fetching from a remote into an empty repository. I made some choices on how / where to expose this functionality, so please let me know if you have thoughts / comments / questions.
Missing functionality:
Implementation:
Issues:
I have seen intermittent failures from libgit2 during both the clone and fetch tests that I have not tracked down at this point (as part of call to git_remote_update_tips in fetch, and git_clone in Clone).
LibGit2Sharp.LibGit2SharpException : An error was raised by libgit2. Category = Reference (Error).
Target OID for the reference doesn't exist on the repository