-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit.go
100 lines (80 loc) · 1.75 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
90
91
92
93
94
95
96
97
98
99
100
package git
import (
"errors"
"fmt"
"os"
"path/filepath"
)
type (
Git struct {
dataRoot string // project folder
gitRoot string // git folder
}
)
var (
ErrNotGit = errors.New("not in git repository")
ErrBadGit = errors.New("invalid gitfile format")
)
func Init(root string) (*Git, error) {
for _, dir := range []string{".git", ".git/objects", ".git/refs"} {
full := filepath.Join(root, dir)
err := os.MkdirAll(full, 0755)
if err != nil {
return nil, err // os package wraps error for us, so we shouldn't
}
}
headFileContents := []byte("ref: refs/heads/master\n")
if err := os.WriteFile(".git/HEAD", headFileContents, 0644); err != nil {
return nil, fmt.Errorf("write %s: %w", ".git/HEAD", err)
}
return &Git{
dataRoot: root,
gitRoot: filepath.Join(root, ".git"),
}, nil
}
func Find(path string) (*Git, error) {
path, err := filepath.Abs(path)
if err != nil {
return nil, err
}
for p := path; ; p = filepath.Dir(p) {
err := checkGitDir(p)
if os.IsNotExist(err) {
if p == "/" {
break
}
continue
}
if err != nil {
return nil, err
}
return &Git{
dataRoot: p,
gitRoot: filepath.Join(p, ".git"),
}, nil
}
return nil, ErrNotGit
}
func checkGitDir(path string) error {
gitPath := filepath.Join(path, ".git")
inf, err := os.Stat(gitPath)
if os.IsNotExist(err) {
return err
}
if !inf.IsDir() {
return ErrBadGit
}
ok := checkDirExists(filepath.Join(gitPath, "objects"))
if !ok {
return fmt.Errorf("%w: no %v folder", ErrBadGit, "objects")
}
ok = checkDirExists(filepath.Join(gitPath, "refs"))
if !ok {
return fmt.Errorf("%w: no %v folder", ErrBadGit, "refs")
}
return nil
}
func checkDirExists(path string) bool {
inf, err := os.Stat(path)
return err == nil && inf.IsDir()
}