Skip to content

Commit

Permalink
Avoid re-scanning directories when searching for READMEs.
Browse files Browse the repository at this point in the history
When rendering a directory's README we have scanned its Tree once,
looking for the README; but we allow READMEs in some special subfolders
too (docs/, .gitea/, .github/), and may need to scan them.

Since we've already scanned the top Tree, we have the subfolders' SHA1
object IDs cached, so, as a minor optimization, instead of calling
SubTree(path string), which re-scans the Tree before using
Repository.getTree() to actually produce their Tree objects,
call Repository.getTree() directly.

But it's a private method, so first expose it via new TreeEntry.Tree().

Feedback from @lunny: https://github.com/go-gitea/gitea/pull/22177/files#r1053953034
  • Loading branch information
user2 authored and kousu committed Dec 24, 2022
1 parent 950f54b commit b02f061
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 13 deletions.
9 changes: 9 additions & 0 deletions modules/git/tree_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ func (te *TreeEntry) FollowLinks() (*TreeEntry, error) {
return entry, nil
}

// returns the subtree, or nil if this is not a tree
func (te *TreeEntry) Tree() *Tree {
t, err := te.ptree.repo.getTree(te.ID)
if err != nil {
return nil
}
return t
}

// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
func (te *TreeEntry) GetSubJumpablePathName() string {
if te.IsSubModule() || !te.IsDir() {
Expand Down
51 changes: 38 additions & 13 deletions routers/web/repo/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,7 @@ func isReadmeFileExtension(name string, ext ...string) (int, bool) {
}

// FIXME: There has to be a more efficient way of doing this
func findReadmeFileInPath(ctx *context.Context, treePath string) (*namedBlob, error) {
tree, err := ctx.Repo.Commit.SubTree(treePath)
if err != nil {
return nil, err
}

func findReadmeFileInTree(ctx *context.Context, tree *git.Tree, searchSubtrees bool) (*namedBlob, error) {
entries, err := tree.ListEntries()
if err != nil {
return nil, err
Expand All @@ -113,8 +108,28 @@ func findReadmeFileInPath(ctx *context.Context, treePath string) (*namedBlob, er
exts := append(localizedExtensions(".md", ctx.Language()), ".txt", "") // sorted by priority
extCount := len(exts)
readmeFiles := make([]*namedBlob, extCount+1)

docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/)
for _, entry := range entries {
if entry.IsDir() {
// as a special case for the top-level repo introduction README,
// fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ...
// (note that docsEntries is ignored unless searchSubtrees)
lowerName := strings.ToLower(entry.Name())
switch lowerName {
case "docs":
if entry.Name() == "docs" || docsEntries[0] == nil {
docsEntries[0] = entry
}
case ".gitea":
if entry.Name() == ".gitea" || docsEntries[1] == nil {
docsEntries[1] = entry
}
case ".github":
if entry.Name() == ".github" || docsEntries[2] == nil {
docsEntries[2] = entry
}
}
continue
}
if i, ok := isReadmeFileExtension(entry.Name(), exts...); ok {
Expand Down Expand Up @@ -147,17 +162,23 @@ func findReadmeFileInPath(ctx *context.Context, treePath string) (*namedBlob, er
}
}

// as a special case for the top-level repo introduction README,
// fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ...
if treePath == "" && readmeFile == nil {
for _, subfolder := range []string{"docs", ".gitea", ".github"} {
if searchSubtrees && readmeFile == nil {
for _, subTreeEntry := range docsEntries {
if subTreeEntry == nil {
continue
}
subTree := subTreeEntry.Tree()
if subTree == nil {
// this should be impossible; if subTreeEntry exists so should this.
continue
}
var err error
readmeFile, err = findReadmeFileInPath(ctx, subfolder)
readmeFile, err = findReadmeFileInTree(ctx, subTree, false)
if err != nil && !git.IsErrNotExist(err) {
return nil, err
}
if readmeFile != nil {
readmeFile.name = subfolder + "/" + readmeFile.name
readmeFile.name = subTreeEntry.Name() + "/" + readmeFile.name
break
}
}
Expand Down Expand Up @@ -222,7 +243,11 @@ func localizedExtensions(ext, languageCode string) (localizedExts []string) {
}

func findReadmeFile(ctx *context.Context) (*namedBlob, error) {
readmeFile, err := findReadmeFileInPath(ctx, ctx.Repo.TreePath)
tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath)
if err != nil {
return nil, err
}
readmeFile, err := findReadmeFileInTree(ctx, tree, (ctx.Repo.TreePath == ""))
if err != nil {
return nil, err
}
Expand Down

0 comments on commit b02f061

Please sign in to comment.