gitech

Форк
0
/
tree_entry.go 
181 строка · 3.9 Кб
1
// Copyright 2015 The Gogs Authors. All rights reserved.
2
// Copyright 2019 The Gitea Authors. All rights reserved.
3
// SPDX-License-Identifier: MIT
4

5
package git
6

7
import (
8
	"io"
9
	"sort"
10
	"strings"
11
)
12

13
// Type returns the type of the entry (commit, tree, blob)
14
func (te *TreeEntry) Type() string {
15
	switch te.Mode() {
16
	case EntryModeCommit:
17
		return "commit"
18
	case EntryModeTree:
19
		return "tree"
20
	default:
21
		return "blob"
22
	}
23
}
24

25
// FollowLink returns the entry pointed to by a symlink
26
func (te *TreeEntry) FollowLink() (*TreeEntry, error) {
27
	if !te.IsLink() {
28
		return nil, ErrBadLink{te.Name(), "not a symlink"}
29
	}
30

31
	// read the link
32
	r, err := te.Blob().DataAsync()
33
	if err != nil {
34
		return nil, err
35
	}
36
	closed := false
37
	defer func() {
38
		if !closed {
39
			_ = r.Close()
40
		}
41
	}()
42
	buf := make([]byte, te.Size())
43
	_, err = io.ReadFull(r, buf)
44
	if err != nil {
45
		return nil, err
46
	}
47
	_ = r.Close()
48
	closed = true
49

50
	lnk := string(buf)
51
	t := te.ptree
52

53
	// traverse up directories
54
	for ; t != nil && strings.HasPrefix(lnk, "../"); lnk = lnk[3:] {
55
		t = t.ptree
56
	}
57

58
	if t == nil {
59
		return nil, ErrBadLink{te.Name(), "points outside of repo"}
60
	}
61

62
	target, err := t.GetTreeEntryByPath(lnk)
63
	if err != nil {
64
		if IsErrNotExist(err) {
65
			return nil, ErrBadLink{te.Name(), "broken link"}
66
		}
67
		return nil, err
68
	}
69
	return target, nil
70
}
71

72
// FollowLinks returns the entry ultimately pointed to by a symlink
73
func (te *TreeEntry) FollowLinks() (*TreeEntry, error) {
74
	if !te.IsLink() {
75
		return nil, ErrBadLink{te.Name(), "not a symlink"}
76
	}
77
	entry := te
78
	for i := 0; i < 999; i++ {
79
		if entry.IsLink() {
80
			next, err := entry.FollowLink()
81
			if err != nil {
82
				return nil, err
83
			}
84
			if next.ID == entry.ID {
85
				return nil, ErrBadLink{
86
					entry.Name(),
87
					"recursive link",
88
				}
89
			}
90
			entry = next
91
		} else {
92
			break
93
		}
94
	}
95
	if entry.IsLink() {
96
		return nil, ErrBadLink{
97
			te.Name(),
98
			"too many levels of symbolic links",
99
		}
100
	}
101
	return entry, nil
102
}
103

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)
107
	if err != nil {
108
		return nil
109
	}
110
	t.ptree = te.ptree
111
	return t
112
}
113

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() {
117
		return ""
118
	}
119
	tree, err := te.ptree.SubTree(te.Name())
120
	if err != nil {
121
		return te.Name()
122
	}
123
	entries, _ := tree.ListEntries()
124
	if len(entries) == 1 && entries[0].IsDir() {
125
		name := entries[0].GetSubJumpablePathName()
126
		if name != "" {
127
			return te.Name() + "/" + name
128
		}
129
	}
130
	return te.Name()
131
}
132

133
// Entries a list of entry
134
type Entries []*TreeEntry
135

136
type customSortableEntries struct {
137
	Comparer func(s1, s2 string) bool
138
	Entries
139
}
140

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()
144
	},
145
	func(t1, t2 *TreeEntry, cmp func(s1, s2 string) bool) bool {
146
		return cmp(t1.Name(), t2.Name())
147
	},
148
}
149

150
func (ctes customSortableEntries) Len() int { return len(ctes.Entries) }
151

152
func (ctes customSortableEntries) Swap(i, j int) {
153
	ctes.Entries[i], ctes.Entries[j] = ctes.Entries[j], ctes.Entries[i]
154
}
155

156
func (ctes customSortableEntries) Less(i, j int) bool {
157
	t1, t2 := ctes.Entries[i], ctes.Entries[j]
158
	var k int
159
	for k = 0; k < len(sorter)-1; k++ {
160
		s := sorter[k]
161
		switch {
162
		case s(t1, t2, ctes.Comparer):
163
			return true
164
		case s(t2, t1, ctes.Comparer):
165
			return false
166
		}
167
	}
168
	return sorter[k](t1, t2, ctes.Comparer)
169
}
170

171
// Sort sort the list of entry
172
func (tes Entries) Sort() {
173
	sort.Sort(customSortableEntries{func(s1, s2 string) bool {
174
		return s1 < s2
175
	}, tes})
176
}
177

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})
181
}
182

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.