From cc7789ef35707ff8817160bcdf1a34404dc959ce Mon Sep 17 00:00:00 2001 From: Sunny Date: Thu, 30 Sep 2021 03:40:24 +0530 Subject: [PATCH] libgit2: Update checkout to respect context Update libgit2-git2go checkout with a clone wrapper to respect the context passed to it. go-git accepts context passed to it during cloning but the git2go does not accept the context passed to it. This makes the GitRepository.Spec.Timeout ineffective when using libgit2. This change updates all the different libgit2 checkouts to use the new clone function. This is also needed to shorten the wait time for tests that depend on failure behavior and should fail early. TestCheckout_ED25519 test would take 30s without a context with timeout. This helps shorten the time for such tests. Signed-off-by: Sunny --- pkg/git/libgit2/checkout.go | 50 ++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/pkg/git/libgit2/checkout.go b/pkg/git/libgit2/checkout.go index 01363f8fa..f39f997f6 100644 --- a/pkg/git/libgit2/checkout.go +++ b/pkg/git/libgit2/checkout.go @@ -53,12 +53,34 @@ func CheckoutStrategyForRef(ref *sourcev1.GitRepositoryRef, opt git.CheckoutOpti } } +// clone is a wrapper around git2go.Clone that respects the provided context. +func clone(ctx context.Context, path, url string, auth *git.Auth, opts *git2go.CloneOptions) (*git2go.Repository, error) { + var repo *git2go.Repository + errCh := make(chan error, 1) + go func() { + var err error + repo, err = git2go.Clone(url, path, opts) + errCh <- err + }() + + select { + case err := <-errCh: + if err != nil { + return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) + } + case <-ctx.Done(): + return nil, ctx.Err() + } + + return repo, nil +} + type CheckoutBranch struct { branch string } func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, auth *git.Auth) (git.Commit, string, error) { - repo, err := git2go.Clone(url, path, &git2go.CloneOptions{ + cloneOpts := &git2go.CloneOptions{ FetchOptions: &git2go.FetchOptions{ DownloadTags: git2go.DownloadTagsNone, RemoteCallbacks: git2go.RemoteCallbacks{ @@ -67,9 +89,10 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, auth *g }, }, CheckoutBranch: c.branch, - }) + } + repo, err := clone(ctx, path, url, auth, cloneOpts) if err != nil { - return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) + return nil, "", err } head, err := repo.Head() if err != nil { @@ -87,7 +110,7 @@ type CheckoutTag struct { } func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, auth *git.Auth) (git.Commit, string, error) { - repo, err := git2go.Clone(url, path, &git2go.CloneOptions{ + cloneOpts := &git2go.CloneOptions{ FetchOptions: &git2go.FetchOptions{ DownloadTags: git2go.DownloadTagsAll, RemoteCallbacks: git2go.RemoteCallbacks{ @@ -95,9 +118,10 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, auth *git. CertificateCheckCallback: auth.CertCallback, }, }, - }) + } + repo, err := clone(ctx, path, url, auth, cloneOpts) if err != nil { - return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, err) + return nil, "", err } ref, err := repo.References.Dwim(c.tag) if err != nil { @@ -131,7 +155,7 @@ type CheckoutCommit struct { } func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, auth *git.Auth) (git.Commit, string, error) { - repo, err := git2go.Clone(url, path, &git2go.CloneOptions{ + cloneOpts := &git2go.CloneOptions{ FetchOptions: &git2go.FetchOptions{ DownloadTags: git2go.DownloadTagsNone, RemoteCallbacks: git2go.RemoteCallbacks{ @@ -140,9 +164,10 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, auth *g }, }, CheckoutBranch: c.branch, - }) + } + repo, err := clone(ctx, path, url, auth, cloneOpts) if err != nil { - return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, err) + return nil, "", err } oid, err := git2go.NewOid(c.commit) if err != nil { @@ -176,7 +201,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, auth *g return nil, "", fmt.Errorf("semver parse range error: %w", err) } - repo, err := git2go.Clone(url, path, &git2go.CloneOptions{ + cloneOpts := &git2go.CloneOptions{ FetchOptions: &git2go.FetchOptions{ DownloadTags: git2go.DownloadTagsAll, RemoteCallbacks: git2go.RemoteCallbacks{ @@ -184,9 +209,10 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, auth *g CertificateCheckCallback: auth.CertCallback, }, }, - }) + } + repo, err := clone(ctx, path, url, auth, cloneOpts) if err != nil { - return nil, "", fmt.Errorf("unable to clone '%s', error: %w", url, err) + return nil, "", err } tags := make(map[string]string)