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

binaries.go « testcfg « testhelper « internal - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: fc4ee9529367f0b956cc96f040b63c4d4c2cf7c1 (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
135
136
137
138
139
140
141
package testcfg

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"testing"

	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/config"
	"gitlab.com/gitlab-org/gitaly/v15/internal/helper/perm"
	"gitlab.com/gitlab-org/gitaly/v15/internal/testhelper"
)

var buildOnceByName sync.Map

// BuildGitalyGit2Go builds the gitaly-git2go command and installs it into the binary directory.
func BuildGitalyGit2Go(tb testing.TB, cfg config.Cfg) string {
	return buildGitalyCommand(tb, cfg, "gitaly-git2go")
}

// BuildGitalyWrapper builds the gitaly-wrapper command and installs it into the binary directory.
func BuildGitalyWrapper(tb testing.TB, cfg config.Cfg) string {
	return buildGitalyCommand(tb, cfg, "gitaly-wrapper")
}

// BuildGitalyLFSSmudge builds the gitaly-lfs-smudge command and installs it into the binary
// directory.
func BuildGitalyLFSSmudge(tb testing.TB, cfg config.Cfg) string {
	return buildGitalyCommand(tb, cfg, "gitaly-lfs-smudge")
}

// BuildGitalyHooks builds the gitaly-hooks command and installs it into the binary directory.
func BuildGitalyHooks(tb testing.TB, cfg config.Cfg) string {
	return buildGitalyCommand(tb, cfg, "gitaly-hooks")
}

// BuildGitalySSH builds the gitaly-ssh command and installs it into the binary directory.
func BuildGitalySSH(tb testing.TB, cfg config.Cfg) string {
	return buildGitalyCommand(tb, cfg, "gitaly-ssh")
}

// BuildPraefect builds the praefect command and installs it into the binary directory.
func BuildPraefect(tb testing.TB, cfg config.Cfg) string {
	return buildGitalyCommand(tb, cfg, "praefect")
}

// BuildGitaly builds the gitaly binary and installs it into the binary directory. The gitaly binary
// embeds other binaries it needs to use when servicing requests. The packed binaries are not built
// prior to building this gitaly binary and thus cannot be guaranteed to be from the same build.
func BuildGitaly(tb testing.TB, cfg config.Cfg) string {
	return buildGitalyCommand(tb, cfg, "gitaly")
}

// buildGitalyCommand builds an executable and places it in the correct directory depending
// whether it is packed in the production build or not.
func buildGitalyCommand(tb testing.TB, cfg config.Cfg, executableName string) string {
	return BuildBinary(tb, filepath.Dir(cfg.BinaryPath(executableName)), gitalyCommandPath(executableName))
}

var (
	sharedBinariesDir               string
	createGlobalBinaryDirectoryOnce sync.Once
)

// BuildBinary builds a Go binary once and copies it into the target directory. The source path can
// either be a ".go" file or a directory containing Go files. Returns the path to the executable in
// the destination directory.
func BuildBinary(tb testing.TB, targetDir, sourcePath string) string {
	createGlobalBinaryDirectoryOnce.Do(func() {
		sharedBinariesDir = testhelper.CreateGlobalDirectory(tb, "bins")
	})
	require.NotEmpty(tb, sharedBinariesDir, "creation of shared binary directory failed")

	var (
		// executableName is the name of the executable.
		executableName = filepath.Base(sourcePath)
		// sharedBinaryPath is the path to the binary shared between all tests.
		sharedBinaryPath = filepath.Join(sharedBinariesDir, executableName)
		// targetPath is the final path where the binary should be copied to.
		targetPath = filepath.Join(targetDir, executableName)
	)

	buildOnceInterface, _ := buildOnceByName.LoadOrStore(executableName, &sync.Once{})
	buildOnce, ok := buildOnceInterface.(*sync.Once)
	require.True(tb, ok)

	buildOnce.Do(func() {
		require.NoFileExists(tb, sharedBinaryPath, "binary has already been built")

		// We need to filter out some environments we set globally in our tests which would
		// cause Git to not operate correctly.
		filteredEnvironment := make([]string, 0, len(os.Environ()))
		for _, env := range os.Environ() {
			if !strings.HasPrefix(env, "GIT_DIR=") {
				filteredEnvironment = append(filteredEnvironment, env)
			}
		}

		buildTags := []string{
			"static", "system_libgit2", "gitaly_test",
		}
		if os.Getenv("GITALY_TESTING_ENABLE_FIPS") != "" {
			buildTags = append(buildTags, "fips")
		}

		cmd := exec.Command(
			"go",
			"build",
			"-buildvcs=false",
			"-tags", strings.Join(buildTags, ","),
			"-o", sharedBinaryPath,
			sourcePath,
		)
		cmd.Env = filteredEnvironment

		output, err := cmd.CombinedOutput()
		require.NoError(tb, err, "building Go executable: %v, output: %q", err, output)
	})

	require.FileExists(tb, sharedBinaryPath, "%s does not exist", executableName)
	require.NoFileExists(tb, targetPath, "%s exists already -- do you try to build it twice?", executableName)

	require.NoError(tb, os.MkdirAll(targetDir, perm.PublicDir))

	// We hard-link the file into place instead of copying it because copying used to cause
	// ETXTBSY errors in CI. This is likely caused by a bug in the overlay filesystem used by
	// Docker, so we just work around this by linking the file instead. It's more efficient
	// anyway, the only thing is that no test must modify the binary directly. But let's count
	// on that.
	require.NoError(tb, os.Link(sharedBinaryPath, targetPath))

	return targetPath
}

func gitalyCommandPath(command string) string {
	return fmt.Sprintf("gitlab.com/gitlab-org/gitaly/v15/cmd/%s", command)
}