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

executor.go « git2go « internal - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: dea316d951f2de0cab33db94f1ebb7669780cd80 (plain)
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/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/gitaly/v16/internal/metadata/featureflag"
	"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
}