package git import ( "bytes" "context" "fmt" "os" "os/exec" "strings" "github.com/hashicorp/go-version" ) func Version() (*version.Version, error) { var buf bytes.Buffer cmd := exec.Command("git", "version") cmd.Stdout = &buf cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { return nil, err } fields := strings.Fields(buf.String()) if len(fields) < 3 { return nil, fmt.Errorf("invalid git version: %s", buf.String()) } // version string is like: "git version 2.29.3" or "git version 2.29.3.windows.1" versionString := fields[2] if pos := strings.Index(versionString, "windows"); pos >= 1 { versionString = versionString[:pos-1] } return version.NewVersion(versionString) } const WorkflowDir = `/.tangled/workflows` func SparseSyncGitRepo(ctx context.Context, cloneUri, path, rev string) error { exist, err := isDir(path) if err != nil { return err } if rev == "" { rev = "HEAD" } if !exist { if err := exec.Command("git", "clone", "--no-checkout", "--depth=1", "--filter=tree:0", "--revision="+rev, cloneUri, path).Run(); err != nil { return fmt.Errorf("git clone: %w", err) } if err := exec.Command("git", "-C", path, "sparse-checkout", "set", "--no-cone", WorkflowDir).Run(); err != nil { return fmt.Errorf("git sparse-checkout set: %w", err) } } else { if err := exec.Command("git", "-C", path, "fetch", "--depth=1", "--filter=tree:0", "origin", rev).Run(); err != nil { return fmt.Errorf("git pull: %w", err) } } if err := exec.Command("git", "-C", path, "checkout", rev).Run(); err != nil { return fmt.Errorf("git checkout: %w", err) } return nil } func isDir(path string) (bool, error) { info, err := os.Stat(path) if err == nil && info.IsDir() { return true, nil } if os.IsNotExist(err) { return false, nil } return false, err }