package gitcmd
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"strings"
)
type Command struct {
args []string
dir string
env []string
stdin io.Reader
stdout io.Writer
stderr io.Writer
}
func New(args ...string) *Command {
return &Command{args: args}
}
func (c *Command) WithDir(dir string) *Command {
c.dir = dir
return c
}
func (c *Command) WithEnv(env []string) *Command {
c.env = env
return c
}
func (c *Command) WithStdio(stdin io.Reader, stdout, stderr io.Writer) *Command {
c.stdin = stdin
c.stdout = stdout
c.stderr = stderr
return c
}
func baseEnv() []string {
home, _ := os.UserHomeDir()
return []string{
"HOME=" + home,
"GIT_CONFIG_NOSYSTEM=1",
"GIT_TERMINAL_PROMPT=0",
"LC_ALL=C",
}
}
func (c *Command) Run(ctx context.Context) error {
cmd := exec.CommandContext(ctx, "git", c.args...)
cmd.Dir = c.dir
cmd.Stdin = c.stdin
cmd.Stdout = c.stdout
cmd.Stderr = c.stderr
env := os.Environ()
if c.env != nil {
env = c.env
}
cmd.Env = append(env, baseEnv()...)
if err := cmd.Run(); err != nil {
return fmt.Errorf("git %v: %w", c.args, err)
}
return nil
}
func RunStdString(ctx context.Context, dir string, args ...string) (string, error) {
var stdout, stderr strings.Builder
err := New(args...).WithDir(dir).WithStdio(nil, &stdout, &stderr).Run(ctx)
if err != nil {
return "", fmt.Errorf("%w: %s", err, stderr.String())
}
return stdout.String(), nil
}