Skip to content

Commit a28b65d

Browse files
committed
complete first version
1 parent b60ee86 commit a28b65d

File tree

4 files changed

+149
-29
lines changed

4 files changed

+149
-29
lines changed

routers/web/repo/tree.go

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ package repo
55

66
import (
77
"net/http"
8-
"path"
9-
"strings"
108

119
"code.gitea.io/gitea/modules/base"
1210
"code.gitea.io/gitea/modules/git"
1311
"code.gitea.io/gitea/services/context"
12+
files_service "code.gitea.io/gitea/services/repository/files"
1413

1514
"github.com/go-enry/go-enry/v2"
1615
)
@@ -55,26 +54,17 @@ func isExcludedEntry(entry *git.TreeEntry) bool {
5554
return false
5655
}
5756

58-
func getPossibleBranches(dir string) []string {
59-
cnt := strings.Count(dir, "/")
60-
branches := make([]string, cnt, cnt)
61-
for i := 0; i < cnt; i++ {
62-
branches[i] = dir
63-
dir = path.Dir(dir)
64-
}
65-
return branches
66-
}
67-
68-
func guessRefInfoAndDir(ctx *context.Context, dir string) (git.RefName, string, error) {
69-
branches := getPossibleBranches(dir)
70-
}
71-
7257
func Tree(ctx *context.Context) {
73-
pathParam := ctx.PathParam("*")
74-
dir := path.Dir(pathParam)
75-
refName, realDir, err := guessRefInfoAndDir(ctx, dir)
58+
dir := ctx.PathParam("*")
59+
ref := ctx.FormTrim("ref")
60+
recursive := ctx.FormBool("recursive")
61+
62+
// TODO: Only support branch for now
63+
results, err := files_service.GetTreeList(ctx, ctx.Repo.Repository, dir, git.RefNameFromBranch(ref), recursive)
7664
if err != nil {
7765
ctx.ServerError("guessRefInfoAndDir", err)
7866
return
7967
}
68+
69+
ctx.JSON(http.StatusOK, results)
8070
}

routers/web/repo/tree_test.go

Lines changed: 0 additions & 10 deletions
This file was deleted.

services/repository/files/tree.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ import (
77
"context"
88
"fmt"
99
"net/url"
10+
"path"
11+
"strings"
1012

1113
"code.gitea.io/gitea/models"
1214
repo_model "code.gitea.io/gitea/models/repo"
1315
"code.gitea.io/gitea/modules/git"
16+
"code.gitea.io/gitea/modules/gitrepo"
1417
"code.gitea.io/gitea/modules/setting"
1518
api "code.gitea.io/gitea/modules/structs"
1619
)
@@ -99,3 +102,92 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
99102
}
100103
return tree, nil
101104
}
105+
106+
type TreeEntry struct {
107+
Name string `json:"name"`
108+
IsFile bool `json:"isFile"`
109+
Path string `json:"path"`
110+
Children []*TreeEntry `json:"children"`
111+
}
112+
113+
func GetTreeList(ctx context.Context, repo *repo_model.Repository, treePath string, ref git.RefName, recursive bool) ([]*TreeEntry, error) {
114+
if repo.IsEmpty {
115+
return nil, nil
116+
}
117+
if ref == "" {
118+
ref = git.RefNameFromBranch(repo.DefaultBranch)
119+
}
120+
121+
// Check that the path given in opts.treePath is valid (not a git path)
122+
cleanTreePath := CleanUploadFileName(treePath)
123+
if cleanTreePath == "" && treePath != "" {
124+
return nil, models.ErrFilenameInvalid{
125+
Path: treePath,
126+
}
127+
}
128+
treePath = cleanTreePath
129+
130+
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
131+
if err != nil {
132+
return nil, err
133+
}
134+
defer closer.Close()
135+
136+
// Get the commit object for the ref
137+
commit, err := gitRepo.GetCommit(ref.String())
138+
if err != nil {
139+
return nil, err
140+
}
141+
142+
entry, err := commit.GetTreeEntryByPath(treePath)
143+
if err != nil {
144+
return nil, err
145+
}
146+
147+
// If the entry is a file, we return a FileContentResponse object
148+
if entry.Type() != "tree" {
149+
return nil, fmt.Errorf("%s is not a tree", treePath)
150+
}
151+
152+
gitTree, err := commit.SubTree(treePath)
153+
if err != nil {
154+
return nil, err
155+
}
156+
var entries git.Entries
157+
if recursive {
158+
entries, err = gitTree.ListEntriesRecursiveFast()
159+
} else {
160+
entries, err = gitTree.ListEntries()
161+
}
162+
if err != nil {
163+
return nil, err
164+
}
165+
166+
var treeList []*TreeEntry
167+
mapTree := make(map[string][]*TreeEntry)
168+
for _, e := range entries {
169+
subTreePath := path.Join(treePath, e.Name())
170+
171+
if strings.Contains(e.Name(), "/") {
172+
mapTree[path.Dir(e.Name())] = append(mapTree[path.Dir(e.Name())], &TreeEntry{
173+
Name: path.Base(e.Name()),
174+
IsFile: e.Mode() != git.EntryModeTree,
175+
Path: subTreePath,
176+
})
177+
} else {
178+
treeList = append(treeList, &TreeEntry{
179+
Name: e.Name(),
180+
IsFile: e.Mode() != git.EntryModeTree,
181+
Path: subTreePath,
182+
})
183+
}
184+
}
185+
186+
for _, tree := range treeList {
187+
if !tree.IsFile {
188+
tree.Children = mapTree[tree.Path]
189+
}
190+
}
191+
192+
return treeList, nil
193+
}

services/repository/files/tree_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"testing"
88

99
"code.gitea.io/gitea/models/unittest"
10+
"code.gitea.io/gitea/modules/git"
1011
api "code.gitea.io/gitea/modules/structs"
1112
"code.gitea.io/gitea/services/contexttest"
1213

@@ -50,3 +51,50 @@ func TestGetTreeBySHA(t *testing.T) {
5051

5152
assert.EqualValues(t, expectedTree, tree)
5253
}
54+
55+
func Test_GetTreeList(t *testing.T) {
56+
unittest.PrepareTestEnv(t)
57+
ctx1, _ := contexttest.MockContext(t, "user2/repo1")
58+
contexttest.LoadRepo(t, ctx1, 1)
59+
contexttest.LoadRepoCommit(t, ctx1)
60+
contexttest.LoadUser(t, ctx1, 2)
61+
contexttest.LoadGitRepo(t, ctx1)
62+
defer ctx1.Repo.GitRepo.Close()
63+
64+
refName := git.RefNameFromBranch(ctx1.Repo.Repository.DefaultBranch)
65+
66+
treeList, err := GetTreeList(ctx1, ctx1.Repo.Repository, "", refName, true)
67+
assert.NoError(t, err)
68+
assert.Len(t, treeList, 1)
69+
assert.EqualValues(t, "README.md", treeList[0].Name)
70+
assert.EqualValues(t, "README.md", treeList[0].Path)
71+
assert.True(t, treeList[0].IsFile)
72+
assert.Empty(t, treeList[0].Children)
73+
74+
ctx2, _ := contexttest.MockContext(t, "org3/repo3")
75+
contexttest.LoadRepo(t, ctx2, 3)
76+
contexttest.LoadRepoCommit(t, ctx2)
77+
contexttest.LoadUser(t, ctx2, 2)
78+
contexttest.LoadGitRepo(t, ctx2)
79+
defer ctx2.Repo.GitRepo.Close()
80+
81+
refName = git.RefNameFromBranch(ctx2.Repo.Repository.DefaultBranch)
82+
83+
treeList, err = GetTreeList(ctx2, ctx2.Repo.Repository, "", refName, true)
84+
assert.NoError(t, err)
85+
assert.Len(t, treeList, 2)
86+
assert.EqualValues(t, "README.md", treeList[0].Name)
87+
assert.EqualValues(t, "README.md", treeList[0].Path)
88+
assert.True(t, treeList[0].IsFile)
89+
assert.Empty(t, treeList[0].Children)
90+
91+
assert.EqualValues(t, "doc", treeList[1].Name)
92+
assert.EqualValues(t, "doc", treeList[1].Path)
93+
assert.False(t, treeList[1].IsFile)
94+
assert.Len(t, treeList[1].Children, 1)
95+
96+
assert.EqualValues(t, "doc.md", treeList[1].Children[0].Name)
97+
assert.EqualValues(t, "doc/doc.md", treeList[1].Children[0].Path)
98+
assert.True(t, treeList[1].Children[0].IsFile)
99+
assert.Empty(t, treeList[1].Children[0].Children)
100+
}

0 commit comments

Comments
 (0)