1package types
2
3import (
4 "fmt"
5 "os"
6 "time"
7
8 "github.com/go-git/go-git/v5/plumbing"
9 "github.com/go-git/go-git/v5/plumbing/filemode"
10)
11
12// A nicer git tree representation.
13type NiceTree struct {
14 // Relative path
15 Name string `json:"name"`
16 Mode string `json:"mode"`
17 Size int64 `json:"size"`
18
19 LastCommit *LastCommitInfo `json:"last_commit,omitempty"`
20}
21
22func (t *NiceTree) FileMode() (filemode.FileMode, error) {
23 if numericMode, err := filemode.New(t.Mode); err == nil {
24 return numericMode, nil
25 }
26
27 // TODO: this is here for backwards compat, can be removed in future versions
28 osMode, err := parseModeString(t.Mode)
29 if err != nil {
30 return filemode.Empty, nil
31 }
32
33 conv, err := filemode.NewFromOSFileMode(osMode)
34 if err != nil {
35 return filemode.Empty, nil
36 }
37
38 return conv, nil
39}
40
41// ParseFileModeString parses a file mode string like "-rw-r--r--"
42// and returns an os.FileMode
43func parseModeString(modeStr string) (os.FileMode, error) {
44 if len(modeStr) != 10 {
45 return 0, fmt.Errorf("invalid mode string length: expected 10, got %d", len(modeStr))
46 }
47
48 var mode os.FileMode
49
50 // Parse file type (first character)
51 switch modeStr[0] {
52 case 'd':
53 mode |= os.ModeDir
54 case 'l':
55 mode |= os.ModeSymlink
56 case '-':
57 // regular file
58 default:
59 return 0, fmt.Errorf("unknown file type: %c", modeStr[0])
60 }
61
62 // parse permissions for owner, group, and other
63 perms := modeStr[1:]
64 shifts := []int{6, 3, 0} // bit shifts for owner, group, other
65
66 for i := range 3 {
67 offset := i * 3
68 shift := shifts[i]
69
70 if perms[offset] == 'r' {
71 mode |= os.FileMode(4 << shift)
72 }
73 if perms[offset+1] == 'w' {
74 mode |= os.FileMode(2 << shift)
75 }
76 if perms[offset+2] == 'x' {
77 mode |= os.FileMode(1 << shift)
78 }
79 }
80
81 return mode, nil
82}
83
84func (t *NiceTree) IsFile() bool {
85 m, err := t.FileMode()
86
87 if err != nil {
88 return false
89 }
90
91 return m.IsFile()
92}
93
94func (t *NiceTree) IsSubmodule() bool {
95 m, err := t.FileMode()
96
97 if err != nil {
98 return false
99 }
100
101 return m == filemode.Submodule
102}
103
104type LastCommitInfo struct {
105 Hash plumbing.Hash
106 Message string
107 When time.Time
108}