aboutsummaryrefslogtreecommitdiffstats
path: root/services/repository/files/tree.go
diff options
context:
space:
mode:
Diffstat (limited to 'services/repository/files/tree.go')
-rw-r--r--services/repository/files/tree.go119
1 files changed, 114 insertions, 5 deletions
diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go
index 6775186afd..f2cbacbf1c 100644
--- a/services/repository/files/tree.go
+++ b/services/repository/files/tree.go
@@ -6,10 +6,16 @@ package files
import (
"context"
"fmt"
+ "html/template"
"net/url"
+ "path"
+ "sort"
+ "strings"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/fileicon"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
@@ -88,11 +94,7 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
if len(entries) > perPage {
tree.Truncated = true
}
- if rangeStart+perPage < len(entries) {
- rangeEnd = rangeStart + perPage
- } else {
- rangeEnd = len(entries)
- }
+ rangeEnd = min(rangeStart+perPage, len(entries))
tree.Entries = make([]api.GitEntry, rangeEnd-rangeStart)
for e := rangeStart; e < rangeEnd; e++ {
i := e - rangeStart
@@ -118,3 +120,110 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
}
return tree, nil
}
+
+func entryModeString(entryMode git.EntryMode) string {
+ switch entryMode {
+ case git.EntryModeBlob:
+ return "blob"
+ case git.EntryModeExec:
+ return "exec"
+ case git.EntryModeSymlink:
+ return "symlink"
+ case git.EntryModeCommit:
+ return "commit" // submodule
+ case git.EntryModeTree:
+ return "tree"
+ }
+ return "unknown"
+}
+
+type TreeViewNode struct {
+ EntryName string `json:"entryName"`
+ EntryMode string `json:"entryMode"`
+ EntryIcon template.HTML `json:"entryIcon"`
+ EntryIconOpen template.HTML `json:"entryIconOpen,omitempty"`
+
+ SymLinkedToMode string `json:"symLinkedToMode,omitempty"` // TODO: for the EntryMode="symlink"
+
+ FullPath string `json:"fullPath"`
+ SubmoduleURL string `json:"submoduleUrl,omitempty"`
+ Children []*TreeViewNode `json:"children,omitempty"`
+}
+
+func (node *TreeViewNode) sortLevel() int {
+ return util.Iif(node.EntryMode == "tree" || node.EntryMode == "commit", 0, 1)
+}
+
+func newTreeViewNodeFromEntry(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, parentDir string, entry *git.TreeEntry) *TreeViewNode {
+ node := &TreeViewNode{
+ EntryName: entry.Name(),
+ EntryMode: entryModeString(entry.Mode()),
+ FullPath: path.Join(parentDir, entry.Name()),
+ }
+
+ entryInfo := fileicon.EntryInfoFromGitTreeEntry(commit, node.FullPath, entry)
+ node.EntryIcon = fileicon.RenderEntryIconHTML(renderedIconPool, entryInfo)
+ if entryInfo.EntryMode.IsDir() {
+ entryInfo.IsOpen = true
+ node.EntryIconOpen = fileicon.RenderEntryIconHTML(renderedIconPool, entryInfo)
+ }
+
+ if node.EntryMode == "commit" {
+ if subModule, err := commit.GetSubModule(node.FullPath); err != nil {
+ log.Error("GetSubModule: %v", err)
+ } else if subModule != nil {
+ submoduleFile := git.NewCommitSubmoduleFile(subModule.URL, entry.ID.String())
+ webLink := submoduleFile.SubmoduleWebLink(ctx)
+ node.SubmoduleURL = webLink.CommitWebLink
+ }
+ }
+
+ return node
+}
+
+// sortTreeViewNodes list directory first and with alpha sequence
+func sortTreeViewNodes(nodes []*TreeViewNode) {
+ sort.Slice(nodes, func(i, j int) bool {
+ a, b := nodes[i].sortLevel(), nodes[j].sortLevel()
+ if a != b {
+ return a < b
+ }
+ return nodes[i].EntryName < nodes[j].EntryName
+ })
+}
+
+func listTreeNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, tree *git.Tree, treePath, subPath string) ([]*TreeViewNode, error) {
+ entries, err := tree.ListEntries()
+ if err != nil {
+ return nil, err
+ }
+
+ subPathDirName, subPathRemaining, _ := strings.Cut(subPath, "/")
+ nodes := make([]*TreeViewNode, 0, len(entries))
+ for _, entry := range entries {
+ node := newTreeViewNodeFromEntry(ctx, renderedIconPool, commit, treePath, entry)
+ nodes = append(nodes, node)
+ if entry.IsDir() && subPathDirName == entry.Name() {
+ subTreePath := treePath + "/" + node.EntryName
+ if subTreePath[0] == '/' {
+ subTreePath = subTreePath[1:]
+ }
+ subNodes, err := listTreeNodes(ctx, renderedIconPool, commit, entry.Tree(), subTreePath, subPathRemaining)
+ if err != nil {
+ log.Error("listTreeNodes: %v", err)
+ } else {
+ node.Children = subNodes
+ }
+ }
+ }
+ sortTreeViewNodes(nodes)
+ return nodes, nil
+}
+
+func GetTreeViewNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, treePath, subPath string) ([]*TreeViewNode, error) {
+ entry, err := commit.GetTreeEntryByPath(treePath)
+ if err != nil {
+ return nil, err
+ }
+ return listTreeNodes(ctx, renderedIconPool, commit, entry.Tree(), treePath, subPath)
+}