Skip to content

Commit afa82bb

Browse files
hiddecodarkowlzz
authored andcommitted
libgit2: ensure context timeout cancels transfer
With the information from the refactor still fresh in mind, I continue to find new paths now I mentally tamed the git2go beast. `libgit2` seems to assume that a transport will eventually tell by itself that it has timed out. This also means that at present any timeout configuration does not seem have an effect. It will continue to transfer until the remote (or _something_ else) tells it is no longer transfering. This commit introduces a simple check (without tests) which was used to confirm the theory in combination with the tests in `pkg/git/strategy` (by setting it to a very low timeout and observing it fail). A future iteration should probably take the data given to the callback into account to ensure it doesn't error out if the given data[1] reports it has successfully received all objects. Another candidate for this check may be `CompletionCallback`, but one should study the C code (and likely some Go code as well) before this. In addition, to ensure the same timeout is taken into account for push operations, `PushTransferProgressCallback` may require a likewise helper. [1]: https://github.com/libgit2/git2go/blob/main/remote.go#L50-L58 Signed-off-by: Hidde Beydals <[email protected]>
1 parent f0d0f2a commit afa82bb

File tree

2 files changed

+21
-5
lines changed

2 files changed

+21
-5
lines changed

pkg/git/libgit2/checkout.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g
6363
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
6464
FetchOptions: &git2go.FetchOptions{
6565
DownloadTags: git2go.DownloadTagsNone,
66-
RemoteCallbacks: RemoteCallbacks(opts),
66+
RemoteCallbacks: RemoteCallbacks(ctx, opts),
6767
},
6868
CheckoutBranch: c.Branch,
6969
})
@@ -92,7 +92,7 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.
9292
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
9393
FetchOptions: &git2go.FetchOptions{
9494
DownloadTags: git2go.DownloadTagsAll,
95-
RemoteCallbacks: RemoteCallbacks(opts),
95+
RemoteCallbacks: RemoteCallbacks(ctx, opts),
9696
},
9797
})
9898
if err != nil {
@@ -115,7 +115,7 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *g
115115
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
116116
FetchOptions: &git2go.FetchOptions{
117117
DownloadTags: git2go.DownloadTagsNone,
118-
RemoteCallbacks: RemoteCallbacks(opts),
118+
RemoteCallbacks: RemoteCallbacks(ctx, opts),
119119
},
120120
})
121121
if err != nil {
@@ -146,7 +146,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g
146146
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
147147
FetchOptions: &git2go.FetchOptions{
148148
DownloadTags: git2go.DownloadTagsAll,
149-
RemoteCallbacks: RemoteCallbacks(opts),
149+
RemoteCallbacks: RemoteCallbacks(ctx, opts),
150150
},
151151
})
152152
if err != nil {

pkg/git/libgit2/transport.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package libgit2
1919
import (
2020
"bufio"
2121
"bytes"
22+
"context"
2223
"crypto/md5"
2324
"crypto/sha1"
2425
"crypto/sha256"
@@ -43,16 +44,31 @@ var (
4344

4445
// RemoteCallbacks constructs RemoteCallbacks with credentialsCallback and
4546
// certificateCallback, and the given options if the given opts is not nil.
46-
func RemoteCallbacks(opts *git.AuthOptions) git2go.RemoteCallbacks {
47+
func RemoteCallbacks(ctx context.Context, opts *git.AuthOptions) git2go.RemoteCallbacks {
4748
if opts != nil {
4849
return git2go.RemoteCallbacks{
50+
TransferProgressCallback: transferProgressCallback(ctx),
4951
CredentialsCallback: credentialsCallback(opts),
5052
CertificateCheckCallback: certificateCallback(opts),
5153
}
5254
}
5355
return git2go.RemoteCallbacks{}
5456
}
5557

58+
// transferProgressCallback constructs TransferProgressCallbacks which signals
59+
// libgit2 it should stop the transfer when the given context is closed (due to
60+
// e.g. a timeout).
61+
func transferProgressCallback(ctx context.Context) git2go.TransferProgressCallback {
62+
return func(_ git2go.TransferProgress) git2go.ErrorCode {
63+
select {
64+
case <-ctx.Done():
65+
return git2go.ErrorCodeUser
66+
default:
67+
return git2go.ErrorCodeOK
68+
}
69+
}
70+
}
71+
5672
// credentialsCallback constructs CredentialsCallbacks with the given options
5773
// for git.Transport, and returns the result.
5874
func credentialsCallback(opts *git.AuthOptions) git2go.CredentialsCallback {

0 commit comments

Comments
 (0)