1package git2go 2 3import ( 4 "bytes" 5 "context" 6 "encoding/gob" 7 "errors" 8 "fmt" 9 "io" 10 "os/exec" 11 "path/filepath" 12 13 "gitlab.com/gitlab-org/gitaly/v14/internal/command" 14 "gitlab.com/gitlab-org/gitaly/v14/internal/git" 15 "gitlab.com/gitlab-org/gitaly/v14/internal/git/alternates" 16 "gitlab.com/gitlab-org/gitaly/v14/internal/git/repository" 17 "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/config" 18 "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/storage" 19 "gitlab.com/gitlab-org/gitaly/v14/internal/version" 20) 21 22var ( 23 // ErrInvalidArgument is returned in case the merge arguments are invalid. 24 ErrInvalidArgument = errors.New("invalid parameters") 25 26 // BinaryName is a binary name with version suffix . 27 BinaryName = "gitaly-git2go-" + version.GetModuleVersion() 28) 29 30// Executor executes gitaly-git2go. 31type Executor struct { 32 binaryPath string 33 gitBinaryPath string 34 locator storage.Locator 35} 36 37// NewExecutor returns a new gitaly-git2go executor using binaries as configured in the given 38// configuration. 39func NewExecutor(cfg config.Cfg, locator storage.Locator) Executor { 40 return Executor{ 41 binaryPath: filepath.Join(cfg.BinDir, BinaryName), 42 gitBinaryPath: cfg.Git.BinPath, 43 locator: locator, 44 } 45} 46 47func (b Executor) run(ctx context.Context, repo repository.GitRepo, stdin io.Reader, args ...string) (*bytes.Buffer, error) { 48 repoPath, err := b.locator.GetRepoPath(repo) 49 if err != nil { 50 return nil, fmt.Errorf("gitaly-git2go: %w", err) 51 } 52 53 env := alternates.Env(repoPath, repo.GetGitObjectDirectory(), repo.GetGitAlternateObjectDirectories()) 54 55 var stderr, stdout bytes.Buffer 56 cmd, err := command.New(ctx, exec.Command(b.binaryPath, args...), stdin, &stdout, &stderr, env...) 57 if err != nil { 58 return nil, err 59 } 60 61 if err := cmd.Wait(); err != nil { 62 if _, ok := err.(*exec.ExitError); ok { 63 return nil, fmt.Errorf("%s", stderr.String()) 64 } 65 return nil, err 66 } 67 68 return &stdout, nil 69} 70 71// runWithGob runs the specified gitaly-git2go cmd with the request gob-encoded 72// as input and returns the commit ID as string or an error. 73func (b Executor) runWithGob(ctx context.Context, repo repository.GitRepo, cmd string, request interface{}) (git.ObjectID, error) { 74 input := &bytes.Buffer{} 75 if err := gob.NewEncoder(input).Encode(request); err != nil { 76 return "", fmt.Errorf("%s: %w", cmd, err) 77 } 78 79 output, err := b.run(ctx, repo, input, cmd) 80 if err != nil { 81 return "", fmt.Errorf("%s: %w", cmd, err) 82 } 83 84 var result Result 85 if err := gob.NewDecoder(output).Decode(&result); err != nil { 86 return "", fmt.Errorf("%s: %w", cmd, err) 87 } 88 89 if result.Error != nil { 90 return "", fmt.Errorf("%s: %w", cmd, result.Error) 91 } 92 93 commitID, err := git.NewObjectIDFromHex(result.CommitID) 94 if err != nil { 95 return "", fmt.Errorf("could not parse commit ID: %w", err) 96 } 97 98 return commitID, nil 99} 100