diff options
author | Toon Claes <toon@gitlab.com> | 2023-02-09 10:07:37 +0300 |
---|---|---|
committer | Toon Claes <toon@gitlab.com> | 2023-02-09 10:07:37 +0300 |
commit | 4a6f31c9182921e5ca14e1b273e8440e510fb403 (patch) | |
tree | 58ddd4c28c11dca87d8065564483e5c209d1fb36 | |
parent | 2e3f4c42cd2f9ea42d830e0e214eae39522b30d5 (diff) | |
parent | e83475a5e80fc0daec8096bf0853c51cf64a98d0 (diff) |
Merge branch 'pks-git-more-robust-version-parsing' into 'master'
git: Fix race between cancelling git-version(1) and reading its output
Closes #4740
See merge request https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5344
Merged-by: Toon Claes <toon@gitlab.com>
Approved-by: Pavlo Strokov <pstrokov@gitlab.com>
Approved-by: Toon Claes <toon@gitlab.com>
Reviewed-by: Patrick Steinhardt <psteinhardt@gitlab.com>
Co-authored-by: Patrick Steinhardt <psteinhardt@gitlab.com>
-rw-r--r-- | internal/git/command_factory.go | 17 | ||||
-rw-r--r-- | internal/git/version.go | 19 |
2 files changed, 16 insertions, 20 deletions
diff --git a/internal/git/command_factory.go b/internal/git/command_factory.go index a7ceca341..e130cc630 100644 --- a/internal/git/command_factory.go +++ b/internal/git/command_factory.go @@ -1,6 +1,7 @@ package git import ( + "bytes" "context" "errors" "fmt" @@ -362,20 +363,24 @@ func (cf *ExecCommandFactory) GitVersion(ctx context.Context) (Version, error) { // Furthermore, note that we're not using `newCommand()` but instead hand-craft the command. // This is required to avoid a cyclic dependency when we need to check the version in // `newCommand()` itself. - cmd, err := command.New(ctx, []string{execEnv.BinaryPath, "version"}, command.WithEnvironment(execEnv.EnvironmentVariables)) + var versionBuffer bytes.Buffer + cmd, err := command.New(ctx, []string{execEnv.BinaryPath, "version"}, + command.WithEnvironment(execEnv.EnvironmentVariables), + command.WithStdout(&versionBuffer), + ) if err != nil { return Version{}, fmt.Errorf("spawning version command: %w", err) } - gitVersion, err := parseVersionFromCommand(cmd) - if err != nil { - return Version{}, err - } - if err := cmd.Wait(); err != nil { return Version{}, fmt.Errorf("waiting for version: %w", err) } + gitVersion, err := parseVersionOutput(versionBuffer.Bytes()) + if err != nil { + return Version{}, err + } + cf.cachedGitVersionByBinary[gitBinary] = cachedGitVersion{ version: gitVersion, stat: stat, diff --git a/internal/git/version.go b/internal/git/version.go index 2d13c1187..4690e96aa 100644 --- a/internal/git/version.go +++ b/internal/git/version.go @@ -1,12 +1,10 @@ package git import ( + "bytes" "fmt" - "io" "strconv" "strings" - - "gitlab.com/gitlab-org/gitaly/v15/internal/command" ) // minimumVersion is the minimum required Git version. If updating this version, be sure to @@ -38,17 +36,10 @@ type Version struct { gl uint32 } -func parseVersionFromCommand(cmd *command.Command) (Version, error) { - versionOutput, err := io.ReadAll(cmd) - if err != nil { - return Version{}, fmt.Errorf("reading version output: %w", err) - } - - if err := cmd.Wait(); err != nil { - return Version{}, fmt.Errorf("waiting for version command: %w", err) - } - - trimmedVersionOutput := strings.Trim(string(versionOutput), " \n") +// parseVersionOutput parses output returned by git-version(1). It is expected to be in the format +// "git version 2.39.1.gl1". +func parseVersionOutput(versionOutput []byte) (Version, error) { + trimmedVersionOutput := string(bytes.Trim(versionOutput, " \n")) versionString := strings.SplitN(trimmedVersionOutput, " ", 3) if len(versionString) != 3 { return Version{}, fmt.Errorf("invalid version format: %q", string(versionOutput)) |