all repos

mugit @ 4ca522b

🐮 git server that your cow will love

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

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