all repos

mugit @ 91e70b7

🐮 git server that your cow will love

mugit/internal/git/tree.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
show binary files, 3 months ago
1
package git
2
3
import (
4
	"errors"
5
	"fmt"
6
	"io"
7
	"mime"
8
	"path/filepath"
9
	"strings"
10
11
	"github.com/go-git/go-git/v5/plumbing/object"
12
)
13
14
type NiceTree struct {
15
	Name      string
16
	Mode      string
17
	Size      int64
18
	IsFile    bool
19
	IsSubtree bool
20
}
21
22
func makeNiceTree(t *object.Tree) []NiceTree {
23
	nts := []NiceTree{}
24
	for _, e := range t.Entries {
25
		mode, _ := e.Mode.ToOSFileMode()
26
		sz, _ := t.Size(e.Name)
27
		nts = append(nts, NiceTree{
28
			Name:   e.Name,
29
			Mode:   mode.String(),
30
			IsFile: e.Mode.IsFile(),
31
			Size:   sz,
32
		})
33
	}
34
	return nts
35
}
36
37
func (g *Repo) FileTree(path string) ([]NiceTree, error) {
38
	c, err := g.r.CommitObject(g.h)
39
	if err != nil {
40
		return nil, fmt.Errorf("commit object: %w", err)
41
	}
42
43
	files := []NiceTree{}
44
	tree, err := c.Tree()
45
	if err != nil {
46
		return nil, fmt.Errorf("file tree: %w", err)
47
	}
48
49
	if path == "" {
50
		files = makeNiceTree(tree)
51
	} else {
52
		o, err := tree.FindEntry(path)
53
		if err != nil {
54
			return nil, err
55
		}
56
57
		if !o.Mode.IsFile() {
58
			subtree, err := tree.Tree(path)
59
			if err != nil {
60
				return nil, err
61
			}
62
			files = makeNiceTree(subtree)
63
		}
64
	}
65
66
	return files, nil
67
}
68
69
type FileContent struct {
70
	IsBinary bool
71
	Content  []byte
72
	Mime     string
73
	Size     int64
74
}
75
76
func (fc FileContent) IsImage() bool {
77
	return strings.HasPrefix(fc.Mime, "image/")
78
}
79
80
func (fc *FileContent) String() string {
81
	if fc.IsBinary {
82
		return ""
83
	}
84
	return string(fc.Content)
85
}
86
87
func (g *Repo) FileContent(path string) (*FileContent, error) {
88
	c, err := g.r.CommitObject(g.h)
89
	if err != nil {
90
		return &FileContent{}, fmt.Errorf("commit object: %w", err)
91
	}
92
93
	tree, err := c.Tree()
94
	if err != nil {
95
		return &FileContent{}, fmt.Errorf("file tree: %w", err)
96
	}
97
98
	file, err := tree.File(path)
99
	if err != nil {
100
		if errors.Is(err, object.ErrFileNotFound) {
101
			return &FileContent{}, ErrFileNotFound
102
		}
103
		return &FileContent{}, err
104
	}
105
106
	reader, err := file.Reader()
107
	if err != nil {
108
		return nil, fmt.Errorf("file reader: %w", err)
109
	}
110
	defer reader.Close()
111
112
	content, err := io.ReadAll(reader)
113
	if err != nil {
114
		return nil, fmt.Errorf("read file: %w", err)
115
	}
116
117
	isBin, _ := file.IsBinary()
118
	mimeType := mime.TypeByExtension(filepath.Ext(path))
119
	if mimeType == "" {
120
		if isBin {
121
			mimeType = "application/octet-stream"
122
		} else {
123
			mimeType = "text/plain"
124
		}
125
	}
126
127
	return &FileContent{
128
		IsBinary: isBin,
129
		Content:  content,
130
		Mime:     mimeType,
131
		Size:     file.Size,
132
	}, nil
133
}