-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgit.go
More file actions
118 lines (92 loc) · 2.72 KB
/
Copy pathgit.go
File metadata and controls
118 lines (92 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package skills
import (
"context"
"errors"
"os"
"os/exec"
"path/filepath"
"strings"
)
var ErrDefaultBranchNotFound = errors.New("default branch not found")
type clonedRepo struct {
Dir string
}
func cloneRepo(ctx context.Context, src SkillSource) (*clonedRepo, error) {
tmp, err := os.MkdirTemp("", "skills-repo-*")
if err != nil {
return nil, err
}
cleanup := func() {
_ = os.RemoveAll(tmp)
}
repoURL := normalizeRepoURL(src)
args := []string{"clone", "--depth", "1"}
if src.Ref != "" {
args = append(args, "--branch", src.Ref)
}
args = append(args, repoURL, tmp)
cmd := exec.CommandContext(ctx, "git", args...)
out, err := cmd.CombinedOutput()
if err != nil {
cleanup()
return nil, errors.New("git clone failed: " + strings.TrimSpace(string(out)))
}
return &clonedRepo{Dir: tmp}, nil
}
func normalizeRepoURL(src SkillSource) string {
repoURL := src.SourceURL
if src.Type == SkillSourceTypeGitHub && src.Owner != "" && src.Repo != "" && !strings.HasPrefix(repoURL, "http") {
repoURL = "https://github.com/" + src.Owner + "/" + src.Repo + ".git"
}
if src.Type == SkillSourceTypeGitHub && src.Owner != "" && src.Repo != "" && strings.HasPrefix(repoURL, "https://github.com/") && !strings.HasSuffix(repoURL, ".git") {
repoURL = "https://github.com/" + src.Owner + "/" + src.Repo + ".git"
}
if src.Type == SkillSourceTypeGitLab && strings.HasPrefix(repoURL, "https://gitlab.com/") && !strings.HasSuffix(repoURL, ".git") {
repoURL = repoURL + ".git"
}
return repoURL
}
func resolveCloneRef(ctx context.Context, repoURL string, requestedRef string) (string, error) {
if requestedRef != "" {
return requestedRef, nil
}
ref, err := detectDefaultBranch(ctx, repoURL)
if err != nil {
if errors.Is(err, ErrDefaultBranchNotFound) {
return "", nil
}
return "", err
}
return ref, nil
}
func detectDefaultBranch(ctx context.Context, repoURL string) (string, error) {
cmd := exec.CommandContext(ctx, "git", "ls-remote", "--symref", repoURL, "HEAD")
out, err := cmd.CombinedOutput()
if err != nil {
return "", errors.New("git ls-remote failed: " + strings.TrimSpace(string(out)))
}
for _, line := range strings.Split(string(out), "\n") {
if !strings.HasPrefix(line, "ref:") || !strings.Contains(line, "\tHEAD") {
continue
}
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}
return strings.TrimPrefix(fields[1], "refs/heads/"), nil
}
return "", ErrDefaultBranchNotFound
}
func (r *clonedRepo) ResolveSubdir(subpath string) (string, error) {
if subpath == "" {
return r.Dir, nil
}
p := filepath.Join(r.Dir, filepath.FromSlash(subpath))
if _, err := os.Stat(p); err != nil {
return "", err
}
return p, nil
}
func (r *clonedRepo) Cleanup() {
_ = os.RemoveAll(r.Dir)
}