-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathgit.go
89 lines (83 loc) · 2.47 KB
/
git.go
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
package envbuilder
import (
"context"
"errors"
"fmt"
"net/url"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/sideband"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/storage/filesystem"
)
type CloneRepoOptions struct {
Path string
Storage billy.Filesystem
RepoURL string
RepoAuth transport.AuthMethod
Progress sideband.Progress
Insecure bool
SingleBranch bool
Depth int
CABundle []byte
}
// CloneRepo will clone the repository at the given URL into the given path.
// If a repository is already initialized at the given path, it will not
// be cloned again.
//
// The bool returned states whether the repository was cloned or not.
func CloneRepo(ctx context.Context, opts CloneRepoOptions) (bool, error) {
parsed, err := url.Parse(opts.RepoURL)
if err != nil {
return false, fmt.Errorf("parse url %q: %w", opts.RepoURL, err)
}
err = opts.Storage.MkdirAll(opts.Path, 0755)
if err != nil {
return false, fmt.Errorf("mkdir %q: %w", opts.Path, err)
}
reference := parsed.Fragment
if reference == "" && opts.SingleBranch {
reference = "refs/heads/main"
}
parsed.RawFragment = ""
parsed.Fragment = ""
fs, err := opts.Storage.Chroot(opts.Path)
if err != nil {
return false, fmt.Errorf("chroot %q: %w", opts.Path, err)
}
gitDir, err := fs.Chroot(".git")
if err != nil {
return false, fmt.Errorf("chroot .git: %w", err)
}
gitStorage := filesystem.NewStorage(gitDir, cache.NewObjectLRU(cache.DefaultMaxSize*10))
fsStorage := filesystem.NewStorage(fs, cache.NewObjectLRU(cache.DefaultMaxSize*10))
repo, err := git.Open(fsStorage, gitDir)
if errors.Is(err, git.ErrRepositoryNotExists) {
err = nil
}
if err != nil {
return false, fmt.Errorf("open %q: %w", opts.RepoURL, err)
}
if repo != nil {
return false, nil
}
_, err = git.CloneContext(ctx, gitStorage, fs, &git.CloneOptions{
URL: parsed.String(),
Auth: opts.RepoAuth,
Progress: opts.Progress,
ReferenceName: plumbing.ReferenceName(reference),
InsecureSkipTLS: opts.Insecure,
Depth: opts.Depth,
SingleBranch: opts.SingleBranch,
CABundle: opts.CABundle,
})
if errors.Is(err, git.ErrRepositoryAlreadyExists) {
return false, nil
}
if err != nil {
return false, fmt.Errorf("clone %q: %w", opts.RepoURL, err)
}
return true, nil
}