1package git23import (4 "context"5 "fmt"6 "io"7 "strings"8 "sync"9)1011var (12 // logOutput is the writer to write logs. When not set, no log will be produced.13 logOutput io.Writer14 // logPrefix is the prefix prepend to each log entry.15 logPrefix = "[git-module] "16)1718// SetOutput sets the output writer for logs.19func SetOutput(output io.Writer) {20 logOutput = output21}2223// SetPrefix sets the prefix to be prepended to each log entry.24func SetPrefix(prefix string) {25 logPrefix = prefix26}2728func logf(format string, args ...interface{}) {29 if logOutput == nil {30 return31 }3233 _, _ = fmt.Fprint(logOutput, logPrefix)34 _, _ = fmt.Fprintf(logOutput, format, args...)35 _, _ = fmt.Fprintln(logOutput)36}3738var (39 // gitVersion stores the Git binary version.40 // NOTE: To check Git version should call BinVersion not this global variable.41 gitVersion string42 gitVersionMu sync.Mutex43 gitVersionSet bool44)4546// BinVersion returns current Git binary version that is used by this module.47// Successful results are cached; failed attempts are not cached, allowing48// retries with a fresh context.49func BinVersion(ctx context.Context) (string, error) {50 gitVersionMu.Lock()51 defer gitVersionMu.Unlock()5253 if gitVersionSet {54 return gitVersion, nil55 }5657 stdout, err := exec(ctx, "", []string{"version"}, nil)58 if err != nil {59 return "", err60 }6162 fields := strings.Fields(string(stdout))63 if len(fields) < 3 {64 return "", fmt.Errorf("not enough output: %s", stdout)65 }6667 // Handle special case on Windows.68 i := strings.Index(fields[2], "windows")69 if i >= 1 {70 gitVersion = fields[2][:i-1]71 } else {72 gitVersion = fields[2]73 }7475 gitVersionSet = true76 return gitVersion, nil77}