Mirror of https://git.jolheiser.com/ugit
1package git
2
3import (
4 "errors"
5 "io/fs"
6 "os"
7 "path/filepath"
8 "sort"
9
10 "github.com/dustin/go-humanize"
11 "github.com/go-git/go-git/v5"
12 "github.com/go-git/go-git/v5/plumbing"
13 "github.com/go-git/go-git/v5/plumbing/object"
14)
15
16// EnsureRepo ensures that the repo exists in the given directory
17func EnsureRepo(dir string, repo string) error {
18 exists, err := PathExists(dir)
19 if err != nil {
20 return err
21 }
22 if !exists {
23 err = os.MkdirAll(dir, os.ModeDir|os.FileMode(0o700))
24 if err != nil {
25 return err
26 }
27 }
28 rp := filepath.Join(dir, repo)
29 exists, err = PathExists(rp)
30 if err != nil {
31 return err
32 }
33 if !exists {
34 _, err := git.PlainInit(rp, true)
35 if err != nil {
36 return err
37 }
38 }
39 return nil
40}
41
42// PathExists checks if a path exists and returns true if it does
43func PathExists(path string) (bool, error) {
44 _, err := os.Stat(path)
45 if err == nil {
46 return true, nil
47 }
48 if errors.Is(err, fs.ErrNotExist) {
49 return false, nil
50 }
51 return true, err
52}
53
54// Tree returns the git tree at a given ref/rev
55func (r Repo) Tree(ref string) (*object.Tree, error) {
56 g, err := r.Git()
57 if err != nil {
58 return nil, err
59 }
60
61 hash, err := g.ResolveRevision(plumbing.Revision(ref))
62 if err != nil {
63 return nil, err
64 }
65
66 c, err := g.CommitObject(*hash)
67 if err != nil {
68 return nil, err
69 }
70
71 return c.Tree()
72}
73
74// FileInfo is the information for a file in a tree
75type FileInfo struct {
76 Path string
77 IsDir bool
78 Mode string
79 Size string
80}
81
82// Name returns the last part of the FileInfo.Path
83func (f FileInfo) Name() string {
84 return filepath.Base(f.Path)
85}
86
87// Dir returns the given dirpath in the given ref as a slice of FileInfo
88// Sorted alphabetically, dirs first
89func (r Repo) Dir(ref, path string) ([]FileInfo, error) {
90 t, err := r.Tree(ref)
91 if err != nil {
92 return nil, err
93 }
94 if path != "" {
95 t, err = t.Tree(path)
96 if err != nil {
97 return nil, err
98 }
99 }
100
101 fis := make([]FileInfo, 0, len(t.Entries))
102 for _, entry := range t.Entries {
103 fm, err := entry.Mode.ToOSFileMode()
104 if err != nil {
105 return nil, err
106 }
107 size, err := t.Size(entry.Name)
108 if err != nil {
109 return nil, err
110 }
111 fis = append(fis, FileInfo{
112 Path: filepath.Join(path, entry.Name),
113 IsDir: fm.IsDir(),
114 Mode: fm.String(),
115 Size: humanize.Bytes(uint64(size)),
116 })
117 }
118 sort.Slice(fis, func(i, j int) bool {
119 fi1 := fis[i]
120 fi2 := fis[j]
121 if fi1.IsDir != fi2.IsDir {
122 return fi1.IsDir
123 }
124 return fi1.Name() < fi2.Name()
125 })
126
127 return fis, nil
128}
129
130// GetCommitFromRef returns the commit object for a given ref
131func (r Repo) GetCommitFromRef(ref string) (*object.Commit, error) {
132 g, err := r.Git()
133 if err != nil {
134 return nil, err
135 }
136
137 hash, err := g.ResolveRevision(plumbing.Revision(ref))
138 if err != nil {
139 return nil, err
140 }
141
142 return g.CommitObject(*hash)
143}
144
145// FileContent returns the content of a file in the git tree at a given ref/rev
146func (r Repo) FileContent(ref, file string) (string, error) {
147 t, err := r.Tree(ref)
148 if err != nil {
149 return "", err
150 }
151
152 f, err := t.File(file)
153 if err != nil {
154 return "", err
155 }
156
157 content, err := f.Contents()
158 if err != nil {
159 return "", err
160 }
161
162 return content, nil
163}