1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"html/template"
"net/http"
"path"
"strings"
pull_model "code.gitea.io/gitea/models/pull"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/fileicon"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/gitdiff"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/go-enry/go-enry/v2"
)
// TreeList get all files' entries of a repository
func TreeList(ctx *context.Context) {
tree, err := ctx.Repo.Commit.SubTree("/")
if err != nil {
ctx.ServerError("Repo.Commit.SubTree", err)
return
}
entries, err := tree.ListEntriesRecursiveFast()
if err != nil {
ctx.ServerError("ListEntriesRecursiveFast", err)
return
}
entries.CustomSort(base.NaturalSortLess)
files := make([]string, 0, len(entries))
for _, entry := range entries {
if !isExcludedEntry(entry) {
files = append(files, entry.Name())
}
}
ctx.JSON(http.StatusOK, files)
}
func isExcludedEntry(entry *git.TreeEntry) bool {
if entry.IsDir() {
return true
}
if entry.IsSubModule() {
return true
}
if enry.IsVendor(entry.Name()) {
return true
}
return false
}
// WebDiffFileItem is used by frontend, check the field names in frontend before changing
type WebDiffFileItem struct {
FullName string
DisplayName string
NameHash string
DiffStatus string
EntryMode string
IsViewed bool
Children []*WebDiffFileItem
FileIcon template.HTML
}
// WebDiffFileTree is used by frontend, check the field names in frontend before changing
type WebDiffFileTree struct {
TreeRoot WebDiffFileItem
}
// transformDiffTreeForWeb transforms a gitdiff.DiffTree into a WebDiffFileTree for Web UI rendering
// it also takes a map of file names to their viewed state, which is used to mark files as viewed
func transformDiffTreeForWeb(renderedIconPool *fileicon.RenderedIconPool, diffTree *gitdiff.DiffTree, filesViewedState map[string]pull_model.ViewedState) (dft WebDiffFileTree) {
dirNodes := map[string]*WebDiffFileItem{"": &dft.TreeRoot}
addItem := func(item *WebDiffFileItem) {
var parentPath string
pos := strings.LastIndexByte(item.FullName, '/')
if pos == -1 {
item.DisplayName = item.FullName
} else {
parentPath = item.FullName[:pos]
item.DisplayName = item.FullName[pos+1:]
}
parentNode, parentExists := dirNodes[parentPath]
if !parentExists {
parentNode = &dft.TreeRoot
fields := strings.Split(parentPath, "/")
for idx, field := range fields {
nodePath := strings.Join(fields[:idx+1], "/")
node, ok := dirNodes[nodePath]
if !ok {
node = &WebDiffFileItem{EntryMode: "tree", DisplayName: field, FullName: nodePath}
dirNodes[nodePath] = node
parentNode.Children = append(parentNode.Children, node)
}
parentNode = node
}
}
parentNode.Children = append(parentNode.Children, item)
}
for _, file := range diffTree.Files {
item := &WebDiffFileItem{FullName: file.HeadPath, DiffStatus: file.Status}
item.IsViewed = filesViewedState[item.FullName] == pull_model.Viewed
item.NameHash = git.HashFilePathForWebUI(item.FullName)
item.FileIcon = fileicon.RenderEntryIconHTML(renderedIconPool, &fileicon.EntryInfo{BaseName: path.Base(file.HeadPath), EntryMode: file.HeadMode})
switch file.HeadMode {
case git.EntryModeTree:
item.EntryMode = "tree"
case git.EntryModeCommit:
item.EntryMode = "commit" // submodule
default:
// default to empty, and will be treated as "blob" file because there is no "symlink" support yet
}
addItem(item)
}
var mergeSingleDir func(node *WebDiffFileItem)
mergeSingleDir = func(node *WebDiffFileItem) {
if len(node.Children) == 1 {
if child := node.Children[0]; child.EntryMode == "tree" {
node.FullName = child.FullName
node.DisplayName = node.DisplayName + "/" + child.DisplayName
node.Children = child.Children
mergeSingleDir(node)
}
}
}
for _, node := range dft.TreeRoot.Children {
mergeSingleDir(node)
}
return dft
}
func TreeViewNodes(ctx *context.Context) {
renderedIconPool := fileicon.NewRenderedIconPool()
results, err := files_service.GetTreeViewNodes(ctx, ctx.Repo.RepoLink, renderedIconPool, ctx.Repo.Commit, ctx.Repo.TreePath, ctx.FormString("sub_path"))
if err != nil {
ctx.ServerError("GetTreeViewNodes", err)
return
}
ctx.JSON(http.StatusOK, map[string]any{"fileTreeNodes": results, "renderedIconPool": renderedIconPool.IconSVGs})
}
|