1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
package git2go
import (
"bytes"
"context"
"encoding/gob"
"errors"
"fmt"
"io"
"strings"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
"gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/alternates"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
glog "gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/labkit/correlation"
)
var (
// ErrInvalidArgument is returned in case the merge arguments are invalid.
ErrInvalidArgument = errors.New("invalid parameters")
// BinaryName is the name of the gitaly-git2go binary.
BinaryName = "gitaly-git2go"
)
// Executor executes gitaly-git2go.
type Executor struct {
binaryPath string
signingKey string
gitCmdFactory git.CommandFactory
locator storage.Locator
logFormat, logLevel string
}
// NewExecutor returns a new gitaly-git2go executor using binaries as configured in the given
// configuration.
func NewExecutor(cfg config.Cfg, gitCmdFactory git.CommandFactory, locator storage.Locator) *Executor {
return &Executor{
binaryPath: cfg.BinaryPath(BinaryName),
signingKey: cfg.Git.SigningKey,
gitCmdFactory: gitCmdFactory,
locator: locator,
logFormat: cfg.Logging.Format,
logLevel: cfg.Logging.Level,
}
}
func (b *Executor) run(ctx context.Context, repo repository.GitRepo, stdin io.Reader, subcmd string, args ...string) (*bytes.Buffer, error) {
repoPath, err := b.locator.GetRepoPath(repo)
if err != nil {
return nil, fmt.Errorf("gitaly-git2go: %w", err)
}
var enabledFeatureFlags, disabledFeatureFlags []string
for flag, value := range featureflag.FromContext(ctx) {
switch value {
case true:
enabledFeatureFlags = append(enabledFeatureFlags, flag.MetadataKey())
case false:
disabledFeatureFlags = append(disabledFeatureFlags, flag.MetadataKey())
}
}
env := alternates.Env(repoPath, repo.GetGitObjectDirectory(), repo.GetGitAlternateObjectDirectories())
env = append(env, b.gitCmdFactory.GetExecutionEnvironment(ctx).EnvironmentVariables...)
// Pass the log output directly to gitaly-git2go. No need to reinterpret
// these logs as long as the destination is an append-only file. See
// https://pkg.go.dev/github.com/sirupsen/logrus#readme-thread-safety
log := glog.Default().Logger.Out
args = append([]string{
"-log-format", b.logFormat,
"-log-level", b.logLevel,
"-correlation-id", correlation.ExtractFromContext(ctx),
"-enabled-feature-flags", strings.Join(enabledFeatureFlags, ","),
"-disabled-feature-flags", strings.Join(disabledFeatureFlags, ","),
subcmd,
}, args...)
var stdout bytes.Buffer
cmd, err := command.New(ctx, append([]string{b.binaryPath}, args...),
command.WithStdin(stdin),
command.WithStdout(&stdout),
command.WithStderr(log),
command.WithEnvironment(env),
command.WithCommandName("gitaly-git2go", subcmd),
)
if err != nil {
return nil, err
}
if err := cmd.Wait(); err != nil {
return nil, err
}
return &stdout, nil
}
// runWithGob runs the specified gitaly-git2go cmd with the request gob-encoded
// as input and returns the commit ID as string or an error.
func (b *Executor) runWithGob(ctx context.Context, repo repository.GitRepo, cmd string, request interface{}) (git.ObjectID, error) {
input := &bytes.Buffer{}
if err := gob.NewEncoder(input).Encode(request); err != nil {
return "", fmt.Errorf("%s: %w", cmd, err)
}
output, err := b.run(ctx, repo, input, cmd)
if err != nil {
return "", fmt.Errorf("%s: %w", cmd, err)
}
var result Result
if err := gob.NewDecoder(output).Decode(&result); err != nil {
return "", fmt.Errorf("%s: %w", cmd, err)
}
if result.Err != nil {
return "", fmt.Errorf("%s: %w", cmd, result.Err)
}
commitID, err := git.ObjectHashSHA1.FromHex(result.CommitID)
if err != nil {
return "", fmt.Errorf("could not parse commit ID: %w", err)
}
return commitID, nil
}
|