1package git
2
3import (
4 "bytes"
5 "context"
6 "fmt"
7 "os"
8 "os/exec"
9 "strings"
10
11 "github.com/hashicorp/go-version"
12)
13
14func Version() (*version.Version, error) {
15 var buf bytes.Buffer
16 cmd := exec.Command("git", "version")
17 cmd.Stdout = &buf
18 cmd.Stderr = os.Stderr
19 err := cmd.Run()
20 if err != nil {
21 return nil, err
22 }
23 fields := strings.Fields(buf.String())
24 if len(fields) < 3 {
25 return nil, fmt.Errorf("invalid git version: %s", buf.String())
26 }
27
28 // version string is like: "git version 2.29.3" or "git version 2.29.3.windows.1"
29 versionString := fields[2]
30 if pos := strings.Index(versionString, "windows"); pos >= 1 {
31 versionString = versionString[:pos-1]
32 }
33 return version.NewVersion(versionString)
34}
35
36const WorkflowDir = `/.tangled/workflows`
37
38func SparseSyncGitRepo(ctx context.Context, cloneUri, path, rev string) error {
39 exist, err := isDir(path)
40 if err != nil {
41 return err
42 }
43 if rev == "" {
44 rev = "HEAD"
45 }
46 if !exist {
47 if err := exec.Command("git", "clone", "--no-checkout", "--depth=1", "--filter=tree:0", "--revision="+rev, cloneUri, path).Run(); err != nil {
48 return fmt.Errorf("git clone: %w", err)
49 }
50 if err := exec.Command("git", "-C", path, "sparse-checkout", "set", "--no-cone", WorkflowDir).Run(); err != nil {
51 return fmt.Errorf("git sparse-checkout set: %w", err)
52 }
53 } else {
54 if err := exec.Command("git", "-C", path, "fetch", "--depth=1", "--filter=tree:0", "origin", rev).Run(); err != nil {
55 return fmt.Errorf("git pull: %w", err)
56 }
57 }
58 if err := exec.Command("git", "-C", path, "checkout", rev).Run(); err != nil {
59 return fmt.Errorf("git checkout: %w", err)
60 }
61 return nil
62}
63
64func isDir(path string) (bool, error) {
65 info, err := os.Stat(path)
66 if err == nil && info.IsDir() {
67 return true, nil
68 }
69 if os.IsNotExist(err) {
70 return false, nil
71 }
72 return false, err
73}