mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Refactor Git Attribute & performance optimization (#34154)
This PR moved git attributes related code to `modules/git/attribute` sub package and moved language stats related code to `modules/git/languagestats` sub package to make it easier to maintain. And it also introduced a performance improvement which use the `git check-attr --source` which can be run in a bare git repository so that we don't need to create a git index file. The new parameter need a git version >= 2.40 . If git version less than 2.40, it will fall back to previous implementation. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: yp05327 <576951401@qq.com>
This commit is contained in:
@@ -15,13 +15,13 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/git/languagestats"
|
||||
"code.gitea.io/gitea/modules/highlight"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
)
|
||||
|
||||
type blameRow struct {
|
||||
@@ -234,7 +234,7 @@ func processBlameParts(ctx *context.Context, blameParts []*git.BlamePart) map[st
|
||||
func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames map[string]*user_model.UserCommit) {
|
||||
repoLink := ctx.Repo.RepoLink
|
||||
|
||||
language, err := files_service.TryGetContentLanguage(ctx.Repo.GitRepo, ctx.Repo.CommitID, ctx.Repo.TreePath)
|
||||
language, err := languagestats.GetFileLanguage(ctx, ctx.Repo.GitRepo, ctx.Repo.CommitID, ctx.Repo.TreePath)
|
||||
if err != nil {
|
||||
log.Error("Unable to get file language for %-v:%s. Error: %v", ctx.Repo.Repository, ctx.Repo.TreePath, err)
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/git/attribute"
|
||||
"code.gitea.io/gitea/modules/git/pipeline"
|
||||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@@ -134,39 +135,24 @@ func LFSLocks(ctx *context.Context) {
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
filenames := make([]string, len(lfsLocks))
|
||||
|
||||
for i, lock := range lfsLocks {
|
||||
filenames[i] = lock.Path
|
||||
}
|
||||
|
||||
if err := gitRepo.ReadTreeToIndex(ctx.Repo.Repository.DefaultBranch); err != nil {
|
||||
log.Error("Unable to read the default branch to the index: %s (%v)", ctx.Repo.Repository.DefaultBranch, err)
|
||||
ctx.ServerError("LFSLocks", fmt.Errorf("unable to read the default branch to the index: %s (%w)", ctx.Repo.Repository.DefaultBranch, err))
|
||||
return
|
||||
}
|
||||
|
||||
name2attribute2info, err := gitRepo.CheckAttribute(git.CheckAttributeOpts{
|
||||
Attributes: []string{"lockable"},
|
||||
Filenames: filenames,
|
||||
CachedOnly: true,
|
||||
})
|
||||
checker, err := attribute.NewBatchChecker(gitRepo, ctx.Repo.Repository.DefaultBranch, []string{attribute.Lockable})
|
||||
if err != nil {
|
||||
log.Error("Unable to check attributes in %s (%v)", tmpBasePath, err)
|
||||
ctx.ServerError("LFSLocks", err)
|
||||
return
|
||||
}
|
||||
defer checker.Close()
|
||||
|
||||
lockables := make([]bool, len(lfsLocks))
|
||||
filenames := make([]string, len(lfsLocks))
|
||||
for i, lock := range lfsLocks {
|
||||
attribute2info, has := name2attribute2info[lock.Path]
|
||||
if !has {
|
||||
filenames[i] = lock.Path
|
||||
attrs, err := checker.CheckPath(lock.Path)
|
||||
if err != nil {
|
||||
log.Error("Unable to check attributes in %s: %s (%v)", tmpBasePath, lock.Path, err)
|
||||
continue
|
||||
}
|
||||
if attribute2info["lockable"] != "set" {
|
||||
continue
|
||||
}
|
||||
lockables[i] = true
|
||||
lockables[i] = attrs.Get(attribute.Lockable).ToBool().Value()
|
||||
}
|
||||
ctx.Data["Lockables"] = lockables
|
||||
|
||||
|
@@ -18,6 +18,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/actions"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/git/attribute"
|
||||
"code.gitea.io/gitea/modules/highlight"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
@@ -25,7 +26,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
||||
"github.com/nektos/act/pkg/model"
|
||||
)
|
||||
@@ -147,6 +147,23 @@ func prepareToRenderFile(ctx *context.Context, entry *git.TreeEntry) {
|
||||
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.cannot_edit_non_text_files")
|
||||
}
|
||||
|
||||
// read all needed attributes which will be used later
|
||||
// there should be no performance different between reading 2 or 4 here
|
||||
attrsMap, err := attribute.CheckAttributes(ctx, ctx.Repo.GitRepo, ctx.Repo.CommitID, attribute.CheckAttributeOpts{
|
||||
Filenames: []string{ctx.Repo.TreePath},
|
||||
Attributes: []string{attribute.LinguistGenerated, attribute.LinguistVendored, attribute.LinguistLanguage, attribute.GitlabLanguage},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("attribute.CheckAttributes", err)
|
||||
return
|
||||
}
|
||||
attrs := attrsMap[ctx.Repo.TreePath]
|
||||
if attrs == nil {
|
||||
// this case shouldn't happen, just in case.
|
||||
setting.PanicInDevOrTesting("no attributes found for %s", ctx.Repo.TreePath)
|
||||
attrs = attribute.NewAttributes()
|
||||
}
|
||||
|
||||
switch {
|
||||
case isRepresentableAsText:
|
||||
if fInfo.fileSize >= setting.UI.MaxDisplayFileSize {
|
||||
@@ -209,11 +226,7 @@ func prepareToRenderFile(ctx *context.Context, entry *git.TreeEntry) {
|
||||
ctx.Data["NumLines"] = bytes.Count(buf, []byte{'\n'}) + 1
|
||||
}
|
||||
|
||||
language, err := files_service.TryGetContentLanguage(ctx.Repo.GitRepo, ctx.Repo.CommitID, ctx.Repo.TreePath)
|
||||
if err != nil {
|
||||
log.Error("Unable to get file language for %-v:%s. Error: %v", ctx.Repo.Repository, ctx.Repo.TreePath, err)
|
||||
}
|
||||
|
||||
language := attrs.GetLanguage().Value()
|
||||
fileContent, lexerName, err := highlight.File(blob.Name(), language, buf)
|
||||
ctx.Data["LexerName"] = lexerName
|
||||
if err != nil {
|
||||
@@ -283,17 +296,7 @@ func prepareToRenderFile(ctx *context.Context, entry *git.TreeEntry) {
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
checker, deferable := ctx.Repo.GitRepo.CheckAttributeReader(ctx.Repo.CommitID)
|
||||
if checker != nil {
|
||||
defer deferable()
|
||||
attrs, err := checker.CheckPath(ctx.Repo.TreePath)
|
||||
if err == nil {
|
||||
ctx.Data["IsVendored"] = git.AttributeToBool(attrs, git.AttributeLinguistVendored).Value()
|
||||
ctx.Data["IsGenerated"] = git.AttributeToBool(attrs, git.AttributeLinguistGenerated).Value()
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.Data["IsVendored"], ctx.Data["IsGenerated"] = attrs.GetVendored().Value(), attrs.GetGenerated().Value()
|
||||
|
||||
if fInfo.st.IsImage() && !fInfo.st.IsSvgImage() {
|
||||
img, _, err := image.DecodeConfig(bytes.NewReader(buf))
|
||||
|
Reference in New Issue
Block a user