ugit/internal/git/git.go

146 lines
2.7 KiB
Go
Raw Normal View History

package git
import (
"errors"
"io/fs"
"os"
"path/filepath"
"sort"
"github.com/dustin/go-humanize"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)
// EnsureRepo ensures that the repo exists in the given directory
func EnsureRepo(dir string, repo string) error {
exists, err := PathExists(dir)
if err != nil {
return err
}
if !exists {
err = os.MkdirAll(dir, os.ModeDir|os.FileMode(0o700))
if err != nil {
return err
}
}
rp := filepath.Join(dir, repo)
exists, err = PathExists(rp)
if err != nil {
return err
}
if !exists {
_, err := git.PlainInit(rp, true)
if err != nil {
return err
}
}
return nil
}
// PathExists checks if a path exists and returns true if it does
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if errors.Is(err, fs.ErrNotExist) {
return false, nil
}
return true, err
}
// Tree returns the git tree at a given ref/rev
func (r Repo) Tree(ref string) (*object.Tree, error) {
g, err := r.Git()
if err != nil {
return nil, err
}
hash, err := g.ResolveRevision(plumbing.Revision(ref))
if err != nil {
return nil, err
}
c, err := g.CommitObject(*hash)
if err != nil {
return nil, err
}
return c.Tree()
}
// FileInfo is the information for a file in a tree
type FileInfo struct {
Path string
IsDir bool
Mode string
Size string
}
// Name returns the last part of the FileInfo.Path
func (f FileInfo) Name() string {
return filepath.Base(f.Path)
}
// Dir returns the given dirpath in the given ref as a slice of FileInfo
// Sorted alphabetically, dirs first
func (r Repo) Dir(ref, path string) ([]FileInfo, error) {
t, err := r.Tree(ref)
if err != nil {
return nil, err
}
if path != "" {
t, err = t.Tree(path)
if err != nil {
return nil, err
}
}
fis := make([]FileInfo, 0)
for _, entry := range t.Entries {
fm, err := entry.Mode.ToOSFileMode()
if err != nil {
return nil, err
}
size, err := t.Size(entry.Name)
if err != nil {
return nil, err
}
fis = append(fis, FileInfo{
Path: filepath.Join(path, entry.Name),
IsDir: fm.IsDir(),
Mode: fm.String(),
Size: humanize.Bytes(uint64(size)),
})
}
sort.Slice(fis, func(i, j int) bool {
fi1 := fis[i]
fi2 := fis[j]
return (fi1.IsDir && !fi2.IsDir) || fi1.Name() < fi2.Name()
})
return fis, nil
}
// FileContent returns the content of a file in the git tree at a given ref/rev
func (r Repo) FileContent(ref, file string) (string, error) {
t, err := r.Tree(ref)
if err != nil {
return "", err
}
f, err := t.File(file)
if err != nil {
return "", err
}
content, err := f.Contents()
if err != nil {
return "", err
}
return content, nil
}