Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'internal/gitaly/service/ref/util.go')
-rw-r--r--internal/gitaly/service/ref/util.go35
1 files changed, 31 insertions, 4 deletions
diff --git a/internal/gitaly/service/ref/util.go b/internal/gitaly/service/ref/util.go
index 5fb74f82d..4f90c3b0d 100644
--- a/internal/gitaly/service/ref/util.go
+++ b/internal/gitaly/service/ref/util.go
@@ -3,12 +3,17 @@ package ref
import (
"bytes"
"context"
+ "errors"
"fmt"
"math"
+ "os/exec"
+ "strings"
+ "syscall"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/lines"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
@@ -129,13 +134,14 @@ func (s *server) findRefs(ctx context.Context, writer lines.Sender, repo git.Rep
options = append(options, opts.cmdArgs...)
}
+ var stderr strings.Builder
cmd, err := repo.Exec(ctx, git.Command{
Name: "for-each-ref",
Flags: options,
Args: patterns,
- }, git.WithSetupStdout())
+ }, git.WithSetupStdout(), git.WithStderr(&stderr))
if err != nil {
- return err
+ return fmt.Errorf("spawning for-each-ref: %w", err)
}
if err := lines.Send(cmd, writer, lines.SenderOpts{
@@ -144,10 +150,31 @@ func (s *server) findRefs(ctx context.Context, writer lines.Sender, repo git.Rep
Limit: opts.Limit,
PageTokenError: opts.PageTokenError,
}); err != nil {
- return err
+ return fmt.Errorf("sending lines: %w", err)
}
- return cmd.Wait()
+ if err := cmd.Wait(); err != nil {
+ var exitErr *exec.ExitError
+ if errors.As(err, &exitErr) {
+ // When we have a limit set up and have sent all references upstream then the call to `Wait()` may
+ // indeed cause us to tear down the still-running git-for-each-ref(1) process. Because we close stdout
+ // before sending a signal the end result may be that the process will die with EPIPE because it failed
+ // to write to stdout.
+ //
+ // This is an expected error though, and thus we ignore it here.
+ status, ok := exitErr.ProcessState.Sys().(syscall.WaitStatus)
+ if ok && status.Signaled() && status.Signal() == syscall.SIGPIPE {
+ return nil
+ }
+
+ return structerr.New("listing failed with exit code %d", status.ExitStatus()).
+ WithMetadata("stderr", stderr.String())
+ }
+
+ return fmt.Errorf("waiting for for-each-ref: %w", err)
+ }
+
+ return nil
}
type paginationOpts struct {