1
// Copyright 2015 The Gogs Authors. All rights reserved.
2
// Copyright 2019 The Gitea Authors. All rights reserved.
3
// SPDX-License-Identifier: MIT
13
// Type returns the type of the entry (commit, tree, blob)
14
func (te *TreeEntry) Type() string {
25
// FollowLink returns the entry pointed to by a symlink
26
func (te *TreeEntry) FollowLink() (*TreeEntry, error) {
28
return nil, ErrBadLink{te.Name(), "not a symlink"}
32
r, err := te.Blob().DataAsync()
42
buf := make([]byte, te.Size())
43
_, err = io.ReadFull(r, buf)
53
// traverse up directories
54
for ; t != nil && strings.HasPrefix(lnk, "../"); lnk = lnk[3:] {
59
return nil, ErrBadLink{te.Name(), "points outside of repo"}
62
target, err := t.GetTreeEntryByPath(lnk)
64
if IsErrNotExist(err) {
65
return nil, ErrBadLink{te.Name(), "broken link"}
72
// FollowLinks returns the entry ultimately pointed to by a symlink
73
func (te *TreeEntry) FollowLinks() (*TreeEntry, error) {
75
return nil, ErrBadLink{te.Name(), "not a symlink"}
78
for i := 0; i < 999; i++ {
80
next, err := entry.FollowLink()
84
if next.ID == entry.ID {
85
return nil, ErrBadLink{
96
return nil, ErrBadLink{
98
"too many levels of symbolic links",
104
// returns the Tree pointed to by this TreeEntry, or nil if this is not a tree
105
func (te *TreeEntry) Tree() *Tree {
106
t, err := te.ptree.repo.getTree(te.ID)
114
// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
115
func (te *TreeEntry) GetSubJumpablePathName() string {
116
if te.IsSubModule() || !te.IsDir() {
119
tree, err := te.ptree.SubTree(te.Name())
123
entries, _ := tree.ListEntries()
124
if len(entries) == 1 && entries[0].IsDir() {
125
name := entries[0].GetSubJumpablePathName()
127
return te.Name() + "/" + name
133
// Entries a list of entry
134
type Entries []*TreeEntry
136
type customSortableEntries struct {
137
Comparer func(s1, s2 string) bool
141
var sorter = []func(t1, t2 *TreeEntry, cmp func(s1, s2 string) bool) bool{
142
func(t1, t2 *TreeEntry, cmp func(s1, s2 string) bool) bool {
143
return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule()
145
func(t1, t2 *TreeEntry, cmp func(s1, s2 string) bool) bool {
146
return cmp(t1.Name(), t2.Name())
150
func (ctes customSortableEntries) Len() int { return len(ctes.Entries) }
152
func (ctes customSortableEntries) Swap(i, j int) {
153
ctes.Entries[i], ctes.Entries[j] = ctes.Entries[j], ctes.Entries[i]
156
func (ctes customSortableEntries) Less(i, j int) bool {
157
t1, t2 := ctes.Entries[i], ctes.Entries[j]
159
for k = 0; k < len(sorter)-1; k++ {
162
case s(t1, t2, ctes.Comparer):
164
case s(t2, t1, ctes.Comparer):
168
return sorter[k](t1, t2, ctes.Comparer)
171
// Sort sort the list of entry
172
func (tes Entries) Sort() {
173
sort.Sort(customSortableEntries{func(s1, s2 string) bool {
178
// CustomSort customizable string comparing sort entry list
179
func (tes Entries) CustomSort(cmp func(s1, s2 string) bool) {
180
sort.Sort(customSortableEntries{cmp, tes})