refactor: decouple git.Repository(ctx) from git.Commit & git.Tree (#38464)

1. Storing "ctx" in a long-living object is wrong
2. Make the commit & tree cacheable (for the future performance
optimization)
3. Also fix some bad designs like `// FIXME: bad design, this field can
be nil if the commit is from "last commit cache"`

ref:
* #33893
This commit is contained in:
wxiaoguang
2026-07-16 01:30:01 +08:00
committed by GitHub
parent ed678b9d45
commit 82edc3da01
115 changed files with 732 additions and 864 deletions
+7 -5
View File
@@ -4,6 +4,8 @@
package actions package actions
import ( import (
"context"
"gitea.dev/modules/actions/jobparser" "gitea.dev/modules/actions/jobparser"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/log" "gitea.dev/modules/log"
@@ -13,8 +15,8 @@ import (
) )
// ListScopedWorkflows lists scoped workflow files (under SCOPED_WORKFLOW_DIRS) at the given commit. // ListScopedWorkflows lists scoped workflow files (under SCOPED_WORKFLOW_DIRS) at the given commit.
func ListScopedWorkflows(commit *git.Commit) (string, git.Entries, error) { func ListScopedWorkflows(ctx context.Context, gitRepo *git.Repository, commit *git.Commit) (string, git.Entries, error) {
return listWorkflowsInDirs(commit, setting.Actions.ScopedWorkflowDirs) return listWorkflowsInDirs(ctx, gitRepo, commit, setting.Actions.ScopedWorkflowDirs)
} }
// ParsedScopedWorkflow is one scoped workflow's source-side parse result // ParsedScopedWorkflow is one scoped workflow's source-side parse result
@@ -26,15 +28,15 @@ type ParsedScopedWorkflow struct {
} }
// ParseScopedWorkflows lists and parses the scoped workflow files at sourceCommit (under SCOPED_WORKFLOW_DIRS). // ParseScopedWorkflows lists and parses the scoped workflow files at sourceCommit (under SCOPED_WORKFLOW_DIRS).
func ParseScopedWorkflows(sourceCommit *git.Commit) ([]*ParsedScopedWorkflow, error) { func ParseScopedWorkflows(ctx context.Context, gitRepo *git.Repository, sourceCommit *git.Commit) ([]*ParsedScopedWorkflow, error) {
_, entries, err := ListScopedWorkflows(sourceCommit) _, entries, err := ListScopedWorkflows(ctx, gitRepo, sourceCommit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
parsed := make([]*ParsedScopedWorkflow, 0, len(entries)) parsed := make([]*ParsedScopedWorkflow, 0, len(entries))
for _, entry := range entries { for _, entry := range entries {
content, err := GetContentFromEntry(entry) content, err := GetContentFromEntry(gitRepo, entry)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+20 -18
View File
@@ -5,6 +5,7 @@ package actions
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"path" "path"
"slices" "slices"
@@ -69,16 +70,16 @@ func isWorkflowInDirs(path string, dirs []string) bool {
return false return false
} }
func ListWorkflows(commit *git.Commit) (string, git.Entries, error) { func ListWorkflows(ctx context.Context, gitRepo *git.Repository, commit *git.Commit) (string, git.Entries, error) {
return listWorkflowsInDirs(commit, setting.Actions.WorkflowDirs) return listWorkflowsInDirs(ctx, gitRepo, commit, setting.Actions.WorkflowDirs)
} }
func listWorkflowsInDirs(commit *git.Commit, dirs []string) (string, git.Entries, error) { func listWorkflowsInDirs(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, dirs []string) (string, git.Entries, error) {
var tree *git.Tree var tree *git.Tree
var err error var err error
var workflowDir string var workflowDir string
for _, workflowDir = range dirs { for _, workflowDir = range dirs {
tree, err = commit.SubTree(workflowDir) tree, err = commit.SubTree(ctx, gitRepo, workflowDir)
if err == nil { if err == nil {
break break
} }
@@ -90,7 +91,7 @@ func listWorkflowsInDirs(commit *git.Commit, dirs []string) (string, git.Entries
return "", nil, nil return "", nil, nil
} }
entries, err := tree.ListEntriesRecursiveFast() entries, err := tree.ListEntriesRecursiveFast(ctx, gitRepo)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
@@ -104,8 +105,8 @@ func listWorkflowsInDirs(commit *git.Commit, dirs []string) (string, git.Entries
return workflowDir, ret, nil return workflowDir, ret, nil
} }
func GetContentFromEntry(entry *git.TreeEntry) ([]byte, error) { func GetContentFromEntry(gitRepo *git.Repository, entry *git.TreeEntry) ([]byte, error) {
f, err := entry.Blob().DataAsync() f, err := entry.Blob(gitRepo).DataAsync()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -175,19 +176,20 @@ func ShouldEventCreateCommitStatus(event string) bool {
} }
func DetectWorkflows( func DetectWorkflows(
ctx context.Context,
gitRepo *git.Repository, gitRepo *git.Repository,
commit *git.Commit, commit *git.Commit,
triggedEvent webhook_module.HookEventType, triggedEvent webhook_module.HookEventType,
payload api.Payloader, payload api.Payloader,
detectSchedule bool, detectSchedule bool,
) (workflows, schedules, filtered []*DetectedWorkflow, err error) { ) (workflows, schedules, filtered []*DetectedWorkflow, err error) {
_, entries, err := ListWorkflows(commit) _, entries, err := ListWorkflows(ctx, gitRepo, commit)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
for _, entry := range entries { for _, entry := range entries {
content, err := GetContentFromEntry(entry) content, err := GetContentFromEntry(gitRepo, entry)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
@@ -229,15 +231,15 @@ func DetectWorkflows(
return workflows, schedules, filtered, nil return workflows, schedules, filtered, nil
} }
func DetectScheduledWorkflows(gitRepo *git.Repository, commit *git.Commit) ([]*DetectedWorkflow, error) { func DetectScheduledWorkflows(ctx context.Context, gitRepo *git.Repository, commit *git.Commit) ([]*DetectedWorkflow, error) {
_, entries, err := ListWorkflows(commit) _, entries, err := ListWorkflows(ctx, gitRepo, commit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
wfs := make([]*DetectedWorkflow, 0, len(entries)) wfs := make([]*DetectedWorkflow, 0, len(entries))
for _, entry := range entries { for _, entry := range entries {
content, err := GetContentFromEntry(entry) content, err := GetContentFromEntry(gitRepo, entry)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -284,7 +286,7 @@ func detectWorkflowMatch(gitRepo *git.Repository, commit *git.Commit, triggedEve
case // push case // push
webhook_module.HookEventPush: webhook_module.HookEventPush:
return matchPushEvent(commit, payload.(*api.PushPayload), evt) return matchPushEvent(gitRepo, commit, payload.(*api.PushPayload), evt)
case // issues case // issues
webhook_module.HookEventIssues, webhook_module.HookEventIssues,
@@ -357,7 +359,7 @@ func detectWorkflowMatch(gitRepo *git.Repository, commit *git.Commit, triggedEve
} }
} }
func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) detectResult { func matchPushEvent(gitRepo *git.Repository, commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) detectResult {
// with no special filter parameters // with no special filter parameters
if len(evt.Acts()) == 0 { if len(evt.Acts()) == 0 {
return detectMatched return detectMatched
@@ -423,7 +425,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
matchTimes++ matchTimes++
break break
} }
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before) filesChanged, err := commit.GetFilesChangedSinceCommit(gitRepo, pushPayload.Before)
if err != nil { if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err) log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
return detectNotApplicable return detectNotApplicable
@@ -440,7 +442,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
matchTimes++ matchTimes++
break break
} }
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before) filesChanged, err := commit.GetFilesChangedSinceCommit(gitRepo, pushPayload.Before)
if err != nil { if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err) log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
return detectNotApplicable return detectNotApplicable
@@ -590,7 +592,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
matchTimes++ matchTimes++
} }
case "paths": case "paths":
filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.MergeBase) filesChanged, err := headCommit.GetFilesChangedSinceCommit(gitRepo, prPayload.PullRequest.MergeBase)
if err != nil { if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err) log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
return detectNotApplicable return detectNotApplicable
@@ -603,7 +605,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
matchTimes++ matchTimes++
} }
case "paths-ignore": case "paths-ignore":
filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.MergeBase) filesChanged, err := headCommit.GetFilesChangedSinceCommit(gitRepo, prPayload.PullRequest.MergeBase)
if err != nil { if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err) log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
return detectNotApplicable return detectNotApplicable
+7 -3
View File
@@ -3,7 +3,11 @@
package fileicon package fileicon
import "gitea.dev/modules/git" import (
"context"
"gitea.dev/modules/git"
)
type EntryInfo struct { type EntryInfo struct {
BaseName string BaseName string
@@ -12,10 +16,10 @@ type EntryInfo struct {
IsOpen bool IsOpen bool
} }
func EntryInfoFromGitTreeEntry(commit *git.Commit, fullPath string, gitEntry *git.TreeEntry) *EntryInfo { func EntryInfoFromGitTreeEntry(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, fullPath string, gitEntry *git.TreeEntry) *EntryInfo {
ret := &EntryInfo{BaseName: gitEntry.Name(), EntryMode: gitEntry.Mode()} ret := &EntryInfo{BaseName: gitEntry.Name(), EntryMode: gitEntry.Mode()}
if gitEntry.IsLink() { if gitEntry.IsLink() {
if res, err := git.EntryFollowLink(commit, fullPath, gitEntry); err == nil && res.TargetEntry.IsDir() { if res, err := git.EntryFollowLink(ctx, gitRepo, commit, fullPath, gitEntry); err == nil && res.TargetEntry.IsDir() {
ret.SymlinkToMode = res.TargetEntry.Mode() ret.SymlinkToMode = res.TargetEntry.Mode()
} }
} }
+52 -43
View File
@@ -17,17 +17,17 @@ import (
// Commit represents a git commit. // Commit represents a git commit.
type Commit struct { type Commit struct {
Tree // FIXME: bad design, this field can be nil if the commit is from "last commit cache"
CommitMessage CommitMessage
ID ObjectID ID ObjectID
TreeID ObjectID
Parents []ObjectID
Author *Signature // never nil Author *Signature // never nil
Committer *Signature // never nil Committer *Signature // never nil
Signature *CommitSignature Signature *CommitSignature
Parents []ObjectID // ID strings
submoduleCache *ObjectCache[*SubModule] submoduleCache *ObjectCache[*SubModule]
treeCache *Tree
} }
// CommitSignature represents a git commit signature part. // CommitSignature represents a git commit signature part.
@@ -46,12 +46,12 @@ func (c *Commit) ParentID(n int) (ObjectID, error) {
} }
// Parent returns n-th parent (0-based index) of the commit. // Parent returns n-th parent (0-based index) of the commit.
func (c *Commit) Parent(n int) (*Commit, error) { func (c *Commit) Parent(gitRepo *Repository, n int) (*Commit, error) {
id, err := c.ParentID(n) id, err := c.ParentID(n)
if err != nil { if err != nil {
return nil, err return nil, err
} }
parent, err := c.repo.getCommit(id) parent, err := gitRepo.getCommit(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -65,25 +65,44 @@ func (c *Commit) ParentCount() int {
} }
// GetCommitByPath return the commit of relative path object. // GetCommitByPath return the commit of relative path object.
func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) { func (c *Commit) GetCommitByPath(gitRepo *Repository, relpath string) (*Commit, error) {
if c.repo.LastCommitCache != nil { if gitRepo.LastCommitCache != nil {
return c.repo.LastCommitCache.GetCommitByPath(c.ID.String(), relpath) return gitRepo.LastCommitCache.GetCommitByPath(c.ID.String(), relpath)
} }
return c.repo.getCommitByPathWithID(c.ID, relpath) return gitRepo.getCommitByPathWithID(c.ID, relpath)
}
func (c *Commit) Tree() *Tree {
if c.treeCache == nil {
c.treeCache = newTree(c.TreeID)
}
return c.treeCache
}
func (c *Commit) GetBlobByPath(ctx context.Context, gitRepo *Repository, relpath string) (*Blob, error) {
return c.Tree().GetBlobByPath(ctx, gitRepo, relpath)
}
func (c *Commit) GetTreeEntryByPath(ctx context.Context, gitRepo *Repository, relpath string) (_ *TreeEntry, err error) {
return c.Tree().GetTreeEntryByPath(ctx, gitRepo, relpath)
}
func (c *Commit) SubTree(ctx context.Context, gitRepo *Repository, relpath string) (*Tree, error) {
return c.Tree().SubTree(ctx, gitRepo, relpath)
} }
// CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize // CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize
func (c *Commit) CommitsByRange(page, pageSize int, not, since, until string) ([]*Commit, error) { func (c *Commit) CommitsByRange(gitRepo *Repository, page, pageSize int, not, since, until string) ([]*Commit, error) {
return c.repo.commitsByRangeWithTime(c.ID, page, pageSize, not, since, until) return gitRepo.commitsByRangeWithTime(c.ID, page, pageSize, not, since, until)
} }
// CommitsBefore returns all the commits before current revision // CommitsBefore returns all the commits before current revision
func (c *Commit) CommitsBefore() ([]*Commit, error) { func (c *Commit) CommitsBefore(gitRepo *Repository) ([]*Commit, error) {
return c.repo.getCommitsBefore(c.ID) return gitRepo.getCommitsBefore(c.ID)
} }
// HasPreviousCommit returns true if a given commitHash is contained in commit's parents // HasPreviousCommit returns true if a given commitHash is contained in commit's parents
func (c *Commit) HasPreviousCommit(objectID ObjectID) (bool, error) { func (c *Commit) HasPreviousCommit(ctx context.Context, gitRepo *Repository, objectID ObjectID) (bool, error) {
this := c.ID.String() this := c.ID.String()
that := objectID.String() that := objectID.String()
@@ -93,8 +112,8 @@ func (c *Commit) HasPreviousCommit(objectID ObjectID) (bool, error) {
_, _, err := gitcmd.NewCommand("merge-base", "--is-ancestor"). _, _, err := gitcmd.NewCommand("merge-base", "--is-ancestor").
AddDynamicArguments(that, this). AddDynamicArguments(that, this).
WithDir(c.repo.Path). WithDir(gitRepo.Path).
RunStdString(c.repo.Ctx) RunStdString(ctx)
if err == nil { if err == nil {
return true, nil return true, nil
} }
@@ -108,8 +127,8 @@ func (c *Commit) HasPreviousCommit(objectID ObjectID) (bool, error) {
} }
// IsForcePush returns true if a push from oldCommitHash to this is a force push // IsForcePush returns true if a push from oldCommitHash to this is a force push
func (c *Commit) IsForcePush(oldCommitID string) (bool, error) { func (c *Commit) IsForcePush(ctx context.Context, gitRepo *Repository, oldCommitID string) (bool, error) {
objectFormat, err := c.repo.GetObjectFormat() objectFormat, err := gitRepo.GetObjectFormat()
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -117,22 +136,22 @@ func (c *Commit) IsForcePush(oldCommitID string) (bool, error) {
return false, nil return false, nil
} }
oldCommit, err := c.repo.GetCommit(oldCommitID) oldCommit, err := gitRepo.GetCommit(oldCommitID)
if err != nil { if err != nil {
return false, err return false, err
} }
hasPreviousCommit, err := c.HasPreviousCommit(oldCommit.ID) hasPreviousCommit, err := c.HasPreviousCommit(ctx, gitRepo, oldCommit.ID)
return !hasPreviousCommit, err return !hasPreviousCommit, err
} }
// CommitsBeforeLimit returns num commits before current revision // CommitsBeforeLimit returns num commits before current revision
func (c *Commit) CommitsBeforeLimit(num int) ([]*Commit, error) { func (c *Commit) CommitsBeforeLimit(gitRepo *Repository, num int) ([]*Commit, error) {
return c.repo.getCommitsBeforeLimit(c.ID, num) return gitRepo.getCommitsBeforeLimit(c.ID, num)
} }
// CommitsBeforeUntil returns the commits in range "[cur, ref)" // CommitsBeforeUntil returns the commits in range "[cur, ref)"
func (c *Commit) CommitsBeforeUntil(ref RefName) ([]*Commit, error) { func (c *Commit) CommitsBeforeUntil(gitRepo *Repository, ref RefName) ([]*Commit, error) {
return c.repo.CommitsBetween(c.ID.RefName(), ref, -1) return gitRepo.CommitsBetween(c.ID.RefName(), ref, -1)
} }
// SearchCommitsOptions specify the parameters for SearchCommits // SearchCommitsOptions specify the parameters for SearchCommits
@@ -175,39 +194,29 @@ func NewSearchCommitsOptions(searchString string, forAllRefs bool) SearchCommits
} }
// SearchCommits returns the commits match the keyword before current revision // SearchCommits returns the commits match the keyword before current revision
func (c *Commit) SearchCommits(opts SearchCommitsOptions) ([]*Commit, error) { func (c *Commit) SearchCommits(gitRepo *Repository, opts SearchCommitsOptions) ([]*Commit, error) {
return c.repo.searchCommits(c.ID, opts) return gitRepo.searchCommits(c.ID, opts)
} }
// GetFilesChangedSinceCommit get all changed file names between pastCommit to current revision // GetFilesChangedSinceCommit get all changed file names between pastCommit to current revision
func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) { func (c *Commit) GetFilesChangedSinceCommit(gitRepo *Repository, pastCommit string) ([]string, error) {
return c.repo.GetFilesChangedBetween(pastCommit, c.ID.String()) return gitRepo.GetFilesChangedBetween(pastCommit, c.ID.String())
} }
// FileChangedSinceCommit Returns true if the file given has changed since the past commit // FileChangedSinceCommit Returns true if the file given has changed since the past commit
// YOU MUST ENSURE THAT pastCommit is a valid commit ID. // YOU MUST ENSURE THAT pastCommit is a valid commit ID.
func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, error) { func (c *Commit) FileChangedSinceCommit(gitRepo *Repository, filename, pastCommit string) (bool, error) {
return c.repo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String()) return gitRepo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String())
}
// HasFile returns true if the file given exists on this commit
// This does only mean it's there - it does not mean the file was changed during the commit.
func (c *Commit) HasFile(filename string) (bool, error) {
_, err := c.GetBlobByPath(filename)
if err != nil {
return false, err
}
return true, nil
} }
// GetFileContent reads a file content as a string or returns false if this was not possible // GetFileContent reads a file content as a string or returns false if this was not possible
func (c *Commit) GetFileContent(filename string, limit int) (string, error) { func (c *Commit) GetFileContent(ctx context.Context, gitRepo *Repository, filename string, limit int) (string, error) {
entry, err := c.GetTreeEntryByPath(filename) entry, err := c.GetTreeEntryByPath(ctx, gitRepo, filename)
if err != nil { if err != nil {
return "", err return "", err
} }
r, err := entry.Blob().DataAsync() r, err := entry.Blob(gitRepo).DataAsync()
if err != nil { if err != nil {
return "", err return "", err
} }
+4 -2
View File
@@ -3,6 +3,8 @@
package git package git
import "context"
// CommitInfo describes the first commit with the provided entry // CommitInfo describes the first commit with the provided entry
type CommitInfo struct { type CommitInfo struct {
Entry *TreeEntry Entry *TreeEntry
@@ -10,8 +12,8 @@ type CommitInfo struct {
SubmoduleFile *CommitSubmoduleFile SubmoduleFile *CommitSubmoduleFile
} }
func GetCommitInfoSubmoduleFile(repoLink, fullPath string, commit *Commit, refCommitID ObjectID) (*CommitSubmoduleFile, error) { func GetCommitInfoSubmoduleFile(ctx context.Context, repoLink, fullPath string, gitRepo *Repository, commit *Commit, refCommitID ObjectID) (*CommitSubmoduleFile, error) {
submodule, err := commit.GetSubModule(fullPath) submodule, err := commit.GetSubModule(ctx, gitRepo, fullPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+25 -22
View File
@@ -17,7 +17,7 @@ import (
) )
// GetCommitsInfo gets information of all commits that are corresponding to these entries // GetCommitsInfo gets information of all commits that are corresponding to these entries
func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) { func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, gitRepo *Repository, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1) entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself // Get the commit for the treePath itself
entryPaths[0] = "" entryPaths[0] = ""
@@ -25,25 +25,16 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
entryPaths[i+1] = entry.Name() entryPaths[i+1] = entry.Name()
} }
commitNodeIndex, commitGraphFile := commit.repo.CommitNodeIndex()
if commitGraphFile != nil {
defer commitGraphFile.Close()
}
c, err := commitNodeIndex.Get(plumbing.Hash(commit.ID.RawValue()))
if err != nil {
return nil, nil, err
}
var revs map[string]*Commit var revs map[string]*Commit
if commit.repo.LastCommitCache != nil { var err error
if gitRepo.LastCommitCache != nil {
var unHitPaths []string var unHitPaths []string
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache) revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, gitRepo.LastCommitCache)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if len(unHitPaths) > 0 { if len(unHitPaths) > 0 {
revs2, err := GetLastCommitForPaths(ctx, commit.repo.LastCommitCache, c, treePath, unHitPaths) revs2, err := GetLastCommitForPaths(ctx, gitRepo, commit, treePath, unHitPaths)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -51,13 +42,13 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
maps.Copy(revs, revs2) maps.Copy(revs, revs2)
} }
} else { } else {
revs, err = GetLastCommitForPaths(ctx, nil, c, treePath, entryPaths) revs, err = GetLastCommitForPaths(ctx, gitRepo, commit, treePath, entryPaths)
} }
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
commit.repo.gogitStorage.Close() gitRepo.gogitStorage.Close()
commitsInfo := make([]CommitInfo, len(tes)) commitsInfo := make([]CommitInfo, len(tes))
for i, entry := range tes { for i, entry := range tes {
@@ -72,7 +63,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// If the entry is a submodule, add a submodule file for this // If the entry is a submodule, add a submodule file for this
if entry.IsSubModule() { if entry.IsSubModule() {
commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(repoLink, path.Join(treePath, entry.Name()), commit, entry.ID) commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(ctx, repoLink, path.Join(treePath, entry.Name()), gitRepo, commit, entry.ID)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -83,11 +74,10 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// get it for free during the tree traversal and it's used for listing // get it for free during the tree traversal and it's used for listing
// pages to display information about newest commit for a given path. // pages to display information about newest commit for a given path.
var treeCommit *Commit var treeCommit *Commit
var ok bool
if treePath == "" { if treePath == "" {
treeCommit = commit treeCommit = commit
} else if treeCommit, ok = revs[""]; ok { } else {
treeCommit.repo = commit.repo treeCommit = revs[""]
} }
return commitsInfo, treeCommit, nil return commitsInfo, treeCommit, nil
} }
@@ -162,7 +152,20 @@ func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cac
} }
// GetLastCommitForPaths returns last commit information // GetLastCommitForPaths returns last commit information
func GetLastCommitForPaths(ctx context.Context, cache *LastCommitCache, c cgobject.CommitNode, treePath string, paths []string) (map[string]*Commit, error) { func GetLastCommitForPaths(ctx context.Context, gitRepo *Repository, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) {
commitNodeIndex, commitGraphFile := gitRepo.CommitNodeIndex()
if commitGraphFile != nil {
defer commitGraphFile.Close()
}
c, err := commitNodeIndex.Get(plumbing.Hash(commit.ID.RawValue()))
if err != nil {
return nil, err
}
return getLastCommitForPathsByCommitNode(ctx, gitRepo, c, treePath, paths)
}
func getLastCommitForPathsByCommitNode(ctx context.Context, gitRepo *Repository, c cgobject.CommitNode, treePath string, paths []string) (map[string]*Commit, error) {
refSha := c.ID().String() refSha := c.ID().String()
// We do a tree traversal with nodes sorted by commit time // We do a tree traversal with nodes sorted by commit time
@@ -243,7 +246,7 @@ heaploop:
// match any of the hashes being merged. This is more common for directories, // match any of the hashes being merged. This is more common for directories,
// but it can also happen if a file is changed through conflict resolution. // but it can also happen if a file is changed through conflict resolution.
resultNodes[pth] = current.commit resultNodes[pth] = current.commit
if err := cache.Put(refSha, path.Join(treePath, pth), current.commit.ID().String()); err != nil { if err := gitRepo.LastCommitCache.Put(refSha, path.Join(treePath, pth), current.commit.ID().String()); err != nil {
return nil, err return nil, err
} }
} }
+11 -12
View File
@@ -15,7 +15,7 @@ import (
) )
// GetCommitsInfo gets information of all commits that are corresponding to these entries // GetCommitsInfo gets information of all commits that are corresponding to these entries
func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) { func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, gitRepo *Repository, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1) entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself // Get the commit for the treePath itself
entryPaths[0] = "" entryPaths[0] = ""
@@ -26,15 +26,15 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
var err error var err error
var revs map[string]*Commit var revs map[string]*Commit
if commit.repo.LastCommitCache != nil { if gitRepo.LastCommitCache != nil {
var unHitPaths []string var unHitPaths []string
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache) revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, gitRepo.LastCommitCache)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if len(unHitPaths) > 0 { if len(unHitPaths) > 0 {
sort.Strings(unHitPaths) sort.Strings(unHitPaths)
commits, err := GetLastCommitForPaths(ctx, commit, treePath, unHitPaths) commits, err := GetLastCommitForPaths(ctx, gitRepo, commit, treePath, unHitPaths)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -43,7 +43,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
} }
} else { } else {
sort.Strings(entryPaths) sort.Strings(entryPaths)
revs, err = GetLastCommitForPaths(ctx, commit, treePath, entryPaths) revs, err = GetLastCommitForPaths(ctx, gitRepo, commit, treePath, entryPaths)
} }
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -64,7 +64,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// If the entry is a submodule, add a submodule file for this // If the entry is a submodule, add a submodule file for this
if entry.IsSubModule() { if entry.IsSubModule() {
commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(repoLink, path.Join(treePath, entry.Name()), commit, entry.ID) commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(ctx, repoLink, path.Join(treePath, entry.Name()), gitRepo, commit, entry.ID)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -75,11 +75,10 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// get it for free during the tree traversal, and it's used for listing // get it for free during the tree traversal, and it's used for listing
// pages to display information about the newest commit for a given path. // pages to display information about the newest commit for a given path.
var treeCommit *Commit var treeCommit *Commit
var ok bool
if treePath == "" { if treePath == "" {
treeCommit = commit treeCommit = commit
} else if treeCommit, ok = revs[""]; ok { } else {
treeCommit.repo = commit.repo treeCommit = revs[""]
} }
return commitsInfo, treeCommit, nil return commitsInfo, treeCommit, nil
} }
@@ -104,9 +103,9 @@ func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cac
} }
// GetLastCommitForPaths returns last commit information // GetLastCommitForPaths returns last commit information
func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) { func GetLastCommitForPaths(ctx context.Context, gitRepo *Repository, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) {
// We read backwards from the commit to obtain all of the commits // We read backwards from the commit to obtain all of the commits
revs, err := walkGitLog(ctx, commit.repo, commit, treePath, paths...) revs, err := walkGitLog(ctx, gitRepo, commit, treePath, paths...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -126,7 +125,7 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string,
continue continue
} }
c, err := commit.repo.GetCommit(commitID) // Ensure the commit exists in the repository c, err := gitRepo.GetCommit(commitID) // Ensure the commit exists in the repository
if err != nil { if err != nil {
return nil, err return nil, err
} }
+3 -3
View File
@@ -24,7 +24,7 @@ func TestEntries_GetCommitsInfo_ContextErr(t *testing.T) {
commit, err := repo.GetCommit("feaf4ba6bc635fec442f46ddd4512416ec43c2c2") commit, err := repo.GetCommit("feaf4ba6bc635fec442f46ddd4512416ec43c2c2")
require.NoError(t, err) require.NoError(t, err)
entries, err := commit.Tree.ListEntries() entries, err := commit.Tree().ListEntries(t.Context(), repo)
require.NoError(t, err) require.NoError(t, err)
countCommitInfosCommit := func(infos []CommitInfo) (nilCommits, nonNilCommits int) { countCommitInfosCommit := func(infos []CommitInfo) (nilCommits, nonNilCommits int) {
@@ -39,14 +39,14 @@ func TestEntries_GetCommitsInfo_ContextErr(t *testing.T) {
defer test.MockVariableValue(&walkGitLogDebugBeforeNext)() defer test.MockVariableValue(&walkGitLogDebugBeforeNext)()
walkGitLogDebugBeforeNext = cancel walkGitLogDebugBeforeNext = cancel
commitInfos, _, err := entries.GetCommitsInfo(ctx, "/any/repo-link", commit, "") commitInfos, _, err := entries.GetCommitsInfo(ctx, "/any/repo-link", repo, commit, "")
assert.NoError(t, err) assert.NoError(t, err)
nilCommits, nonNilCommits := countCommitInfosCommit(commitInfos) nilCommits, nonNilCommits := countCommitInfosCommit(commitInfos)
assert.Equal(t, 0, nonNilCommits) // no commit info due to canceled (or deadline-exceeded) context assert.Equal(t, 0, nonNilCommits) // no commit info due to canceled (or deadline-exceeded) context
assert.Equal(t, 3, nilCommits) assert.Equal(t, 3, nilCommits)
walkGitLogDebugBeforeNext = nil walkGitLogDebugBeforeNext = nil
commitInfos, _, err = entries.GetCommitsInfo(t.Context(), "/any/repo-link", commit, "") commitInfos, _, err = entries.GetCommitsInfo(t.Context(), "/any/repo-link", repo, commit, "")
assert.NoError(t, err) assert.NoError(t, err)
nilCommits, nonNilCommits = countCommitInfosCommit(commitInfos) nilCommits, nonNilCommits = countCommitInfosCommit(commitInfos)
assert.Equal(t, 3, nonNilCommits) assert.Equal(t, 3, nonNilCommits)
+7 -58
View File
@@ -91,10 +91,9 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
continue continue
} }
assert.NotNil(t, commit) assert.NotNil(t, commit)
assert.NotNil(t, commit.Tree) assert.NotNil(t, commit.TreeID)
assert.NotNil(t, commit.Tree.repo)
tree, err := commit.Tree.SubTree(testCase.Path) tree, err := commit.SubTree(t.Context(), repo1, testCase.Path)
if err != nil { if err != nil {
assert.NoError(t, err, "Unable to get subtree: %s of commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err) assert.NoError(t, err, "Unable to get subtree: %s of commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
// no point trying to do anything else for this test. // no point trying to do anything else for this test.
@@ -102,9 +101,8 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
} }
assert.NotNil(t, tree, "tree is nil for testCase CommitID %s in Path %s", testCase.CommitID, testCase.Path) assert.NotNil(t, tree, "tree is nil for testCase CommitID %s in Path %s", testCase.CommitID, testCase.Path)
assert.NotNil(t, tree.repo, "repo is nil for testCase CommitID %s in Path %s", testCase.CommitID, testCase.Path)
entries, err := tree.ListEntries() entries, err := tree.ListEntries(t.Context(), repo1)
if err != nil { if err != nil {
assert.NoError(t, err, "Unable to get entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err) assert.NoError(t, err, "Unable to get entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
// no point trying to do anything else for this test. // no point trying to do anything else for this test.
@@ -112,7 +110,7 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
} }
// FIXME: Context.TODO() - if graceful has started we should use its Shutdown context otherwise use install signals in TestMain. // FIXME: Context.TODO() - if graceful has started we should use its Shutdown context otherwise use install signals in TestMain.
commitsInfo, treeCommit, err := entries.GetCommitsInfo(t.Context(), "/any/repo-link", commit, testCase.Path) commitsInfo, treeCommit, err := entries.GetCommitsInfo(t.Context(), "/any/repo-link", repo1, commit, testCase.Path)
assert.NoError(t, err, "Unable to get commit information for entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err) assert.NoError(t, err, "Unable to get commit information for entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
if err != nil { if err != nil {
t.FailNow() t.FailNow()
@@ -127,7 +125,7 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
continue continue
} }
assert.Equal(t, expectedInfo.CommitID, commit.ID.String()) assert.Equal(t, expectedInfo.CommitID, commit.ID.String())
assert.Equal(t, expectedInfo.Size, entry.Size(), entry.Name()) assert.Equal(t, expectedInfo.Size, entry.GetSize(t.Context(), repo1), entry.Name())
} }
} }
} }
@@ -155,9 +153,9 @@ func TestEntries_GetCommitsInfo(t *testing.T) {
t.Run("NonExistingSubmoduleAsNil", func(t *testing.T) { t.Run("NonExistingSubmoduleAsNil", func(t *testing.T) {
commit, err := bareRepo1.GetCommit("HEAD") commit, err := bareRepo1.GetCommit("HEAD")
require.NoError(t, err) require.NoError(t, err)
treeEntry, err := commit.GetTreeEntryByPath("file1.txt") treeEntry, err := commit.GetTreeEntryByPath(t.Context(), bareRepo1, "file1.txt")
require.NoError(t, err) require.NoError(t, err)
cisf, err := GetCommitInfoSubmoduleFile("/any/repo-link", "file1.txt", commit, treeEntry.ID) cisf, err := GetCommitInfoSubmoduleFile(t.Context(), "/any/repo-link", "file1.txt", bareRepo1, commit, treeEntry.ID)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, &CommitSubmoduleFile{ assert.Equal(t, &CommitSubmoduleFile{
repoLink: "/any/repo-link", repoLink: "/any/repo-link",
@@ -169,52 +167,3 @@ func TestEntries_GetCommitsInfo(t *testing.T) {
assert.Nil(t, cisf.SubmoduleWebLinkTree(t.Context())) assert.Nil(t, cisf.SubmoduleWebLinkTree(t.Context()))
}) })
} }
func BenchmarkEntries_GetCommitsInfo(b *testing.B) {
type benchmarkType struct {
url string
name string
}
benchmarks := []benchmarkType{
{url: "https://github.com/go-gitea/gitea.git", name: "gitea"},
{url: "https://github.com/ethantkoenig/manyfiles.git", name: "manyfiles"},
{url: "https://github.com/moby/moby.git", name: "moby"},
{url: "https://github.com/golang/go.git", name: "go"},
{url: "https://github.com/torvalds/linux.git", name: "linux"},
}
doBenchmark := func(benchmark benchmarkType) {
var commit *Commit
var entries Entries
var repo *Repository
repoPath, err := cloneRepo(b, benchmark.url)
if err != nil {
b.Fatal(err)
}
if repo, err = OpenRepository(b.Context(), repoPath); err != nil {
b.Fatal(err)
}
defer repo.Close()
if commit, err = repo.GetBranchCommit("master"); err != nil {
b.Fatal(err)
} else if entries, err = commit.Tree.ListEntries(); err != nil {
b.Fatal(err)
}
b.ResetTimer()
b.Run(benchmark.name, func(b *testing.B) {
for b.Loop() {
_, _, err := entries.GetCommitsInfo(b.Context(), "/any/repo-link", commit, "")
if err != nil {
b.Fatal(err)
}
}
})
}
for _, benchmark := range benchmarks {
doBenchmark(benchmark)
}
}
+4 -4
View File
@@ -15,7 +15,7 @@ const (
commitHeaderGpgsigSha256 = "gpgsig-sha256" commitHeaderGpgsigSha256 = "gpgsig-sha256"
) )
func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, headerValue []byte) error { func assignCommitFields(commit *Commit, headerKey string, headerValue []byte) error {
if len(headerValue) > 0 && headerValue[len(headerValue)-1] == '\n' { if len(headerValue) > 0 && headerValue[len(headerValue)-1] == '\n' {
headerValue = headerValue[:len(headerValue)-1] // remove trailing newline headerValue = headerValue[:len(headerValue)-1] // remove trailing newline
} }
@@ -25,7 +25,7 @@ func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, h
if err != nil { if err != nil {
return fmt.Errorf("invalid tree ID %q: %w", string(headerValue), err) return fmt.Errorf("invalid tree ID %q: %w", string(headerValue), err)
} }
commit.Tree = *NewTree(gitRepo, objID) commit.TreeID = objID
case "parent": case "parent":
objID, err := NewIDFromString(string(headerValue)) objID, err := NewIDFromString(string(headerValue))
if err != nil { if err != nil {
@@ -48,7 +48,7 @@ func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, h
// We need this to interpret commits from cat-file or cat-file --batch // We need this to interpret commits from cat-file or cat-file --batch
// //
// If used as part of a cat-file --batch stream you need to limit the reader to the correct size // If used as part of a cat-file --batch stream you need to limit the reader to the correct size
func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader) (*Commit, error) { func CommitFromReader(objectID ObjectID, reader io.Reader) (*Commit, error) {
commit := &Commit{ commit := &Commit{
ID: objectID, ID: objectID,
Author: &Signature{}, Author: &Signature{},
@@ -74,7 +74,7 @@ func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader)
k, v, _ := bytes.Cut(line, []byte{' '}) k, v, _ := bytes.Cut(line, []byte{' '})
if len(k) != 0 || !inHeader { if len(k) != 0 || !inHeader {
if headerKey != "" { if headerKey != "" {
if err = assignCommitFields(gitRepo, commit, headerKey, headerValue); err != nil { if err = assignCommitFields(commit, headerKey, headerValue); err != nil {
return nil, fmt.Errorf("unable to parse commit %q: %w", objectID.String(), err) return nil, fmt.Errorf("unable to parse commit %q: %w", objectID.String(), err)
} }
} }
+5 -5
View File
@@ -65,7 +65,7 @@ signed commit`
assert.NotNil(t, gitRepo) assert.NotNil(t, gitRepo)
defer gitRepo.Close() defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString)) commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err) assert.NoError(t, err)
require.NotNil(t, commitFromReader) require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID) assert.EqualValues(t, sha, commitFromReader.ID)
@@ -93,7 +93,7 @@ committer Adam Majer <amajer@suse.de> 1698676906 +0100
signed commit`, commitFromReader.Signature.Payload) signed commit`, commitFromReader.Signature.Payload)
assert.Equal(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String()) assert.Equal(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n")) commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err) assert.NoError(t, err)
commitFromReader.CommitMessage.MessageRaw += "\n\n" commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n" commitFromReader.Signature.Payload += "\n\n"
@@ -118,15 +118,15 @@ func TestHasPreviousCommitSha256(t *testing.T) {
assert.Equal(t, objectFormat, parentSHA.Type()) assert.Equal(t, objectFormat, parentSHA.Type())
assert.Equal(t, "sha256", objectFormat.Name()) assert.Equal(t, "sha256", objectFormat.Name())
haz, err := commit.HasPreviousCommit(parentSHA) haz, err := commit.HasPreviousCommit(t.Context(), repo, parentSHA)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, haz) assert.True(t, haz)
hazNot, err := commit.HasPreviousCommit(notParentSHA) hazNot, err := commit.HasPreviousCommit(t.Context(), repo, notParentSHA)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, hazNot) assert.False(t, hazNot)
selfNot, err := commit.HasPreviousCommit(commit.ID) selfNot, err := commit.HasPreviousCommit(t.Context(), repo, commit.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, selfNot) assert.False(t, selfNot)
} }
+7 -5
View File
@@ -3,17 +3,19 @@
package git package git
import "context"
type SubmoduleWebLink struct { type SubmoduleWebLink struct {
RepoWebLink, CommitWebLink string RepoWebLink, CommitWebLink string
} }
// GetSubModules get all the submodules of current revision git tree // GetSubModules get all the submodules of current revision git tree
func (c *Commit) GetSubModules() (*ObjectCache[*SubModule], error) { func (c *Commit) GetSubModules(ctx context.Context, gitRepo *Repository) (*ObjectCache[*SubModule], error) {
if c.submoduleCache != nil { if c.submoduleCache != nil {
return c.submoduleCache, nil return c.submoduleCache, nil
} }
entry, err := c.GetTreeEntryByPath(".gitmodules") entry, err := c.GetTreeEntryByPath(ctx, gitRepo, ".gitmodules")
if err != nil { if err != nil {
if _, ok := err.(ErrNotExist); ok { if _, ok := err.(ErrNotExist); ok {
return nil, nil //nolint:nilnil // return nil to indicate that the submodule does not exist return nil, nil //nolint:nilnil // return nil to indicate that the submodule does not exist
@@ -21,7 +23,7 @@ func (c *Commit) GetSubModules() (*ObjectCache[*SubModule], error) {
return nil, err return nil, err
} }
rd, err := entry.Blob().DataAsync() rd, err := entry.Blob(gitRepo).DataAsync()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -37,8 +39,8 @@ func (c *Commit) GetSubModules() (*ObjectCache[*SubModule], error) {
// GetSubModule gets the submodule by the entry name. // GetSubModule gets the submodule by the entry name.
// It returns "nil, nil" if the submodule does not exist, caller should always remember to check the "nil" // It returns "nil, nil" if the submodule does not exist, caller should always remember to check the "nil"
func (c *Commit) GetSubModule(entryName string) (*SubModule, error) { func (c *Commit) GetSubModule(ctx context.Context, gitRepo *Repository, entryName string) (*SubModule, error) {
modules, err := c.GetSubModules() modules, err := c.GetSubModules(ctx, gitRepo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+7 -7
View File
@@ -61,7 +61,7 @@ empty commit`
assert.NotNil(t, gitRepo) assert.NotNil(t, gitRepo)
defer gitRepo.Close() defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString)) commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err) assert.NoError(t, err)
require.NotNil(t, commitFromReader) require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID) assert.EqualValues(t, sha, commitFromReader.ID)
@@ -89,7 +89,7 @@ committer silverwind <me@silverwind.io> 1563741793 +0200
empty commit`, commitFromReader.Signature.Payload) empty commit`, commitFromReader.Signature.Payload)
assert.Equal(t, "silverwind <me@silverwind.io>", commitFromReader.Author.String()) assert.Equal(t, "silverwind <me@silverwind.io>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n")) commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err) assert.NoError(t, err)
commitFromReader.CommitMessage.MessageRaw += "\n\n" commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n" commitFromReader.Signature.Payload += "\n\n"
@@ -125,7 +125,7 @@ ISO-8859-1`
assert.NotNil(t, gitRepo) assert.NotNil(t, gitRepo)
defer gitRepo.Close() defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString)) commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err) assert.NoError(t, err)
require.NotNil(t, commitFromReader) require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID) assert.EqualValues(t, sha, commitFromReader.ID)
@@ -152,7 +152,7 @@ encoding ISO-8859-1
ISO-8859-1`, commitFromReader.Signature.Payload) ISO-8859-1`, commitFromReader.Signature.Payload)
assert.Equal(t, "KN4CK3R <admin@oldschoolhack.me>", commitFromReader.Author.String()) assert.Equal(t, "KN4CK3R <admin@oldschoolhack.me>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n")) commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err) assert.NoError(t, err)
commitFromReader.CommitMessage.MessageRaw += "\n\n" commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n" commitFromReader.Signature.Payload += "\n\n"
@@ -172,15 +172,15 @@ func TestHasPreviousCommit(t *testing.T) {
parentSHA := MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2") parentSHA := MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
notParentSHA := MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3") notParentSHA := MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
haz, err := commit.HasPreviousCommit(parentSHA) haz, err := commit.HasPreviousCommit(t.Context(), repo, parentSHA)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, haz) assert.True(t, haz)
hazNot, err := commit.HasPreviousCommit(notParentSHA) hazNot, err := commit.HasPreviousCommit(t.Context(), repo, notParentSHA)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, hazNot) assert.False(t, hazNot)
selfNot, err := commit.HasPreviousCommit(commit.ID) selfNot, err := commit.HasPreviousCommit(t.Context(), repo, commit.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, selfNot) assert.False(t, selfNot)
} }
+2 -2
View File
@@ -75,7 +75,7 @@ func getRepoRawDiffForFileCmd(_ context.Context, repo *Repository, startCommit,
} else if commit.ParentCount() == 0 { } else if commit.ParentCount() == 0 {
cmd.AddArguments("show").AddDynamicArguments(endCommit).AddDashesAndList(files...) cmd.AddArguments("show").AddDynamicArguments(endCommit).AddDashesAndList(files...)
} else { } else {
c, err := commit.Parent(0) c, err := commit.Parent(repo, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -90,7 +90,7 @@ func getRepoRawDiffForFileCmd(_ context.Context, repo *Repository, startCommit,
} else if commit.ParentCount() == 0 { } else if commit.ParentCount() == 0 {
cmd.AddArguments("format-patch", "--no-signature", "--stdout", "--root").AddDynamicArguments(endCommit).AddDashesAndList(files...) cmd.AddArguments("format-patch", "--no-signature", "--stdout", "--root").AddDynamicArguments(endCommit).AddDashesAndList(files...)
} else { } else {
c, err := commit.Parent(0) c, err := commit.Parent(repo, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -7,6 +7,7 @@ package languagestats
import ( import (
"bytes" "bytes"
"context"
"io" "io"
"gitea.dev/modules/analyze" "gitea.dev/modules/analyze"
@@ -21,7 +22,7 @@ import (
) )
// GetLanguageStats calculates language stats for git repository at specified commit // GetLanguageStats calculates language stats for git repository at specified commit
func GetLanguageStats(repo *git_module.Repository, commitID string) (map[string]int64, error) { func GetLanguageStats(_ context.Context, repo *git_module.Repository, commitID string) (map[string]int64, error) {
r, err := git.PlainOpen(repo.Path) r, err := git.PlainOpen(repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -7,6 +7,7 @@ package languagestats
import ( import (
"bytes" "bytes"
"context"
"io" "io"
"gitea.dev/modules/analyze" "gitea.dev/modules/analyze"
@@ -19,10 +20,10 @@ import (
) )
// GetLanguageStats calculates language stats for git repository at specified commit // GetLanguageStats calculates language stats for git repository at specified commit
func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64, error) { func GetLanguageStats(ctx context.Context, repo *git.Repository, commitID string) (map[string]int64, error) {
// We will feed the commit IDs in order into cat-file --batch, followed by blobs as necessary. // We will feed the commit IDs in order into cat-file --batch, followed by blobs as necessary.
// so let's create a batch stdin and stdout // so let's create a batch stdin and stdout
batch, cancel, err := repo.CatFileBatch(repo.Ctx) batch, cancel, err := repo.CatFileBatch(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -43,7 +44,7 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
return nil, git.ErrNotExist{ID: commitID} return nil, git.ErrNotExist{ID: commitID}
} }
commit, err := git.CommitFromReader(repo, sha, io.LimitReader(batchReader, commitInfo.Size)) commit, err := git.CommitFromReader(sha, io.LimitReader(batchReader, commitInfo.Size))
if err != nil { if err != nil {
log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
return nil, err return nil, err
@@ -52,9 +53,7 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
return nil, err return nil, err
} }
tree := commit.Tree entries, err := commit.Tree().ListEntriesRecursiveWithSize(ctx, repo)
entries, err := tree.ListEntriesRecursiveWithSize()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -81,13 +80,15 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
select { select {
case <-repo.Ctx.Done(): case <-repo.Ctx.Done():
return sizes, repo.Ctx.Err() return sizes, repo.Ctx.Err()
case <-ctx.Done():
return sizes, ctx.Err()
default: default:
} }
contentBuf.Reset() contentBuf.Reset()
content = contentBuf.Bytes() content = contentBuf.Bytes()
if f.Size() == 0 { if f.GetSize(ctx, repo) == 0 {
continue continue
} }
@@ -124,7 +125,7 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
} }
// this language will always be added to the size // this language will always be added to the size
sizes[language] += f.Size() sizes[language] += f.GetSize(ctx, repo)
continue continue
} }
} }
@@ -138,7 +139,7 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
// If content can not be read or file is too big just do detection by filename // If content can not be read or file is too big just do detection by filename
if f.Size() <= bigFileSize { if f.GetSize(ctx, repo) <= bigFileSize {
info, _, err := batch.QueryContent(f.ID.String()) info, _, err := batch.QueryContent(f.ID.String())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -192,10 +193,10 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
includedLanguage[language] = included includedLanguage[language] = included
} }
if included || isDetectable.ValueOrDefault(false) { if included || isDetectable.ValueOrDefault(false) {
sizes[language] += f.Size() sizes[language] += f.GetSize(ctx, repo)
} else if len(sizes) == 0 && (firstExcludedLanguage == "" || firstExcludedLanguage == language) { } else if len(sizes) == 0 && (firstExcludedLanguage == "" || firstExcludedLanguage == language) {
firstExcludedLanguage = language firstExcludedLanguage = language
firstExcludedLanguageSize += f.Size() firstExcludedLanguageSize += f.GetSize(ctx, repo)
} }
} }
@@ -22,7 +22,7 @@ func TestRepository_GetLanguageStats(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer gitRepo.Close() defer gitRepo.Close()
stats, err := GetLanguageStats(gitRepo, "8fee858da5796dfb37704761701bb8e800ad9ef3") stats, err := GetLanguageStats(t.Context(), gitRepo, "8fee858da5796dfb37704761701bb8e800ad9ef3")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, map[string]int64{ assert.Equal(t, map[string]int64{
+9 -9
View File
@@ -13,26 +13,26 @@ import (
) )
// CacheCommit will cache the commit from the gitRepository // CacheCommit will cache the commit from the gitRepository
func (c *Commit) CacheCommit(ctx context.Context) error { func (c *Commit) CacheCommit(ctx context.Context, gitRepo *Repository) error {
if c.repo.LastCommitCache == nil { if gitRepo.LastCommitCache == nil {
return nil return nil
} }
commitNodeIndex, _ := c.repo.CommitNodeIndex() commitNodeIndex, _ := gitRepo.CommitNodeIndex()
index, err := commitNodeIndex.Get(plumbing.Hash(c.ID.RawValue())) index, err := commitNodeIndex.Get(plumbing.Hash(c.ID.RawValue()))
if err != nil { if err != nil {
return err return err
} }
return c.recursiveCache(ctx, index, &c.Tree, "", 1) return c.recursiveCache(ctx, gitRepo, index, c.Tree(), "", 1)
} }
func (c *Commit) recursiveCache(ctx context.Context, index cgobject.CommitNode, tree *Tree, treePath string, level int) error { func (c *Commit) recursiveCache(ctx context.Context, gitRepo *Repository, index cgobject.CommitNode, tree *Tree, treePath string, level int) error {
if level == 0 { if level == 0 {
return nil return nil
} }
entries, err := tree.ListEntries() entries, err := tree.ListEntries(ctx, gitRepo)
if err != nil { if err != nil {
return err return err
} }
@@ -44,18 +44,18 @@ func (c *Commit) recursiveCache(ctx context.Context, index cgobject.CommitNode,
entryMap[entry.Name()] = entry entryMap[entry.Name()] = entry
} }
commits, err := GetLastCommitForPaths(ctx, c.repo.LastCommitCache, index, treePath, entryPaths) commits, err := getLastCommitForPathsByCommitNode(ctx, gitRepo, index, treePath, entryPaths)
if err != nil { if err != nil {
return err return err
} }
for entry := range commits { for entry := range commits {
if entryMap[entry].IsDir() { if entryMap[entry].IsDir() {
subTree, err := tree.SubTree(entry) subTree, err := tree.SubTree(ctx, gitRepo, entry)
if err != nil { if err != nil {
return err return err
} }
if err := c.recursiveCache(ctx, index, subTree, entry, level-1); err != nil { if err := c.recursiveCache(ctx, gitRepo, index, subTree, entry, level-1); err != nil {
return err return err
} }
} }
+8 -9
View File
@@ -10,19 +10,18 @@ import (
) )
// CacheCommit will cache the commit from the gitRepository // CacheCommit will cache the commit from the gitRepository
func (c *Commit) CacheCommit(ctx context.Context) error { func (c *Commit) CacheCommit(ctx context.Context, gitRepo *Repository) error {
if c.repo.LastCommitCache == nil { if gitRepo.LastCommitCache == nil {
return nil return nil
} }
return c.recursiveCache(ctx, &c.Tree, "", 1) return c.recursiveCache(ctx, gitRepo, c.Tree(), "", 1)
} }
func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string, level int) error { func (c *Commit) recursiveCache(ctx context.Context, gitRepo *Repository, tree *Tree, treePath string, level int) error {
if level == 0 { if level == 0 {
return nil return nil
} }
entries, err := tree.ListEntries(ctx, gitRepo)
entries, err := tree.ListEntries()
if err != nil { if err != nil {
return err return err
} }
@@ -32,7 +31,7 @@ func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string
entryPaths[i] = entry.Name() entryPaths[i] = entry.Name()
} }
_, err = walkGitLog(ctx, c.repo, c, treePath, entryPaths...) _, err = walkGitLog(ctx, gitRepo, c, treePath, entryPaths...)
if err != nil { if err != nil {
return err return err
} }
@@ -40,11 +39,11 @@ func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string
for _, treeEntry := range entries { for _, treeEntry := range entries {
// entryMap won't contain "" therefore skip this. // entryMap won't contain "" therefore skip this.
if treeEntry.IsDir() { if treeEntry.IsDir() {
subTree, err := tree.SubTree(treeEntry.Name()) subTree, err := tree.SubTree(ctx, gitRepo, treeEntry.Name())
if err != nil { if err != nil {
return err return err
} }
if err := c.recursiveCache(ctx, subTree, treeEntry.Name(), level-1); err != nil { if err := c.recursiveCache(ctx, gitRepo, subTree, treeEntry.Name(), level-1); err != nil {
return err return err
} }
} }
+2 -3
View File
@@ -263,13 +263,12 @@ var walkGitLogDebugBeforeNext func() // is used to simulate various edge git pro
// walkGitLog walks the git log --name-status for the head commit in the provided treepath and files // walkGitLog walks the git log --name-status for the head commit in the provided treepath and files
func walkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath string, paths ...string) (map[string]string, error) { func walkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath string, paths ...string) (map[string]string, error) {
headRef := head.ID.String() headRef := head.ID.String()
tree, err := head.SubTree(ctx, repo, treepath)
tree, err := head.SubTree(treepath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
entries, err := tree.ListEntries() entries, err := tree.ListEntries(ctx, repo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+85
View File
@@ -3,6 +3,14 @@
package git package git
import (
"context"
"io"
"strings"
"gitea.dev/modules/log"
)
// NotesRef is the git ref where Gitea will look for git-notes data. // NotesRef is the git ref where Gitea will look for git-notes data.
// The value ("refs/notes/commits") is the default ref used by git-notes. // The value ("refs/notes/commits") is the default ref used by git-notes.
const NotesRef = "refs/notes/commits" const NotesRef = "refs/notes/commits"
@@ -12,3 +20,80 @@ type Note struct {
Message []byte Message []byte
Commit *Commit Commit *Commit
} }
// GetNote retrieves the git-notes data for a given commit.
// FIXME: Add LastCommitCache support
func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note) error {
log.Trace("Searching for git note corresponding to the commit %q in the repository %q", commitID, repo.Path)
notes, err := repo.GetCommit(NotesRef)
if err != nil {
if IsErrNotExist(err) {
return err
}
log.Error("Unable to get commit from ref %q. Error: %v", NotesRef, err)
return err
}
path := ""
tree := notes.Tree()
log.Trace("Found tree with ID %q while searching for git note corresponding to the commit %q", tree.ID, commitID)
var entry *TreeEntry
originalCommitID := commitID
for len(commitID) > 2 {
entry, err = tree.GetTreeEntryByPath(ctx, repo, commitID)
if err == nil {
path += commitID
break
}
if IsErrNotExist(err) {
tree, err = tree.SubTree(ctx, repo, commitID[0:2])
path += commitID[0:2] + "/"
commitID = commitID[2:]
}
if err != nil {
// Err may have been updated by the SubTree we need to recheck if it's again an ErrNotExist
if !IsErrNotExist(err) {
log.Error("Unable to find git note corresponding to the commit %q. Error: %v", originalCommitID, err)
}
return err
}
}
blob := entry.Blob(repo)
dataRc, err := blob.DataAsync()
if err != nil {
log.Error("Unable to read blob with ID %q. Error: %v", blob.ID, err)
return err
}
closed := false
defer func() {
if !closed {
_ = dataRc.Close()
}
}()
d, err := io.ReadAll(dataRc)
if err != nil {
log.Error("Unable to read blob with ID %q. Error: %v", blob.ID, err)
return err
}
_ = dataRc.Close()
closed = true
note.Message = d
treePath := ""
if idx := strings.LastIndex(path, "/"); idx > -1 {
treePath = path[:idx]
path = path[idx+1:]
}
lastCommits, err := GetLastCommitForPaths(ctx, repo, notes, treePath, []string{path})
if err != nil {
log.Error("Unable to get the commit for the path %q. Error: %v", treePath, err)
return err
}
note.Commit = lastCommits[path]
return nil
}
-95
View File
@@ -1,95 +0,0 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build gogit
package git
import (
"context"
"fmt"
"io"
"strings"
"gitea.dev/modules/log"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)
// GetNote retrieves the git-notes data for a given commit.
// FIXME: Add LastCommitCache support
func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note) error {
log.Trace("Searching for git note corresponding to the commit %q in the repository %q", commitID, repo.Path)
notes, err := repo.GetCommit(NotesRef)
if err != nil {
if IsErrNotExist(err) {
return err
}
log.Error("Unable to get commit from ref %q. Error: %v", NotesRef, err)
return err
}
remainingCommitID := commitID
var path strings.Builder
currentTree, err := notes.Tree.gogitTreeObject()
if err != nil {
return fmt.Errorf("unable to get tree object for notes commit %q: %w", notes.ID.String(), err)
}
log.Trace("Found tree with ID %q while searching for git note corresponding to the commit %q", currentTree.Entries[0].Name, commitID)
var file *object.File
for len(remainingCommitID) > 2 {
file, err = currentTree.File(remainingCommitID)
if err == nil {
path.WriteString(remainingCommitID)
break
}
if err == object.ErrFileNotFound {
currentTree, err = currentTree.Tree(remainingCommitID[0:2])
path.WriteString(remainingCommitID[0:2] + "/")
remainingCommitID = remainingCommitID[2:]
}
if err != nil {
if err == object.ErrDirectoryNotFound {
return ErrNotExist{ID: remainingCommitID, RelPath: path.String()}
}
log.Error("Unable to find git note corresponding to the commit %q. Error: %v", commitID, err)
return err
}
}
blob := file.Blob
dataRc, err := blob.Reader()
if err != nil {
log.Error("Unable to read blob with ID %q. Error: %v", blob.ID, err)
return err
}
defer dataRc.Close()
d, err := io.ReadAll(dataRc)
if err != nil {
log.Error("Unable to read blob with ID %q. Error: %v", blob.ID, err)
return err
}
note.Message = d
commitNodeIndex, commitGraphFile := repo.CommitNodeIndex()
if commitGraphFile != nil {
defer commitGraphFile.Close()
}
commitNode, err := commitNodeIndex.Get(plumbing.Hash(notes.ID.RawValue()))
if err != nil {
return err
}
lastCommits, err := GetLastCommitForPaths(ctx, nil, commitNode, "", []string{path.String()})
if err != nil {
log.Error("Unable to get the commit for the path %q. Error: %v", path.String(), err)
return err
}
note.Commit = lastCommits[path.String()]
return nil
}
-91
View File
@@ -1,91 +0,0 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build !gogit
package git
import (
"context"
"io"
"strings"
"gitea.dev/modules/log"
)
// GetNote retrieves the git-notes data for a given commit.
// FIXME: Add LastCommitCache support
func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note) error {
log.Trace("Searching for git note corresponding to the commit %q in the repository %q", commitID, repo.Path)
notes, err := repo.GetCommit(NotesRef)
if err != nil {
if IsErrNotExist(err) {
return err
}
log.Error("Unable to get commit from ref %q. Error: %v", NotesRef, err)
return err
}
path := ""
tree := &notes.Tree
log.Trace("Found tree with ID %q while searching for git note corresponding to the commit %q", tree.ID, commitID)
var entry *TreeEntry
originalCommitID := commitID
for len(commitID) > 2 {
entry, err = tree.GetTreeEntryByPath(commitID)
if err == nil {
path += commitID
break
}
if IsErrNotExist(err) {
tree, err = tree.SubTree(commitID[0:2])
path += commitID[0:2] + "/"
commitID = commitID[2:]
}
if err != nil {
// Err may have been updated by the SubTree we need to recheck if it's again an ErrNotExist
if !IsErrNotExist(err) {
log.Error("Unable to find git note corresponding to the commit %q. Error: %v", originalCommitID, err)
}
return err
}
}
blob := entry.Blob()
dataRc, err := blob.DataAsync()
if err != nil {
log.Error("Unable to read blob with ID %q. Error: %v", blob.ID, err)
return err
}
closed := false
defer func() {
if !closed {
_ = dataRc.Close()
}
}()
d, err := io.ReadAll(dataRc)
if err != nil {
log.Error("Unable to read blob with ID %q. Error: %v", blob.ID, err)
return err
}
_ = dataRc.Close()
closed = true
note.Message = d
treePath := ""
if idx := strings.LastIndex(path, "/"); idx > -1 {
treePath = path[:idx]
path = path[idx+1:]
}
lastCommits, err := GetLastCommitForPaths(ctx, notes, treePath, []string{path})
if err != nil {
log.Error("Unable to get the commit for the path %q. Error: %v", treePath, err)
return err
}
note.Commit = lastCommits[path]
return nil
}
+2 -2
View File
@@ -72,7 +72,7 @@ func findLFSFileFunc(repo *git.Repository, objectID git.ObjectID, revListReader
continue continue
case "commit": case "commit":
// Read in the commit to get its tree and in case this is one of the last used commits // Read in the commit to get its tree and in case this is one of the last used commits
curCommit, err = git.CommitFromReader(repo, git.MustIDFromString(commitID), io.LimitReader(batchReader, info.Size)) curCommit, err = git.CommitFromReader(git.MustIDFromString(commitID), io.LimitReader(batchReader, info.Size))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -80,7 +80,7 @@ func findLFSFileFunc(repo *git.Repository, objectID git.ObjectID, revListReader
return nil, err return nil, err
} }
if info, _, err = batch.QueryContent(curCommit.Tree.ID.String()); err != nil { if info, _, err = batch.QueryContent(curCommit.TreeID.String()); err != nil {
return nil, err return nil, err
} }
curPath = "" curPath = ""
+2 -3
View File
@@ -92,15 +92,14 @@ func (repo *Repository) getCommit(id ObjectID) (*Commit, error) {
} }
commit := convertCommit(gogitCommit) commit := convertCommit(gogitCommit)
commit.repo = repo
tree, err := gogitCommit.Tree() tree, err := gogitCommit.Tree()
if err != nil { if err != nil {
return nil, err return nil, err
} }
commit.Tree.ID = ParseGogitHash(tree.Hash) commit.TreeID = ParseGogitHash(tree.Hash)
commit.Tree.resolvedGogitTreeObject = tree commit.Tree().resolvedGogitTreeObject = tree
return commit, nil return commit, nil
} }
+1 -1
View File
@@ -88,7 +88,7 @@ func (repo *Repository) getCommitWithBatch(batch CatFileBatch, id ObjectID) (*Co
} }
return repo.getCommitWithBatch(batch, tag.Object) return repo.getCommitWithBatch(batch, tag.Object)
case "commit": case "commit":
commit, err := CommitFromReader(repo, id, io.LimitReader(rd, info.Size)) commit, err := CommitFromReader(id, io.LimitReader(rd, info.Size))
if err != nil { if err != nil {
return nil, err return nil, err
} }
+1 -1
View File
@@ -149,5 +149,5 @@ func (repo *Repository) WriteTree() (*Tree, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewTree(repo, id), nil return newTree(id), nil
} }
+1 -3
View File
@@ -25,7 +25,7 @@ func (repo *Repository) getTree(id ObjectID) (*Tree, error) {
return nil, err return nil, err
} }
tree := NewTree(repo, id) tree := newTree(id)
tree.resolvedGogitTreeObject = gogitTree tree.resolvedGogitTreeObject = gogitTree
return tree, nil return tree, nil
} }
@@ -53,7 +53,6 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
resolvedID := id
commitObject, err := repo.gogitRepo.CommitObject(plumbing.Hash(id.RawValue())) commitObject, err := repo.gogitRepo.CommitObject(plumbing.Hash(id.RawValue()))
if err == nil { if err == nil {
id = ParseGogitHash(commitObject.TreeHash) id = ParseGogitHash(commitObject.TreeHash)
@@ -62,6 +61,5 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
treeObject.ResolvedID = resolvedID
return treeObject, nil return treeObject, nil
} }
+6 -8
View File
@@ -23,7 +23,6 @@ func (repo *Repository) getTree(id ObjectID) (*Tree, error) {
switch info.Type { switch info.Type {
case "tag": case "tag":
resolvedID := id
data, err := io.ReadAll(io.LimitReader(rd, info.Size)) data, err := io.ReadAll(io.LimitReader(rd, info.Size))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -37,21 +36,20 @@ func (repo *Repository) getTree(id ObjectID) (*Tree, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
commit.Tree.ResolvedID = resolvedID tree := commit.Tree()
return &commit.Tree, nil return tree, nil
case "commit": case "commit":
commit, err := CommitFromReader(repo, id, io.LimitReader(rd, info.Size)) commit, err := CommitFromReader(id, io.LimitReader(rd, info.Size))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if _, err := rd.Discard(1); err != nil { if _, err := rd.Discard(1); err != nil {
return nil, err return nil, err
} }
commit.Tree.ResolvedID = commit.ID tree := commit.Tree()
return &commit.Tree, nil return tree, nil
case "tree": case "tree":
tree := NewTree(repo, id) tree := newTree(id)
tree.ResolvedID = id
objectFormat, err := repo.GetObjectFormat() objectFormat, err := repo.GetObjectFormat()
if err != nil { if err != nil {
return nil, err return nil, err
+7 -17
View File
@@ -6,31 +6,22 @@ package git
import ( import (
"bytes" "bytes"
"context"
"strings" "strings"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
) )
type TreeCommon struct { type TreeCommon struct {
ID ObjectID ID ObjectID
ResolvedID ObjectID
repo *Repository
ptree *Tree // parent tree
} }
// NewTree create a new tree according the repository and tree id func newTree(id ObjectID) *Tree {
func NewTree(repo *Repository, id ObjectID) *Tree { return &Tree{TreeCommon: TreeCommon{ID: id}}
return &Tree{
TreeCommon: TreeCommon{
ID: id,
repo: repo,
},
}
} }
// SubTree get a subtree by the sub dir path // SubTree get a subtree by the sub dir path
func (t *Tree) SubTree(rpath string) (*Tree, error) { func (t *Tree) SubTree(ctx context.Context, gitRepo *Repository, rpath string) (*Tree, error) {
if len(rpath) == 0 { if len(rpath) == 0 {
return t, nil return t, nil
} }
@@ -43,16 +34,15 @@ func (t *Tree) SubTree(rpath string) (*Tree, error) {
te *TreeEntry te *TreeEntry
) )
for _, name := range paths { for _, name := range paths {
te, err = p.GetTreeEntryByPath(name) te, err = p.GetTreeEntryByPath(ctx, gitRepo, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
g, err = t.repo.getTree(te.ID) g, err = gitRepo.getTree(te.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
g.ptree = p
p = g p = g
} }
return g, nil return g, nil
+5 -3
View File
@@ -4,15 +4,17 @@
package git package git
import "context"
// GetBlobByPath get the blob object according the path // GetBlobByPath get the blob object according the path
func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) { func (t *Tree) GetBlobByPath(ctx context.Context, gitRepo *Repository, relpath string) (*Blob, error) {
entry, err := t.GetTreeEntryByPath(relpath) entry, err := t.GetTreeEntryByPath(ctx, gitRepo, relpath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !entry.IsDir() && !entry.IsSubModule() { if !entry.IsDir() && !entry.IsSubModule() {
return entry.Blob(), nil return entry.Blob(gitRepo), nil
} }
return nil, ErrNotExist{"", relpath} return nil, ErrNotExist{"", relpath}
+4 -3
View File
@@ -7,6 +7,7 @@
package git package git
import ( import (
"context"
"path" "path"
"strings" "strings"
@@ -14,7 +15,7 @@ import (
) )
// GetTreeEntryByPath get the tree entries according the sub dir // GetTreeEntryByPath get the tree entries according the sub dir
func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) { func (t *Tree) GetTreeEntryByPath(ctx context.Context, gitRepo *Repository, relpath string) (*TreeEntry, error) {
if len(relpath) == 0 { if len(relpath) == 0 {
return &TreeEntry{ return &TreeEntry{
ID: t.ID, ID: t.ID,
@@ -30,7 +31,7 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
tree := t tree := t
for i, name := range parts { for i, name := range parts {
if i == len(parts)-1 { if i == len(parts)-1 {
entries, err := tree.ListEntries() entries, err := tree.ListEntries(ctx, gitRepo)
if err != nil { if err != nil {
if err == plumbing.ErrObjectNotFound { if err == plumbing.ErrObjectNotFound {
return nil, ErrNotExist{ return nil, ErrNotExist{
@@ -45,7 +46,7 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
} }
} }
} else { } else {
tree, err = tree.SubTree(name) tree, err = tree.SubTree(ctx, gitRepo, name)
if err != nil { if err != nil {
if err == plumbing.ErrObjectNotFound { if err == plumbing.ErrObjectNotFound {
return nil, ErrNotExist{ return nil, ErrNotExist{
+4 -3
View File
@@ -6,12 +6,13 @@
package git package git
import ( import (
"context"
"path" "path"
"strings" "strings"
) )
// GetTreeEntryByPath get the tree entries according the sub dir // GetTreeEntryByPath get the tree entries according the sub dir
func (t *Tree) GetTreeEntryByPath(relpath string) (_ *TreeEntry, err error) { func (t *Tree) GetTreeEntryByPath(ctx context.Context, gitRepo *Repository, relpath string) (_ *TreeEntry, err error) {
if len(relpath) == 0 { if len(relpath) == 0 {
return &TreeEntry{ return &TreeEntry{
ptree: t, ptree: t,
@@ -26,14 +27,14 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (_ *TreeEntry, err error) {
tree := t tree := t
for _, name := range parts[:len(parts)-1] { for _, name := range parts[:len(parts)-1] {
tree, err = tree.SubTree(name) tree, err = tree.SubTree(ctx, gitRepo, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
name := parts[len(parts)-1] name := parts[len(parts)-1]
entries, err := tree.ListEntries() entries, err := tree.ListEntries(ctx, gitRepo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+13 -14
View File
@@ -5,6 +5,7 @@
package git package git
import ( import (
"context"
"path" "path"
"slices" "slices"
"strings" "strings"
@@ -78,18 +79,18 @@ type EntryFollowResult struct {
TargetEntry *TreeEntry TargetEntry *TreeEntry
} }
func EntryFollowLink(commit *Commit, fullPath string, te *TreeEntry) (*EntryFollowResult, error) { func EntryFollowLink(ctx context.Context, gitRepo *Repository, commit *Commit, fullPath string, te *TreeEntry) (*EntryFollowResult, error) {
if !te.IsLink() { if !te.IsLink() {
return nil, util.ErrorWrap(util.ErrUnprocessableContent, "%q is not a symlink", fullPath) return nil, util.ErrorWrap(util.ErrUnprocessableContent, "%q is not a symlink", fullPath)
} }
// git's filename max length is 4096, hopefully a link won't be longer than multiple of that // git's filename max length is 4096, hopefully a link won't be longer than multiple of that
const maxSymlinkSize = 20 * 4096 const maxSymlinkSize = 20 * 4096
if te.Blob().Size() > maxSymlinkSize { if te.Blob(gitRepo).Size() > maxSymlinkSize {
return nil, util.ErrorWrap(util.ErrUnprocessableContent, "%q content exceeds symlink limit", fullPath) return nil, util.ErrorWrap(util.ErrUnprocessableContent, "%q content exceeds symlink limit", fullPath)
} }
link, err := te.Blob().GetBlobContent(maxSymlinkSize) link, err := te.Blob(gitRepo).GetBlobContent(maxSymlinkSize)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -99,18 +100,18 @@ func EntryFollowLink(commit *Commit, fullPath string, te *TreeEntry) (*EntryFoll
} }
targetFullPath := path.Join(path.Dir(fullPath), link) targetFullPath := path.Join(path.Dir(fullPath), link)
targetEntry, err := commit.GetTreeEntryByPath(targetFullPath) targetEntry, err := commit.GetTreeEntryByPath(ctx, gitRepo, targetFullPath)
if err != nil { if err != nil {
return &EntryFollowResult{SymlinkContent: link}, err return &EntryFollowResult{SymlinkContent: link}, err
} }
return &EntryFollowResult{SymlinkContent: link, TargetFullPath: targetFullPath, TargetEntry: targetEntry}, nil return &EntryFollowResult{SymlinkContent: link, TargetFullPath: targetFullPath, TargetEntry: targetEntry}, nil
} }
func EntryFollowLinks(commit *Commit, firstFullPath string, firstTreeEntry *TreeEntry, optLimit ...int) (res *EntryFollowResult, err error) { func EntryFollowLinks(ctx context.Context, gitRepo *Repository, commit *Commit, firstFullPath string, firstTreeEntry *TreeEntry, optLimit ...int) (res *EntryFollowResult, err error) {
limit := util.OptionalArg(optLimit, 10) limit := util.OptionalArg(optLimit, 10)
treeEntry, fullPath := firstTreeEntry, firstFullPath treeEntry, fullPath := firstTreeEntry, firstFullPath
for range limit { for range limit {
res, err = EntryFollowLink(commit, fullPath, treeEntry) res, err = EntryFollowLink(ctx, gitRepo, commit, fullPath, treeEntry)
if err != nil { if err != nil {
return res, err return res, err
} }
@@ -125,28 +126,26 @@ func EntryFollowLinks(commit *Commit, firstFullPath string, firstTreeEntry *Tree
return res, nil return res, nil
} }
// returns the Tree pointed to by this TreeEntry, or nil if this is not a tree func (te *TreeEntry) Tree(gitRepo *Repository) *Tree {
func (te *TreeEntry) Tree() *Tree { t, err := gitRepo.getTree(te.ID)
t, err := te.ptree.repo.getTree(te.ID)
if err != nil { if err != nil {
return nil return nil
} }
t.ptree = te.ptree
return t return t
} }
// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory ) // GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
func (te *TreeEntry) GetSubJumpablePathName() string { func (te *TreeEntry) GetSubJumpablePathName(ctx context.Context, gitRepo *Repository) string {
if te.IsSubModule() || !te.IsDir() { if te.IsSubModule() || !te.IsDir() {
return "" return ""
} }
tree, err := te.ptree.SubTree(te.Name()) tree, err := te.ptree.SubTree(ctx, gitRepo, te.Name())
if err != nil { if err != nil {
return te.Name() return te.Name()
} }
entries, _ := tree.ListEntries() entries, _ := tree.ListEntries(ctx, gitRepo)
if len(entries) == 1 && entries[0].IsDir() { if len(entries) == 1 && entries[0].IsDir() {
name := entries[0].GetSubJumpablePathName() name := entries[0].GetSubJumpablePathName(ctx, gitRepo)
if name != "" { if name != "" {
return te.Name() + "/" + name return te.Name() + "/" + name
} }
+10 -10
View File
@@ -23,12 +23,12 @@ func TestFollowLink(t *testing.T) {
// get the symlink // get the symlink
{ {
lnkFullPath := "foo/bar/link_to_hello" lnkFullPath := "foo/bar/link_to_hello"
lnk, err := commit.Tree.GetTreeEntryByPath("foo/bar/link_to_hello") lnk, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "foo/bar/link_to_hello")
require.NoError(t, err) require.NoError(t, err)
assert.True(t, lnk.IsLink()) assert.True(t, lnk.IsLink())
// should be able to dereference to target // should be able to dereference to target
res, err := EntryFollowLink(commit, lnkFullPath, lnk) res, err := EntryFollowLink(t.Context(), r, commit, lnkFullPath, lnk)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "hello", res.TargetEntry.Name()) assert.Equal(t, "hello", res.TargetEntry.Name())
assert.Equal(t, "foo/nar/hello", res.TargetFullPath) assert.Equal(t, "foo/nar/hello", res.TargetFullPath)
@@ -38,38 +38,38 @@ func TestFollowLink(t *testing.T) {
{ {
// should error when called on a normal file // should error when called on a normal file
entry, err := commit.Tree.GetTreeEntryByPath("file1.txt") entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "file1.txt")
require.NoError(t, err) require.NoError(t, err)
res, err := EntryFollowLink(commit, "file1.txt", entry) res, err := EntryFollowLink(t.Context(), r, commit, "file1.txt", entry)
assert.ErrorIs(t, err, util.ErrUnprocessableContent) assert.ErrorIs(t, err, util.ErrUnprocessableContent)
assert.Nil(t, res) assert.Nil(t, res)
} }
{ {
// should error for broken links // should error for broken links
entry, err := commit.Tree.GetTreeEntryByPath("foo/broken_link") entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "foo/broken_link")
require.NoError(t, err) require.NoError(t, err)
assert.True(t, entry.IsLink()) assert.True(t, entry.IsLink())
res, err := EntryFollowLink(commit, "foo/broken_link", entry) res, err := EntryFollowLink(t.Context(), r, commit, "foo/broken_link", entry)
assert.ErrorIs(t, err, util.ErrNotExist) assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "nar/broken_link", res.SymlinkContent) assert.Equal(t, "nar/broken_link", res.SymlinkContent)
} }
{ {
// should error for external links // should error for external links
entry, err := commit.Tree.GetTreeEntryByPath("foo/outside_repo") entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "foo/outside_repo")
require.NoError(t, err) require.NoError(t, err)
assert.True(t, entry.IsLink()) assert.True(t, entry.IsLink())
res, err := EntryFollowLink(commit, "foo/outside_repo", entry) res, err := EntryFollowLink(t.Context(), r, commit, "foo/outside_repo", entry)
assert.ErrorIs(t, err, util.ErrNotExist) assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "../../outside_repo", res.SymlinkContent) assert.Equal(t, "../../outside_repo", res.SymlinkContent)
} }
{ {
// testing fix for short link bug // testing fix for short link bug
entry, err := commit.Tree.GetTreeEntryByPath("foo/link_short") entry, err := commit.Tree().GetTreeEntryByPath(t.Context(), r, "foo/link_short")
require.NoError(t, err) require.NoError(t, err)
res, err := EntryFollowLink(commit, "foo/link_short", entry) res, err := EntryFollowLink(t.Context(), r, commit, "foo/link_short", entry)
assert.ErrorIs(t, err, util.ErrNotExist) assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "a", res.SymlinkContent) assert.Equal(t, "a", res.SymlinkContent)
} }
+7 -5
View File
@@ -7,6 +7,8 @@
package git package git
import ( import (
"context"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/filemode" "github.com/go-git/go-git/v5/plumbing/filemode"
"github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/object"
@@ -29,15 +31,15 @@ func (te *TreeEntry) toGogitTreeEntry() *object.TreeEntry {
} }
} }
// Size returns the size of the entry // GetSize returns the size of the entry
func (te *TreeEntry) Size() int64 { func (te *TreeEntry) GetSize(ctx context.Context, gitRepo *Repository) int64 {
if te.IsDir() { if te.IsDir() {
return 0 return 0
} else if te.sized { } else if te.sized {
return te.size return te.size
} }
ptreeGogitTree, err := te.ptree.gogitTreeObject() ptreeGogitTree, err := te.ptree.gogitTreeObject(gitRepo)
if err != nil { if err != nil {
return 0 return 0
} }
@@ -52,10 +54,10 @@ func (te *TreeEntry) Size() int64 {
} }
// Blob returns the blob object the entry // Blob returns the blob object the entry
func (te *TreeEntry) Blob() *Blob { func (te *TreeEntry) Blob(gitRepo *Repository) *Blob {
return &Blob{ return &Blob{
ID: te.ID, ID: te.ID,
repo: te.ptree.repo, repo: gitRepo,
name: te.Name(), name: te.Name(),
} }
} }
+11 -8
View File
@@ -5,25 +5,28 @@
package git package git
import "gitea.dev/modules/log" import (
"context"
// Size returns the size of the entry "gitea.dev/modules/log"
func (te *TreeEntry) Size() int64 { )
func (te *TreeEntry) GetSize(ctx context.Context, gitRepo *Repository) int64 {
if te.IsDir() { if te.IsDir() {
return 0 return 0
} else if te.sized { } else if te.sized {
return te.size return te.size
} }
batch, cancel, err := te.ptree.repo.CatFileBatch(te.ptree.repo.Ctx) batch, cancel, err := gitRepo.CatFileBatch(ctx)
if err != nil { if err != nil {
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err) log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), gitRepo.Path, err)
return 0 return 0
} }
defer cancel() defer cancel()
info, err := batch.QueryInfo(te.ID.String()) info, err := batch.QueryInfo(te.ID.String())
if err != nil { if err != nil {
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err) log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), gitRepo.Path, err)
return 0 return 0
} }
@@ -33,12 +36,12 @@ func (te *TreeEntry) Size() int64 {
} }
// Blob returns the blob object the entry // Blob returns the blob object the entry
func (te *TreeEntry) Blob() *Blob { func (te *TreeEntry) Blob(gitRepo *Repository) *Blob {
return &Blob{ return &Blob{
ID: te.ID, ID: te.ID,
name: te.Name(), name: te.Name(),
size: te.size, size: te.size,
gotSize: te.sized, gotSize: te.sized,
repo: te.ptree.repo, repo: gitRepo,
} }
} }
+9 -8
View File
@@ -7,6 +7,7 @@
package git package git
import ( import (
"context"
"io" "io"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
@@ -20,9 +21,9 @@ type Tree struct {
resolvedGogitTreeObject *object.Tree resolvedGogitTreeObject *object.Tree
} }
func (t *Tree) gogitTreeObject() (_ *object.Tree, err error) { func (t *Tree) gogitTreeObject(gitRepo *Repository) (_ *object.Tree, err error) {
if t.resolvedGogitTreeObject == nil { if t.resolvedGogitTreeObject == nil {
t.resolvedGogitTreeObject, err = t.repo.gogitRepo.TreeObject(plumbing.Hash(t.ID.RawValue())) t.resolvedGogitTreeObject, err = gitRepo.gogitRepo.TreeObject(plumbing.Hash(t.ID.RawValue()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -31,8 +32,8 @@ func (t *Tree) gogitTreeObject() (_ *object.Tree, err error) {
} }
// ListEntries returns all entries of current tree. // ListEntries returns all entries of current tree.
func (t *Tree) ListEntries() (Entries, error) { func (t *Tree) ListEntries(_ context.Context, gitRepo *Repository) (Entries, error) {
gogitTree, err := t.gogitTreeObject() gogitTree, err := t.gogitTreeObject(gitRepo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -50,8 +51,8 @@ func (t *Tree) ListEntries() (Entries, error) {
} }
// ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees // ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees
func (t *Tree) ListEntriesRecursiveWithSize() (entries Entries, _ error) { func (t *Tree) ListEntriesRecursiveWithSize(_ context.Context, gitRepo *Repository) (entries Entries, _ error) {
gogitTree, err := t.gogitTreeObject() gogitTree, err := t.gogitTreeObject(gitRepo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -76,6 +77,6 @@ func (t *Tree) ListEntriesRecursiveWithSize() (entries Entries, _ error) {
} }
// ListEntriesRecursiveFast is the alias of ListEntriesRecursiveWithSize for the gogit version // ListEntriesRecursiveFast is the alias of ListEntriesRecursiveWithSize for the gogit version
func (t *Tree) ListEntriesRecursiveFast() (Entries, error) { func (t *Tree) ListEntriesRecursiveFast(ctx context.Context, gitRepo *Repository) (Entries, error) {
return t.ListEntriesRecursiveWithSize() return t.ListEntriesRecursiveWithSize(ctx, gitRepo)
} }
+38 -40
View File
@@ -6,6 +6,7 @@
package git package git
import ( import (
"context"
"io" "io"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
@@ -20,49 +21,47 @@ type Tree struct {
} }
// ListEntries returns all entries of current tree. // ListEntries returns all entries of current tree.
func (t *Tree) ListEntries() (Entries, error) { func (t *Tree) ListEntries(ctx context.Context, gitRepo *Repository) (Entries, error) {
if t.entriesParsed { if t.entriesParsed {
return t.entries, nil return t.entries, nil
} }
if t.repo != nil { batch, cancel, err := gitRepo.CatFileBatch(ctx)
batch, cancel, err := t.repo.CatFileBatch(t.repo.Ctx) if err != nil {
if err != nil { return nil, err
}
defer cancel()
info, rd, err := batch.QueryContent(t.ID.String())
if err != nil {
return nil, err
}
if info.Type == "commit" {
treeID, err := ReadTreeID(rd, info.Size)
if err != nil && err != io.EOF {
return nil, err return nil, err
} }
defer cancel() info, rd, err = batch.QueryContent(treeID)
info, rd, err := batch.QueryContent(t.ID.String())
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
if info.Type == "commit" { if info.Type == "tree" {
treeID, err := ReadTreeID(rd, info.Size) t.entries, err = catBatchParseTreeEntries(t.ID.Type(), t, rd, info.Size)
if err != nil && err != io.EOF { if err != nil {
return nil, err return nil, err
} }
info, rd, err = batch.QueryContent(treeID) t.entriesParsed = true
if err != nil { return t.entries, nil
return nil, err
}
}
if info.Type == "tree" {
t.entries, err = catBatchParseTreeEntries(t.ID.Type(), t, rd, info.Size)
if err != nil {
return nil, err
}
t.entriesParsed = true
return t.entries, nil
}
// Not a tree just use ls-tree instead
if err := DiscardFull(rd, info.Size+1); err != nil {
return nil, err
}
} }
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).WithDir(t.repo.Path).RunStdBytes(t.repo.Ctx) // Not a tree just use ls-tree instead
if err := DiscardFull(rd, info.Size+1); err != nil {
return nil, err
}
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).WithDir(gitRepo.Path).RunStdBytes(ctx)
if runErr != nil { if runErr != nil {
if gitcmd.IsStderr(runErr, gitcmd.StderrNotValidObjectName) || gitcmd.IsStderr(runErr, gitcmd.StderrNotTreeObject) { if gitcmd.IsStderr(runErr, gitcmd.StderrNotValidObjectName) || gitcmd.IsStderr(runErr, gitcmd.StderrNotTreeObject) {
return nil, ErrNotExist{ return nil, ErrNotExist{
@@ -72,7 +71,6 @@ func (t *Tree) ListEntries() (Entries, error) {
return nil, runErr return nil, runErr
} }
var err error
t.entries, err = parseTreeEntries(stdout, t) t.entries, err = parseTreeEntries(stdout, t)
if err == nil { if err == nil {
t.entriesParsed = true t.entriesParsed = true
@@ -83,12 +81,12 @@ func (t *Tree) ListEntries() (Entries, error) {
// listEntriesRecursive returns all entries of current tree recursively including all subtrees // listEntriesRecursive returns all entries of current tree recursively including all subtrees
// extraArgs could be "-l" to get the size, which is slower // extraArgs could be "-l" to get the size, which is slower
func (t *Tree) listEntriesRecursive(extraArgs gitcmd.TrustedCmdArgs) (Entries, error) { func (t *Tree) listEntriesRecursive(ctx context.Context, gitRepo *Repository, extraArgs gitcmd.TrustedCmdArgs) (Entries, error) {
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-t", "-r"). stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-t", "-r").
AddArguments(extraArgs...). AddArguments(extraArgs...).
AddDynamicArguments(t.ID.String()). AddDynamicArguments(t.ID.String()).
WithDir(t.repo.Path). WithDir(gitRepo.Path).
RunStdBytes(t.repo.Ctx) RunStdBytes(ctx)
if runErr != nil { if runErr != nil {
return nil, runErr return nil, runErr
} }
@@ -99,11 +97,11 @@ func (t *Tree) listEntriesRecursive(extraArgs gitcmd.TrustedCmdArgs) (Entries, e
} }
// ListEntriesRecursiveFast returns all entries of current tree recursively including all subtrees, no size // ListEntriesRecursiveFast returns all entries of current tree recursively including all subtrees, no size
func (t *Tree) ListEntriesRecursiveFast() (Entries, error) { func (t *Tree) ListEntriesRecursiveFast(ctx context.Context, gitRepo *Repository) (Entries, error) {
return t.listEntriesRecursive(nil) return t.listEntriesRecursive(ctx, gitRepo, nil)
} }
// ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size // ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size
func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) { func (t *Tree) ListEntriesRecursiveWithSize(ctx context.Context, gitRepo *Repository) (Entries, error) {
return t.listEntriesRecursive(gitcmd.TrustedCmdArgs{"--long"}) return t.listEntriesRecursive(ctx, gitRepo, gitcmd.TrustedCmdArgs{"--long"})
} }
+1 -1
View File
@@ -20,7 +20,7 @@ func TestSubTree_Issue29101(t *testing.T) {
// old code could produce a different error if called multiple times // old code could produce a different error if called multiple times
for range 10 { for range 10 {
_, err = commit.SubTree("file1.txt") _, err = commit.SubTree(t.Context(), repo, "file1.txt")
assert.Error(t, err) assert.Error(t, err)
assert.True(t, IsErrNotExist(err)) assert.True(t, IsErrNotExist(err))
} }
+5 -5
View File
@@ -139,7 +139,7 @@ func (r *BlameReader) cleanup() {
} }
// CreateBlameReader creates reader for given repository, commit and file // CreateBlameReader creates reader for given repository, commit and file
func CreateBlameReader(ctx context.Context, objectFormat git.ObjectFormat, repo Repository, commit *git.Commit, file string, bypassBlameIgnore bool) (rd *BlameReader, retErr error) { func CreateBlameReader(ctx context.Context, objectFormat git.ObjectFormat, repo Repository, gitRepo *git.Repository, commit *git.Commit, file string, bypassBlameIgnore bool) (rd *BlameReader, retErr error) {
defer func() { defer func() {
if retErr != nil { if retErr != nil {
rd.cleanup() rd.cleanup()
@@ -158,7 +158,7 @@ func CreateBlameReader(ctx context.Context, objectFormat git.ObjectFormat, repo
rd.cleanupFuncs = append(rd.cleanupFuncs, stdoutReaderClose) rd.cleanupFuncs = append(rd.cleanupFuncs, stdoutReaderClose)
if git.DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore { if git.DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
ignoreRevsFileName, ignoreRevsFileCleanup, err := tryCreateBlameIgnoreRevsFile(commit) ignoreRevsFileName, ignoreRevsFileCleanup, err := tryCreateBlameIgnoreRevsFile(ctx, gitRepo, commit)
if err != nil && !git.IsErrNotExist(err) { if err != nil && !git.IsErrNotExist(err) {
return nil, err return nil, err
} else if err == nil { } else if err == nil {
@@ -180,13 +180,13 @@ func CreateBlameReader(ctx context.Context, objectFormat git.ObjectFormat, repo
return rd, nil return rd, nil
} }
func tryCreateBlameIgnoreRevsFile(commit *git.Commit) (string, func(), error) { func tryCreateBlameIgnoreRevsFile(ctx context.Context, gitRepo *git.Repository, commit *git.Commit) (string, func(), error) {
entry, err := commit.GetTreeEntryByPath(".git-blame-ignore-revs") entry, err := commit.GetTreeEntryByPath(ctx, gitRepo, ".git-blame-ignore-revs")
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
r, err := entry.Blob().DataAsync() r, err := entry.Blob(gitRepo).DataAsync()
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
+2 -2
View File
@@ -49,7 +49,7 @@ func TestReadingBlameOutputSha256(t *testing.T) {
} }
for _, bypass := range []bool{false, true} { for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, git.Sha256ObjectFormat, storage, commit, "README.md", bypass) blameReader, err := CreateBlameReader(ctx, git.Sha256ObjectFormat, storage, repo, commit, "README.md", bypass)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, blameReader) assert.NotNil(t, blameReader)
defer blameReader.Close() defer blameReader.Close()
@@ -134,7 +134,7 @@ func TestReadingBlameOutputSha256(t *testing.T) {
for _, c := range cases { for _, c := range cases {
commit, err := repo.GetCommit(c.CommitID) commit, err := repo.GetCommit(c.CommitID)
assert.NoError(t, err) assert.NoError(t, err)
blameReader, err := CreateBlameReader(ctx, objectFormat, storage, commit, "blame.txt", c.Bypass) blameReader, err := CreateBlameReader(ctx, objectFormat, storage, repo, commit, "blame.txt", c.Bypass)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, blameReader) assert.NotNil(t, blameReader)
defer blameReader.Close() defer blameReader.Close()
+2 -2
View File
@@ -43,7 +43,7 @@ func TestReadingBlameOutput(t *testing.T) {
} }
for _, bypass := range []bool{false, true} { for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, git.Sha1ObjectFormat, storage, commit, "README.md", bypass) blameReader, err := CreateBlameReader(ctx, git.Sha1ObjectFormat, storage, repo, commit, "README.md", bypass)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, blameReader) assert.NotNil(t, blameReader)
defer blameReader.Close() defer blameReader.Close()
@@ -129,7 +129,7 @@ func TestReadingBlameOutput(t *testing.T) {
commit, err := repo.GetCommit(c.CommitID) commit, err := repo.GetCommit(c.CommitID)
assert.NoError(t, err) assert.NoError(t, err)
blameReader, err := CreateBlameReader(ctx, objectFormat, storage, commit, "blame.txt", c.Bypass) blameReader, err := CreateBlameReader(ctx, objectFormat, storage, repo, commit, "blame.txt", c.Bypass)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, blameReader) assert.NotNil(t, blameReader)
defer blameReader.Close() defer blameReader.Close()
+10 -10
View File
@@ -26,7 +26,7 @@ func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (stri
} }
// getRepoChanges returns changes to repo since last indexer update // getRepoChanges returns changes to repo since last indexer update
func getRepoChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) { func getRepoChanges(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, revision string) (*internal.RepoChanges, error) {
status, err := repo_model.GetIndexerStatus(ctx, repo, repo_model.RepoIndexerTypeCode) status, err := repo_model.GetIndexerStatus(ctx, repo, repo_model.RepoIndexerTypeCode)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -40,9 +40,9 @@ func getRepoChanges(ctx context.Context, repo *repo_model.Repository, revision s
} }
if needGenesis { if needGenesis {
return genesisChanges(ctx, repo, revision) return genesisChanges(ctx, repo, gitRepo, revision)
} }
return nonGenesisChanges(ctx, repo, revision) return nonGenesisChanges(ctx, repo, gitRepo, revision)
} }
func isIndexable(entry *git.TreeEntry) bool { func isIndexable(entry *git.TreeEntry) bool {
@@ -64,7 +64,7 @@ func isIndexable(entry *git.TreeEntry) bool {
} }
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command // parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
func parseGitLsTreeOutput(stdout []byte) ([]internal.FileUpdate, error) { func parseGitLsTreeOutput(ctx context.Context, gitRepo *git.Repository, stdout []byte) ([]internal.FileUpdate, error) {
entries, err := git.ParseTreeEntries(stdout) entries, err := git.ParseTreeEntries(stdout)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -76,7 +76,7 @@ func parseGitLsTreeOutput(stdout []byte) ([]internal.FileUpdate, error) {
updates[idxCount] = internal.FileUpdate{ updates[idxCount] = internal.FileUpdate{
Filename: entry.Name(), Filename: entry.Name(),
BlobSha: entry.ID.String(), BlobSha: entry.ID.String(),
Size: entry.Size(), Size: entry.GetSize(ctx, gitRepo),
Sized: true, Sized: true,
} }
idxCount++ idxCount++
@@ -86,7 +86,7 @@ func parseGitLsTreeOutput(stdout []byte) ([]internal.FileUpdate, error) {
} }
// genesisChanges get changes to add repo to the indexer for the first time // genesisChanges get changes to add repo to the indexer for the first time
func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) { func genesisChanges(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, revision string) (*internal.RepoChanges, error) {
var changes internal.RepoChanges var changes internal.RepoChanges
stdout, _, runErr := gitrepo.RunCmdBytes(ctx, repo, gitcmd.NewCommand("ls-tree", "--full-tree", "-l", "-r").AddDynamicArguments(revision)) stdout, _, runErr := gitrepo.RunCmdBytes(ctx, repo, gitcmd.NewCommand("ls-tree", "--full-tree", "-l", "-r").AddDynamicArguments(revision))
if runErr != nil { if runErr != nil {
@@ -94,12 +94,12 @@ func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision s
} }
var err error var err error
changes.Updates, err = parseGitLsTreeOutput(stdout) changes.Updates, err = parseGitLsTreeOutput(ctx, gitRepo, stdout)
return &changes, err return &changes, err
} }
// nonGenesisChanges get changes since the previous indexer update // nonGenesisChanges get changes since the previous indexer update
func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) { func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, revision string) (*internal.RepoChanges, error) {
diffCmd := gitcmd.NewCommand("diff", "--name-status").AddDynamicArguments(repo.CodeIndexerStatus.CommitSha, revision) diffCmd := gitcmd.NewCommand("diff", "--name-status").AddDynamicArguments(repo.CodeIndexerStatus.CommitSha, revision)
stdout, _, runErr := gitrepo.RunCmdString(ctx, repo, diffCmd) stdout, _, runErr := gitrepo.RunCmdString(ctx, repo, diffCmd)
if runErr != nil { if runErr != nil {
@@ -109,7 +109,7 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio
if err := (*globalIndexer.Load()).Delete(ctx, repo.ID); err != nil { if err := (*globalIndexer.Load()).Delete(ctx, repo.ID); err != nil {
return nil, err return nil, err
} }
return genesisChanges(ctx, repo, revision) return genesisChanges(ctx, repo, gitRepo, revision)
} }
var changes internal.RepoChanges var changes internal.RepoChanges
@@ -124,7 +124,7 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio
return err return err
} }
updates, err1 := parseGitLsTreeOutput(lsTreeStdout) updates, err1 := parseGitLsTreeOutput(ctx, gitRepo, lsTreeStdout)
if err1 != nil { if err1 != nil {
return err1 return err1
} }
+8 -1
View File
@@ -13,6 +13,7 @@ import (
"gitea.dev/models/db" "gitea.dev/models/db"
repo_model "gitea.dev/models/repo" repo_model "gitea.dev/models/repo"
"gitea.dev/modules/gitrepo"
"gitea.dev/modules/graceful" "gitea.dev/modules/graceful"
"gitea.dev/modules/indexer" "gitea.dev/modules/indexer"
"gitea.dev/modules/indexer/code/bleve" "gitea.dev/modules/indexer/code/bleve"
@@ -73,11 +74,17 @@ func index(ctx context.Context, indexer internal.Indexer, repoID int64) error {
return nil return nil
} }
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
if err != nil {
return err
}
defer closer.Close()
sha, err := getDefaultBranchSha(ctx, repo) sha, err := getDefaultBranchSha(ctx, repo)
if err != nil { if err != nil {
return err return err
} }
changes, err := getRepoChanges(ctx, repo, sha) changes, err := getRepoChanges(ctx, repo, gitRepo, sha)
if err != nil { if err != nil {
return err return err
} else if changes == nil { } else if changes == nil {
+1 -1
View File
@@ -63,7 +63,7 @@ func (db *DBIndexer) Index(id int64) error {
} }
// Calculate and save language statistics to database // Calculate and save language statistics to database
stats, err := languagestats.GetLanguageStats(gitRepo, commitID) stats, err := languagestats.GetLanguageStats(ctx, gitRepo, commitID)
if err != nil { if err != nil {
if !setting.IsInTesting { if !setting.IsInTesting {
log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.FullName(), err) log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.FullName(), err)
+11 -10
View File
@@ -4,6 +4,7 @@
package template package template
import ( import (
"context"
"fmt" "fmt"
"path" "path"
"strconv" "strconv"
@@ -41,35 +42,35 @@ func Unmarshal(filename string, content []byte) (*api.IssueTemplate, error) {
} }
// UnmarshalFromEntry parses out a valid template from the blob in entry // UnmarshalFromEntry parses out a valid template from the blob in entry
func UnmarshalFromEntry(entry *git.TreeEntry, dir string) (*api.IssueTemplate, error) { func UnmarshalFromEntry(gitRepo *git.Repository, entry *git.TreeEntry, dir string) (*api.IssueTemplate, error) {
return unmarshalFromEntry(entry, path.Join(dir, entry.Name())) // Filepaths in Git are ALWAYS '/' separated do not use filepath here return unmarshalFromEntry(gitRepo, entry, path.Join(dir, entry.Name())) // Filepaths in Git are ALWAYS '/' separated do not use filepath here
} }
// UnmarshalFromCommit parses out a valid template from the commit // UnmarshalFromCommit parses out a valid template from the commit
func UnmarshalFromCommit(commit *git.Commit, filename string) (*api.IssueTemplate, error) { func UnmarshalFromCommit(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, filename string) (*api.IssueTemplate, error) {
entry, err := commit.GetTreeEntryByPath(filename) entry, err := commit.GetTreeEntryByPath(ctx, gitRepo, filename)
if err != nil { if err != nil {
return nil, fmt.Errorf("get entry for %q: %w", filename, err) return nil, fmt.Errorf("get entry for %q: %w", filename, err)
} }
return unmarshalFromEntry(entry, filename) return unmarshalFromEntry(gitRepo, entry, filename)
} }
// UnmarshalFromRepo parses out a valid template from the head commit of the branch // UnmarshalFromRepo parses out a valid template from the head commit of the branch
func UnmarshalFromRepo(repo *git.Repository, branch, filename string) (*api.IssueTemplate, error) { func UnmarshalFromRepo(ctx context.Context, repo *git.Repository, branch, filename string) (*api.IssueTemplate, error) {
commit, err := repo.GetBranchCommit(branch) commit, err := repo.GetBranchCommit(branch)
if err != nil { if err != nil {
return nil, fmt.Errorf("get commit on branch %q: %w", branch, err) return nil, fmt.Errorf("get commit on branch %q: %w", branch, err)
} }
return UnmarshalFromCommit(commit, filename) return UnmarshalFromCommit(ctx, repo, commit, filename)
} }
func unmarshalFromEntry(entry *git.TreeEntry, filename string) (*api.IssueTemplate, error) { func unmarshalFromEntry(gitRepo *git.Repository, entry *git.TreeEntry, filename string) (*api.IssueTemplate, error) {
if size := entry.Blob().Size(); size > setting.UI.MaxDisplayFileSize { if size := entry.Blob(gitRepo).Size(); size > setting.UI.MaxDisplayFileSize {
return nil, fmt.Errorf("too large: %v > MaxDisplayFileSize", size) return nil, fmt.Errorf("too large: %v > MaxDisplayFileSize", size)
} }
r, err := entry.Blob().DataAsync() r, err := entry.Blob(gitRepo).DataAsync()
if err != nil { if err != nil {
return nil, fmt.Errorf("data async: %w", err) return nil, fmt.Errorf("data async: %w", err)
} }
+1 -1
View File
@@ -235,7 +235,7 @@ func GetAllCommits(ctx *context.APIContext) {
} }
// Query commits // Query commits
commits, err = baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize, not, since, until) commits, err = baseCommit.CommitsByRange(ctx.Repo.GitRepo, listOptions.Page, listOptions.PageSize, not, since, until)
if err != nil { if err != nil {
ctx.APIErrorInternal(err) ctx.APIErrorInternal(err)
return return
+3 -3
View File
@@ -202,7 +202,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
} }
func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, entry *git.TreeEntry, lastModified *time.Time) { func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, entry *git.TreeEntry, lastModified *time.Time) {
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
if git.IsErrNotExist(err) { if git.IsErrNotExist(err) {
ctx.APIErrorNotFound() ctx.APIErrorNotFound()
@@ -224,7 +224,7 @@ func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, entry *git.TreeEn
} }
when := &latestCommit.Committer.When when := &latestCommit.Committer.When
return entry.Blob(), entry, when return entry.Blob(ctx.Repo.GitRepo), entry, when
} }
// GetArchive get archive of a repository // GetArchive get archive of a repository
@@ -299,7 +299,7 @@ func GetEditorconfig(ctx *context.APIContext) {
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
ec, _, err := ctx.Repo.GetEditorconfig(ctx.Repo.Commit) ec, _, err := ctx.Repo.GetEditorconfig(ctx, ctx.Repo.Commit)
if err != nil { if err != nil {
ctx.APIErrorAuto(err) ctx.APIErrorAuto(err)
return return
+3 -3
View File
@@ -1200,7 +1200,7 @@ func GetIssueTemplates(ctx *context.APIContext) {
// "$ref": "#/responses/IssueTemplates" // "$ref": "#/responses/IssueTemplates"
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
ret := issue.ParseTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ret := issue.ParseTemplatesFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
if cnt := len(ret.TemplateErrors); cnt != 0 { if cnt := len(ret.TemplateErrors); cnt != 0 {
ctx.Resp.Header().Add("X-Gitea-Warning", "error occurs when parsing issue template: count="+strconv.Itoa(cnt)) ctx.Resp.Header().Add("X-Gitea-Warning", "error occurs when parsing issue template: count="+strconv.Itoa(cnt))
} }
@@ -1230,7 +1230,7 @@ func GetIssueConfig(ctx *context.APIContext) {
// "$ref": "#/responses/RepoIssueConfig" // "$ref": "#/responses/RepoIssueConfig"
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
issueConfig, _ := issue.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) issueConfig, _ := issue.GetTemplateConfigFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
ctx.JSON(http.StatusOK, issueConfig) ctx.JSON(http.StatusOK, issueConfig)
} }
@@ -1257,7 +1257,7 @@ func ValidateIssueConfig(ctx *context.APIContext) {
// "$ref": "#/responses/RepoIssueConfigValidation" // "$ref": "#/responses/RepoIssueConfigValidation"
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
_, err := issue.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) _, err := issue.GetTemplateConfigFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
if err == nil { if err == nil {
ctx.JSON(http.StatusOK, api.IssueConfigValidation{Valid: true, Message: ""}) ctx.JSON(http.StatusOK, api.IssueConfigValidation{Valid: true, Message: ""})
+1 -1
View File
@@ -62,7 +62,7 @@ func GetTree(ctx *context.APIContext) {
return return
} }
if tree, err := files_service.GetTreeBySHA(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, sha, ctx.FormInt("page"), ctx.FormInt("per_page"), ctx.FormBool("recursive")); err != nil { if tree, err := files_service.GetTreeBySHA(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, sha, ctx.FormInt("page"), ctx.FormInt("per_page"), ctx.FormBool("recursive")); err != nil {
ctx.APIError(http.StatusBadRequest, err.Error()) ctx.APIErrorAuto(err)
} else { } else {
ctx.SetTotalCountHeader(int64(tree.TotalCount)) ctx.SetTotalCountHeader(int64(tree.TotalCount))
ctx.JSON(http.StatusOK, tree) ctx.JSON(http.StatusOK, tree)
+13 -13
View File
@@ -177,17 +177,17 @@ func getWikiPage(ctx *context.APIContext, wikiName wiki_service.WebPath) *api.Wi
} }
// lookup filename in wiki - get filecontent, real filename // lookup filename in wiki - get filecontent, real filename
content, pageFilename := wikiContentsByName(ctx, commit, wikiName, false) content, pageFilename := wikiContentsByName(ctx, wikiRepo, commit, wikiName, false)
if ctx.Written() { if ctx.Written() {
return nil return nil
} }
sidebarContent, _ := wikiContentsByName(ctx, commit, "_Sidebar", true) sidebarContent, _ := wikiContentsByName(ctx, wikiRepo, commit, "_Sidebar", true)
if ctx.Written() { if ctx.Written() {
return nil return nil
} }
footerContent, _ := wikiContentsByName(ctx, commit, "_Footer", true) footerContent, _ := wikiContentsByName(ctx, wikiRepo, commit, "_Footer", true)
if ctx.Written() { if ctx.Written() {
return nil return nil
} }
@@ -303,7 +303,7 @@ func ListWikiPages(ctx *context.APIContext) {
skip := (page - 1) * limit skip := (page - 1) * limit
maxNum := page * limit maxNum := page * limit
entries, err := commit.ListEntries() entries, err := commit.Tree().ListEntries(ctx, wikiRepo)
if err != nil { if err != nil {
ctx.APIErrorInternal(err) ctx.APIErrorInternal(err)
return return
@@ -420,7 +420,7 @@ func ListPageRevisions(ctx *context.APIContext) {
} }
// lookup filename in wiki - get filecontent, gitTree entry , real filename // lookup filename in wiki - get filecontent, gitTree entry , real filename
_, pageFilename := wikiContentsByName(ctx, commit, pageName, false) _, pageFilename := wikiContentsByName(ctx, wikiRepo, commit, pageName, false)
if ctx.Written() { if ctx.Written() {
return return
} }
@@ -448,8 +448,8 @@ func ListPageRevisions(ctx *context.APIContext) {
} }
// findEntryForFile finds the tree entry for a target filepath. // findEntryForFile finds the tree entry for a target filepath.
func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) { func findEntryForFile(ctx *context.APIContext, wikiRepo *git.Repository, commit *git.Commit, target string) (*git.TreeEntry, error) {
entry, err := commit.GetTreeEntryByPath(target) entry, err := commit.GetTreeEntryByPath(ctx, wikiRepo, target)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -462,7 +462,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
if unescapedTarget, err = url.QueryUnescape(target); err != nil { if unescapedTarget, err = url.QueryUnescape(target); err != nil {
return nil, err return nil, err
} }
return commit.GetTreeEntryByPath(unescapedTarget) return commit.GetTreeEntryByPath(ctx, wikiRepo, unescapedTarget)
} }
// findWikiRepoCommit opens the wiki repo and returns the latest commit, writing to context on error. // findWikiRepoCommit opens the wiki repo and returns the latest commit, writing to context on error.
@@ -484,8 +484,8 @@ func findWikiRepoCommit(ctx *context.APIContext) (*git.Repository, *git.Commit)
// wikiContentsByEntry returns the contents of the wiki page referenced by the // wikiContentsByEntry returns the contents of the wiki page referenced by the
// given tree entry, encoded with base64. Writes to ctx if an error occurs. // given tree entry, encoded with base64. Writes to ctx if an error occurs.
func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string { func wikiContentsByEntry(ctx *context.APIContext, wikiRepo *git.Repository, entry *git.TreeEntry) string {
blob := entry.Blob() blob := entry.Blob(wikiRepo)
if blob.Size() > setting.API.DefaultMaxBlobSize { if blob.Size() > setting.API.DefaultMaxBlobSize {
return "" return ""
} }
@@ -499,9 +499,9 @@ func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string {
// wikiContentsByName returns the contents of a wiki page, along with a boolean // wikiContentsByName returns the contents of a wiki page, along with a boolean
// indicating whether the page exists. Writes to ctx if an error occurs. // indicating whether the page exists. Writes to ctx if an error occurs.
func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName wiki_service.WebPath, isSidebarOrFooter bool) (string, string) { func wikiContentsByName(ctx *context.APIContext, wikiRepo *git.Repository, commit *git.Commit, wikiName wiki_service.WebPath, isSidebarOrFooter bool) (string, string) {
gitFilename := wiki_service.WebPathToGitPath(wikiName) gitFilename := wiki_service.WebPathToGitPath(wikiName)
entry, err := findEntryForFile(commit, gitFilename) entry, err := findEntryForFile(ctx, wikiRepo, commit, gitFilename)
if err != nil { if err != nil {
if git.IsErrNotExist(err) { if git.IsErrNotExist(err) {
if !isSidebarOrFooter { if !isSidebarOrFooter {
@@ -512,5 +512,5 @@ func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName wi
} }
return "", "" return "", ""
} }
return wikiContentsByEntry(ctx, entry), gitFilename return wikiContentsByEntry(ctx, wikiRepo, entry), gitFilename
} }
+1 -1
View File
@@ -64,7 +64,7 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
return cmd.WithEnv(env). return cmd.WithEnv(env).
WithDir(repo.Path). WithDir(repo.Path).
WithPipelineFunc(func(ctx gitcmd.Context) error { WithPipelineFunc(func(ctx gitcmd.Context) error {
commit, err := git.CommitFromReader(repo, commitID, stdoutReader) commit, err := git.CommitFromReader(commitID, stdoutReader)
if err != nil { if err != nil {
return err return err
} }
+1 -1
View File
@@ -21,7 +21,7 @@ func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType stri
var commits []*git.Commit var commits []*git.Commit
var err error var err error
if ctx.Repo.Commit != nil { if ctx.Repo.Commit != nil {
commits, err = ctx.Repo.Commit.CommitsByRange(0, 10, "", "", "") commits, err = ctx.Repo.Commit.CommitsByRange(ctx.Repo.GitRepo, 0, 10, "", "", "")
if err != nil { if err != nil {
ctx.ServerError("ShowBranchFeed", err) ctx.ServerError("ShowBranchFeed", err)
return return
+2 -2
View File
@@ -206,7 +206,7 @@ func WorkflowDispatchInputs(ctx *context.Context) {
func prepareWorkflowTemplate(ctx *context.Context, commit *git.Commit) (workflows []WorkflowInfo, curWorkflowID string) { func prepareWorkflowTemplate(ctx *context.Context, commit *git.Commit) (workflows []WorkflowInfo, curWorkflowID string) {
curWorkflowID = ctx.FormString("workflow") curWorkflowID = ctx.FormString("workflow")
_, entries, err := actions.ListWorkflows(commit) _, entries, err := actions.ListWorkflows(ctx, ctx.Repo.GitRepo, commit)
if err != nil { if err != nil {
ctx.ServerError("ListWorkflows", err) ctx.ServerError("ListWorkflows", err)
return nil, "" return nil, ""
@@ -215,7 +215,7 @@ func prepareWorkflowTemplate(ctx *context.Context, commit *git.Commit) (workflow
workflows = make([]WorkflowInfo, 0, len(entries)) workflows = make([]WorkflowInfo, 0, len(entries))
for _, entry := range entries { for _, entry := range entries {
workflow := WorkflowInfo{EntryName: entry.Name()} workflow := WorkflowInfo{EntryName: entry.Name()}
content, err := actions.GetContentFromEntry(entry) content, err := actions.GetContentFromEntry(ctx.Repo.GitRepo, entry)
if err != nil { if err != nil {
ctx.ServerError("GetContentFromEntry", err) ctx.ServerError("GetContentFromEntry", err)
return nil, "" return nil, ""
+2 -2
View File
@@ -257,7 +257,7 @@ func ViewWorkflowFile(ctx *context_module.Context) {
}, err) }, err)
return return
} }
rpath, entries, err := actions.ListWorkflows(commit) rpath, entries, err := actions.ListWorkflows(ctx, ctx.Repo.GitRepo, commit)
if err != nil { if err != nil {
ctx.ServerError("ListWorkflows", err) ctx.ServerError("ListWorkflows", err)
return return
@@ -1414,7 +1414,7 @@ func viewScopedWorkflowFile(ctx *context_module.Context, run *actions_model.Acti
}, err) }, err)
return return
} }
rpath, entries, err := actions.ListScopedWorkflows(commit) rpath, entries, err := actions.ListScopedWorkflows(ctx, sourceGitRepo, commit)
if err != nil { if err != nil {
ctx.ServerError("ListScopedWorkflows", err) ctx.ServerError("ListScopedWorkflows", err)
return return
+10 -7
View File
@@ -13,7 +13,6 @@ import (
"strconv" "strconv"
"gitea.dev/models/gituser" "gitea.dev/models/gituser"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/charset" "gitea.dev/modules/charset"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/git/languagestats" "gitea.dev/modules/git/languagestats"
@@ -51,13 +50,13 @@ func RefBlame(ctx *context.Context) {
ctx.NotFound(nil) ctx.NotFound(nil)
return return
} }
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err)
return return
} }
blob := entry.Blob() blob := entry.Blob(ctx.Repo.GitRepo)
fileSize := blob.Size() fileSize := blob.Size()
ctx.Data["FileSize"] = fileSize ctx.Data["FileSize"] = fileSize
ctx.Data["FileTreePath"] = ctx.Repo.TreePath ctx.Data["FileTreePath"] = ctx.Repo.TreePath
@@ -81,7 +80,7 @@ func RefBlame(ctx *context.Context) {
} }
bypassBlameIgnore, _ := strconv.ParseBool(ctx.FormString("bypass-blame-ignore")) bypassBlameIgnore, _ := strconv.ParseBool(ctx.FormString("bypass-blame-ignore"))
result, err := performBlame(ctx, ctx.Repo.Repository, ctx.Repo.Commit, ctx.Repo.TreePath, bypassBlameIgnore) result, err := performBlame(ctx, bypassBlameIgnore)
if err != nil { if err != nil {
ctx.NotFound(err) ctx.NotFound(err)
return return
@@ -106,10 +105,14 @@ type blameResult struct {
FaultyIgnoreRevsFile bool FaultyIgnoreRevsFile bool
} }
func performBlame(ctx *context.Context, repo *repo_model.Repository, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) { func performBlame(ctx *context.Context, bypassBlameIgnore bool) (*blameResult, error) {
repo := ctx.Repo.Repository
gitRepo := ctx.Repo.GitRepo
commit := ctx.Repo.Commit
file := ctx.Repo.TreePath
objectFormat := ctx.Repo.GetObjectFormat() objectFormat := ctx.Repo.GetObjectFormat()
blameReader, err := gitrepo.CreateBlameReader(ctx, objectFormat, repo, commit, file, bypassBlameIgnore) blameReader, err := gitrepo.CreateBlameReader(ctx, objectFormat, repo, gitRepo, commit, file, bypassBlameIgnore)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -125,7 +128,7 @@ func performBlame(ctx *context.Context, repo *repo_model.Repository, commit *git
if len(r.Parts) == 0 && r.UsesIgnoreRevs { if len(r.Parts) == 0 && r.UsesIgnoreRevs {
// try again without ignored revs // try again without ignored revs
blameReader, err = gitrepo.CreateBlameReader(ctx, objectFormat, repo, commit, file, true) blameReader, err = gitrepo.CreateBlameReader(ctx, objectFormat, repo, gitRepo, commit, file, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+2 -2
View File
@@ -76,7 +76,7 @@ func Commits(ctx *context.Context) {
} }
// Both `git log branchName` and `git log commitId` work. // Both `git log branchName` and `git log commitId` work.
commits, err := ctx.Repo.Commit.CommitsByRange(page, pageSize, "", "", "") commits, err := ctx.Repo.Commit.CommitsByRange(ctx.Repo.GitRepo, page, pageSize, "", "", "")
if err != nil { if err != nil {
ctx.ServerError("CommitsByRange", err) ctx.ServerError("CommitsByRange", err)
return return
@@ -189,7 +189,7 @@ func SearchCommits(ctx *context.Context) {
all := ctx.FormBool("all") all := ctx.FormBool("all")
opts := git.NewSearchCommitsOptions(query, all) opts := git.NewSearchCommitsOptions(query, all)
commits, err := ctx.Repo.Commit.SearchCommits(opts) commits, err := ctx.Repo.Commit.SearchCommits(ctx.Repo.GitRepo, opts)
if err != nil { if err != nil {
ctx.ServerError("SearchCommits", err) ctx.ServerError("SearchCommits", err)
return return
+2 -2
View File
@@ -61,7 +61,7 @@ func setCompareContext(ctx *context.Context, before, head *git.Commit, headOwner
return nil return nil
} }
blob, err := commit.GetBlobByPath(path) blob, err := commit.GetBlobByPath(ctx, ctx.Repo.GitRepo, path)
if err != nil { if err != nil {
return nil return nil
} }
@@ -773,7 +773,7 @@ func ExcerptBlob(ctx *context.Context) {
ctx.ServerError("GetCommit", err) ctx.ServerError("GetCommit", err)
return return
} }
blob, err := commit.Tree.GetBlobByPath(filePath) blob, err := commit.GetBlobByPath(ctx, ctx.Repo.GitRepo, filePath)
if err != nil { if err != nil {
ctx.ServerError("GetBlobByPath", err) ctx.ServerError("GetBlobByPath", err)
return return
+2 -2
View File
@@ -67,7 +67,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Tim
} }
func getBlobForEntry(ctx *context.Context) (*git.Blob, *time.Time) { func getBlobForEntry(ctx *context.Context) (*git.Blob, *time.Time) {
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
if git.IsErrNotExist(err) { if git.IsErrNotExist(err) {
ctx.NotFound(err) ctx.NotFound(err)
@@ -89,7 +89,7 @@ func getBlobForEntry(ctx *context.Context) (*git.Blob, *time.Time) {
} }
lastModified := &latestCommit.Committer.When lastModified := &latestCommit.Committer.When
return entry.Blob(), lastModified return entry.Blob(ctx.Repo.GitRepo), lastModified
} }
// SingleDownload download a file by repos path // SingleDownload download a file by repos path
+4 -4
View File
@@ -224,7 +224,7 @@ func redirectForCommitChoice[T any](ctx *context.Context, parsed *preparedEditor
} }
func editFileOpenExisting(ctx *context.Context) (prefetch []byte, dataRc io.ReadCloser, fInfo *fileInfo) { func editFileOpenExisting(ctx *context.Context) (prefetch []byte, dataRc io.ReadCloser, fInfo *fileInfo) {
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
HandleGitError(ctx, "GetTreeEntryByPath", err) HandleGitError(ctx, "GetTreeEntryByPath", err)
return nil, nil, nil return nil, nil, nil
@@ -236,7 +236,7 @@ func editFileOpenExisting(ctx *context.Context) (prefetch []byte, dataRc io.Read
return nil, nil, nil return nil, nil, nil
} }
blob := entry.Blob() blob := entry.Blob(ctx.Repo.GitRepo)
buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, blob) buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, blob)
if err != nil { if err != nil {
if git.IsErrNotExist(err) { if git.IsErrNotExist(err) {
@@ -403,7 +403,7 @@ func DeleteFilePost(ctx *context.Context) {
} }
// Check if the path is a directory // Check if the path is a directory
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, treePath)
if err != nil { if err != nil {
ctx.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err) ctx.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err)
return return
@@ -442,7 +442,7 @@ func DeleteFilePost(ctx *context.Context) {
} else { } else {
ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", treePath)) ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", treePath))
} }
redirectTreePath := getClosestParentWithFiles(ctx.Repo.GitRepo, parsed.NewBranchName, treePath) redirectTreePath := getClosestParentWithFiles(ctx, ctx.Repo.GitRepo, parsed.NewBranchName, treePath)
redirectForCommitChoice(ctx, parsed, redirectTreePath) redirectForCommitChoice(ctx, parsed, redirectTreePath)
} }
+2 -2
View File
@@ -19,7 +19,7 @@ func DiffPreviewPost(ctx *context.Context) {
return return
} }
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, treePath)
if err != nil { if err != nil {
ctx.ServerError("GetTreeEntryByPath", err) ctx.ServerError("GetTreeEntryByPath", err)
return return
@@ -28,7 +28,7 @@ func DiffPreviewPost(ctx *context.Context) {
return return
} }
oldContent, err := entry.Blob().GetBlobContent(setting.UI.MaxDisplayFileSize) oldContent, err := entry.Blob(ctx.Repo.GitRepo).GetBlobContent(setting.UI.MaxDisplayFileSize)
if err != nil { if err != nil {
ctx.ServerError("GetBlobContent", err) ctx.ServerError("GetBlobContent", err)
return return
+2 -2
View File
@@ -23,9 +23,9 @@ func TestEditorUtils(t *testing.T) {
t.Run("getClosestParentWithFiles", func(t *testing.T) { t.Run("getClosestParentWithFiles", func(t *testing.T) {
gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo) gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo)
defer gitRepo.Close() defer gitRepo.Close()
treePath := getClosestParentWithFiles(gitRepo, "sub-home-md-img-check", "docs/foo/bar") treePath := getClosestParentWithFiles(t.Context(), gitRepo, "sub-home-md-img-check", "docs/foo/bar")
assert.Equal(t, "docs", treePath) assert.Equal(t, "docs", treePath)
treePath = getClosestParentWithFiles(gitRepo, "sub-home-md-img-check", "any/other") treePath = getClosestParentWithFiles(t.Context(), gitRepo, "sub-home-md-img-check", "any/other")
assert.Empty(t, treePath) assert.Empty(t, treePath)
}) })
} }
+4 -4
View File
@@ -43,16 +43,16 @@ func getUniquePatchBranchName(ctx context.Context, prefixName string, repo *repo
// getClosestParentWithFiles Recursively gets the closest path of parent in a tree that has files when a file in a tree is // getClosestParentWithFiles Recursively gets the closest path of parent in a tree that has files when a file in a tree is
// deleted. It returns "" for the tree root if no parents other than the root have files. // deleted. It returns "" for the tree root if no parents other than the root have files.
func getClosestParentWithFiles(gitRepo *git.Repository, branchName, originTreePath string) string { func getClosestParentWithFiles(ctx context.Context, gitRepo *git.Repository, branchName, originTreePath string) string {
var f func(treePath string, commit *git.Commit) string var f func(treePath string, commit *git.Commit) string
f = func(treePath string, commit *git.Commit) string { f = func(treePath string, commit *git.Commit) string {
if treePath == "" || treePath == "." { if treePath == "" || treePath == "." {
return "" return ""
} }
// see if the tree has entries // see if the tree has entries
if tree, err := commit.SubTree(treePath); err != nil { if tree, err := commit.SubTree(ctx, gitRepo, treePath); err != nil {
return f(path.Dir(treePath), commit) // failed to get the tree, going up a dir return f(path.Dir(treePath), commit) // failed to get the tree, going up a dir
} else if entries, err := tree.ListEntries(); err != nil || len(entries) == 0 { } else if entries, err := tree.ListEntries(ctx, gitRepo); err != nil || len(entries) == 0 {
return f(path.Dir(treePath), commit) // no files in this dir, going up a dir return f(path.Dir(treePath), commit) // no files in this dir, going up a dir
} }
return treePath return treePath
@@ -87,7 +87,7 @@ func getCodeEditorConfigByEditorconfig(ctx *context_service.Context, treePath st
ret.LineWrapExtensions = setting.Repository.Editor.LineWrapExtensions ret.LineWrapExtensions = setting.Repository.Editor.LineWrapExtensions
ret.LineWrap = util.SliceContainsString(ret.LineWrapExtensions, path.Ext(treePath), true) ret.LineWrap = util.SliceContainsString(ret.LineWrapExtensions, path.Ext(treePath), true)
ret.Previewable = util.SliceContainsString(ret.PreviewableExtensions, path.Ext(treePath), true) ret.Previewable = util.SliceContainsString(ret.PreviewableExtensions, path.Ext(treePath), true)
ec, _, err := ctx.Repo.GetEditorconfig() ec, _, err := ctx.Repo.GetEditorconfig(ctx)
if err == nil { if err == nil {
def, err := ec.GetDefinitionForFilename(treePath) def, err := ec.GetDefinitionForFilename(treePath)
if err == nil { if err == nil {
+1 -1
View File
@@ -754,7 +754,7 @@ func Issues(ctx *context.Context) {
} }
ctx.Data["Title"] = ctx.Tr("repo.issues") ctx.Data["Title"] = ctx.Tr("repo.issues")
ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsIssueList"] = true
ctx.Data["NewIssueChooseTemplate"] = issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo) ctx.Data["NewIssueChooseTemplate"] = issue_service.HasTemplatesOrContactLinks(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
} }
projectIDs := parseProjectIDsFromQuery(ctx) projectIDs := parseProjectIDsFromQuery(ctx)
+9 -9
View File
@@ -51,10 +51,10 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
templateErrs := map[string]error{} templateErrs := map[string]error{}
for _, filename := range templateCandidates { for _, filename := range templateCandidates {
if ok, _ := commit.HasFile(filename); !ok { template, err := issue_template.UnmarshalFromCommit(ctx, ctx.Repo.GitRepo, commit, filename)
if errors.Is(err, util.ErrNotExist) {
continue continue
} }
template, err := issue_template.UnmarshalFromCommit(commit, filename)
if err != nil { if err != nil {
templateErrs[filename] = err templateErrs[filename] = err
continue continue
@@ -98,8 +98,8 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
// NewIssue render creating issue page // NewIssue render creating issue page
func NewIssue(ctx *context.Context) { func NewIssue(ctx *context.Context) {
issueConfig, _ := issue_service.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) issueConfig, _ := issue_service.GetTemplateConfigFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
hasTemplates := issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo) hasTemplates := issue_service.HasTemplatesOrContactLinks(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
ctx.Data["Title"] = ctx.Tr("repo.issues.new") ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsIssueList"] = true
@@ -134,7 +134,7 @@ func NewIssue(ctx *context.Context) {
} }
ctx.Data["Tags"] = tags ctx.Data["Tags"] = tags
ret := issue_service.ParseTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ret := issue_service.ParseTemplatesFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
templateLoaded, errs := setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates, pageMetaData) templateLoaded, errs := setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates, pageMetaData)
maps.Copy(ret.TemplateErrors, errs) maps.Copy(ret.TemplateErrors, errs)
if ctx.Written() { if ctx.Written() {
@@ -186,20 +186,20 @@ func NewIssueChooseTemplate(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.issues.new") ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsIssueList"] = true
ret := issue_service.ParseTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ret := issue_service.ParseTemplatesFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
ctx.Data["IssueTemplates"] = ret.IssueTemplates ctx.Data["IssueTemplates"] = ret.IssueTemplates
if len(ret.TemplateErrors) > 0 { if len(ret.TemplateErrors) > 0 {
ctx.Flash.Warning(renderErrorOfTemplates(ctx, ret.TemplateErrors), true) ctx.Flash.Warning(renderErrorOfTemplates(ctx, ret.TemplateErrors), true)
} }
if !issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo) { if !issue_service.HasTemplatesOrContactLinks(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) {
// The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if no template here, just redirect to the "issues/new" page with these parameters. // The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if no template here, just redirect to the "issues/new" page with these parameters.
ctx.Redirect(fmt.Sprintf("%s/issues/new?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther) ctx.Redirect(fmt.Sprintf("%s/issues/new?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther)
return return
} }
issueConfig, err := issue_service.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) issueConfig, err := issue_service.GetTemplateConfigFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
ctx.Data["IssueConfig"] = issueConfig ctx.Data["IssueConfig"] = issueConfig
ctx.Data["IssueConfigError"] = err // ctx.Flash.Err makes problems here ctx.Data["IssueConfigError"] = err // ctx.Flash.Err makes problems here
@@ -358,7 +358,7 @@ func NewIssuePost(ctx *context.Context) {
content := form.Content content := form.Content
if filename := ctx.Req.Form.Get("template-file"); filename != "" { if filename := ctx.Req.Form.Get("template-file"); filename != "" {
if template, err := issue_template.UnmarshalFromRepo(ctx.Repo.GitRepo, ctx.Repo.Repository.DefaultBranch, filename); err == nil { if template, err := issue_template.UnmarshalFromRepo(ctx, ctx.Repo.GitRepo, ctx.Repo.Repository.DefaultBranch, filename); err == nil {
content = issue_template.RenderToMarkdown(template, ctx.Req.Form) content = issue_template.RenderToMarkdown(template, ctx.Req.Form)
} }
} }
+1 -1
View File
@@ -334,7 +334,7 @@ func ViewIssue(ctx *context.Context) {
return return
} }
ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsIssueList"] = true
ctx.Data["NewIssueChooseTemplate"] = issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo) ctx.Data["NewIssueChooseTemplate"] = issue_service.HasTemplatesOrContactLinks(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
} }
ctx.Data["IsProjectsEnabled"] = ctx.Repo.Permission.CanRead(unit.TypeProjects) ctx.Data["IsProjectsEnabled"] = ctx.Repo.Permission.CanRead(unit.TypeProjects)
+1 -1
View File
@@ -22,7 +22,7 @@ func SetEditorconfigIfExists(ctx *context.Context) {
return return
} }
ec, _, err := ctx.Repo.GetEditorconfig() ec, _, err := ctx.Repo.GetEditorconfig(ctx)
if err != nil { if err != nil {
// it used to check `!git.IsErrNotExist(err)` and create a system notice, but it is quite annoying and useless // it used to check `!git.IsErrNotExist(err)` and create a system notice, but it is quite annoying and useless
// because network errors also happen frequently, so we just ignore it // because network errors also happen frequently, so we just ignore it
+1 -1
View File
@@ -262,7 +262,7 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {
prepareIssueFilterAndList(ctx, milestoneID, projectIDs, optional.None[bool]()) prepareIssueFilterAndList(ctx, milestoneID, projectIDs, optional.None[bool]())
ret := issue.ParseTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ret := issue.ParseTemplatesFromDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
ctx.Data["NewIssueChooseTemplate"] = len(ret.IssueTemplates) > 0 ctx.Data["NewIssueChooseTemplate"] = len(ret.IssueTemplates) > 0
ctx.Data["CanWriteIssues"] = ctx.Repo.Permission.CanWriteIssuesOrPulls(false) ctx.Data["CanWriteIssues"] = ctx.Repo.Permission.CanWriteIssuesOrPulls(false)
+2 -2
View File
@@ -744,7 +744,7 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) {
var beforeCommit *git.Commit var beforeCommit *git.Commit
if isSingleCommit { if isSingleCommit {
beforeCommit, err = afterCommit.Parent(0) beforeCommit, err = afterCommit.Parent(ctx.Repo.GitRepo, 0)
if err != nil { if err != nil {
ctx.ServerError("afterCommit.Parent", err) ctx.ServerError("afterCommit.Parent", err)
return return
@@ -1377,7 +1377,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
content := form.Content content := form.Content
if filename := ctx.Req.Form.Get("template-file"); filename != "" { if filename := ctx.Req.Form.Get("template-file"); filename != "" {
if template, err := issue_template.UnmarshalFromRepo(ctx.Repo.GitRepo, ctx.Repo.Repository.DefaultBranch, filename); err == nil { if template, err := issue_template.UnmarshalFromRepo(ctx, ctx.Repo.GitRepo, ctx.Repo.Repository.DefaultBranch, filename); err == nil {
content = issue_template.RenderToMarkdown(template, ctx.Req.Form) content = issue_template.RenderToMarkdown(template, ctx.Req.Form)
} }
} }
+1 -1
View File
@@ -19,7 +19,7 @@ func RenderFile(ctx *context.Context) {
var blob *git.Blob var blob *git.Blob
var err error var err error
if ctx.Repo.TreePath != "" { if ctx.Repo.TreePath != "" {
blob, err = ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath) blob, err = ctx.Repo.Commit.GetBlobByPath(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
} else { } else {
blob, err = ctx.Repo.GitRepo.GetBlob(ctx.PathParam("sha")) blob, err = ctx.Repo.GitRepo.GetBlob(ctx.PathParam("sha"))
} }
+3 -3
View File
@@ -22,13 +22,13 @@ import (
// TreeList get all files' entries of a repository // TreeList get all files' entries of a repository
func TreeList(ctx *context.Context) { func TreeList(ctx *context.Context) {
tree, err := ctx.Repo.Commit.SubTree("/") tree, err := ctx.Repo.Commit.SubTree(ctx, ctx.Repo.GitRepo, "/")
if err != nil { if err != nil {
ctx.ServerError("Repo.Commit.SubTree", err) ctx.ServerError("Repo.Commit.SubTree", err)
return return
} }
entries, err := tree.ListEntriesRecursiveFast() entries, err := tree.ListEntriesRecursiveFast(ctx, ctx.Repo.GitRepo)
if err != nil { if err != nil {
ctx.ServerError("ListEntriesRecursiveFast", err) ctx.ServerError("ListEntriesRecursiveFast", err)
return return
@@ -144,7 +144,7 @@ func transformDiffTreeForWeb(renderedIconPool *fileicon.RenderedIconPool, diffTr
func TreeViewNodes(ctx *context.Context) { func TreeViewNodes(ctx *context.Context) {
renderedIconPool := fileicon.NewRenderedIconPool() renderedIconPool := fileicon.NewRenderedIconPool()
results, err := files_service.GetTreeViewNodes(ctx, ctx.Repo.RepoLink, renderedIconPool, ctx.Repo.Commit, ctx.Repo.TreePath, ctx.FormString("sub_path")) results, err := files_service.GetTreeViewNodes(ctx, ctx.Repo.RepoLink, renderedIconPool, ctx.Repo.GitRepo, ctx.Repo.Commit, ctx.Repo.TreePath, ctx.FormString("sub_path"))
if err != nil { if err != nil {
ctx.ServerError("GetTreeViewNodes", err) ctx.ServerError("GetTreeViewNodes", err)
return return
+8 -5
View File
@@ -260,7 +260,7 @@ func prepareDirectoryFileIcons(ctx *context.Context, files []git.CommitInfo) {
fileIcons := map[string]template.HTML{} fileIcons := map[string]template.HTML{}
for _, f := range files { for _, f := range files {
fullPath := path.Join(ctx.Repo.TreePath, f.Entry.Name()) fullPath := path.Join(ctx.Repo.TreePath, f.Entry.Name())
entryInfo := fileicon.EntryInfoFromGitTreeEntry(ctx.Repo.Commit, fullPath, f.Entry) entryInfo := fileicon.EntryInfoFromGitTreeEntry(ctx, ctx.Repo.GitRepo, ctx.Repo.Commit, fullPath, f.Entry)
fileIcons[f.Entry.Name()] = fileicon.RenderEntryIconHTML(renderedIconPool, entryInfo) fileIcons[f.Entry.Name()] = fileicon.RenderEntryIconHTML(renderedIconPool, entryInfo)
} }
fileIcons[".."] = fileicon.RenderEntryIconHTML(renderedIconPool, fileicon.EntryInfoFolder()) fileIcons[".."] = fileicon.RenderEntryIconHTML(renderedIconPool, fileicon.EntryInfoFolder())
@@ -269,7 +269,7 @@ func prepareDirectoryFileIcons(ctx *context.Context, files []git.CommitInfo) {
} }
func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entries { func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entries {
tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) tree, err := ctx.Repo.Commit.SubTree(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
HandleGitError(ctx, "Repo.Commit.SubTree", err) HandleGitError(ctx, "Repo.Commit.SubTree", err)
return nil return nil
@@ -280,7 +280,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
ctx.Data["LastCommitLoaderURL"] = lastCommitLoaderURL + "?refSubUrl=" + url.QueryEscape(ctx.Repo.RefTypeNameSubURL()) ctx.Data["LastCommitLoaderURL"] = lastCommitLoaderURL + "?refSubUrl=" + url.QueryEscape(ctx.Repo.RefTypeNameSubURL())
// Get current entry user currently looking at. // Get current entry user currently looking at.
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err)
return nil return nil
@@ -291,7 +291,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
return nil return nil
} }
allEntries, err := tree.ListEntries() allEntries, err := tree.ListEntries(ctx, ctx.Repo.GitRepo)
if err != nil { if err != nil {
ctx.ServerError("ListEntries", err) ctx.ServerError("ListEntries", err)
return nil return nil
@@ -305,7 +305,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
defer cancel() defer cancel()
} }
files, latestCommit, err := allEntries.GetCommitsInfo(commitInfoCtx, ctx.Repo.RepoLink, ctx.Repo.Commit, ctx.Repo.TreePath) files, latestCommit, err := allEntries.GetCommitsInfo(commitInfoCtx, ctx.Repo.RepoLink, ctx.Repo.GitRepo, ctx.Repo.Commit, ctx.Repo.TreePath)
if err != nil { if err != nil {
ctx.ServerError("GetCommitsInfo", err) ctx.ServerError("GetCommitsInfo", err)
return nil return nil
@@ -328,6 +328,9 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
} }
ctx.Data["Files"] = files ctx.Data["Files"] = files
ctx.Data["GetSubJumpablePathName"] = func(entry *git.TreeEntry) string {
return entry.GetSubJumpablePathName(ctx, ctx.Repo.GitRepo)
}
prepareDirectoryFileIcons(ctx, files) prepareDirectoryFileIcons(ctx, files)
for _, f := range files { for _, f := range files {
if f.Commit == nil { if f.Commit == nil {
+5 -5
View File
@@ -29,7 +29,7 @@ import (
) )
func prepareLatestCommitInfo(ctx *context.Context) bool { func prepareLatestCommitInfo(ctx *context.Context) bool {
commit, err := ctx.Repo.Commit.GetCommitByPath(ctx.Repo.TreePath) commit, err := ctx.Repo.Commit.GetCommitByPath(ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
ctx.ServerError("GetCommitByPath", err) ctx.ServerError("GetCommitByPath", err)
return false return false
@@ -161,7 +161,7 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) {
return return
} }
blob := entry.Blob() blob := entry.Blob(ctx.Repo.GitRepo)
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+ctx.Repo.TreePath, ctx.Repo.RefFullName.ShortName()) ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+ctx.Repo.TreePath, ctx.Repo.RefFullName.ShortName())
ctx.Data["FileIsSymlink"] = entry.IsLink() ctx.Data["FileIsSymlink"] = entry.IsLink()
@@ -169,7 +169,7 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) {
ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/raw/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/raw/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
if ctx.Repo.TreePath == ".editorconfig" { if ctx.Repo.TreePath == ".editorconfig" {
_, editorconfigWarning, editorconfigErr := ctx.Repo.GetEditorconfig(ctx.Repo.Commit) _, editorconfigWarning, editorconfigErr := ctx.Repo.GetEditorconfig(ctx, ctx.Repo.Commit)
if editorconfigWarning != nil { if editorconfigWarning != nil {
ctx.Data["FileWarning"] = strings.TrimSpace(editorconfigWarning.Error()) ctx.Data["FileWarning"] = strings.TrimSpace(editorconfigWarning.Error())
} }
@@ -177,12 +177,12 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) {
ctx.Data["FileError"] = strings.TrimSpace(editorconfigErr.Error()) ctx.Data["FileError"] = strings.TrimSpace(editorconfigErr.Error())
} }
} else if issue_service.IsTemplateConfig(ctx.Repo.TreePath) { } else if issue_service.IsTemplateConfig(ctx.Repo.TreePath) {
_, issueConfigErr := issue_service.GetTemplateConfig(ctx.Repo.GitRepo, ctx.Repo.TreePath, ctx.Repo.Commit) _, issueConfigErr := issue_service.GetTemplateConfig(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath, ctx.Repo.Commit)
if issueConfigErr != nil { if issueConfigErr != nil {
ctx.Data["FileError"] = strings.TrimSpace(issueConfigErr.Error()) ctx.Data["FileError"] = strings.TrimSpace(issueConfigErr.Error())
} }
} else if actions.IsWorkflow(ctx.Repo.TreePath) { } else if actions.IsWorkflow(ctx.Repo.TreePath) {
content, err := actions.GetContentFromEntry(entry) content, err := actions.GetContentFromEntry(ctx.Repo.GitRepo, entry)
if err != nil { if err != nil {
log.Error("actions.GetContentFromEntry: %v", err) log.Error("actions.GetContentFromEntry: %v", err)
} }
+6 -6
View File
@@ -100,12 +100,12 @@ func prepareHomeSidebarCitationFile(entry *git.TreeEntry) func(ctx *context.Cont
if entry.Name() != "" { if entry.Name() != "" {
return return
} }
tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) tree, err := ctx.Repo.Commit.SubTree(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
HandleGitError(ctx, "Repo.Commit.SubTree", err) HandleGitError(ctx, "Repo.Commit.SubTree", err)
return return
} }
allEntries, err := tree.ListEntries() allEntries, err := tree.ListEntries(ctx, ctx.Repo.GitRepo)
if err != nil { if err != nil {
ctx.ServerError("ListEntries", err) ctx.ServerError("ListEntries", err)
return return
@@ -113,7 +113,7 @@ func prepareHomeSidebarCitationFile(entry *git.TreeEntry) func(ctx *context.Cont
for _, entry := range allEntries { for _, entry := range allEntries {
if entry.Name() == "CITATION.cff" || entry.Name() == "CITATION.bib" { if entry.Name() == "CITATION.cff" || entry.Name() == "CITATION.bib" {
// Read Citation file contents // Read Citation file contents
if content, err := entry.Blob().GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil { if content, err := entry.Blob(ctx.Repo.GitRepo).GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil {
log.Error("checkCitationFile: GetBlobContent: %v", err) log.Error("checkCitationFile: GetBlobContent: %v", err)
} else { } else {
ctx.Data["CitiationExist"] = true ctx.Data["CitiationExist"] = true
@@ -290,7 +290,7 @@ func handleRepoViewSubmodule(ctx *context.Context, commitSubmoduleFile *git.Comm
func prepareToRenderDirOrFile(entry *git.TreeEntry) func(ctx *context.Context) { func prepareToRenderDirOrFile(entry *git.TreeEntry) func(ctx *context.Context) {
return func(ctx *context.Context) { return func(ctx *context.Context) {
if entry.IsSubModule() { if entry.IsSubModule() {
commitSubmoduleFile, err := git.GetCommitInfoSubmoduleFile(ctx.Repo.RepoLink, ctx.Repo.TreePath, ctx.Repo.Commit, entry.ID) commitSubmoduleFile, err := git.GetCommitInfoSubmoduleFile(ctx, ctx.Repo.RepoLink, ctx.Repo.TreePath, ctx.Repo.GitRepo, ctx.Repo.Commit, entry.ID)
if err != nil { if err != nil {
HandleGitError(ctx, "prepareToRenderDirOrFile: GetCommitInfoSubmoduleFile", err) HandleGitError(ctx, "prepareToRenderDirOrFile: GetCommitInfoSubmoduleFile", err)
return return
@@ -351,7 +351,7 @@ func redirectFollowSymlink(ctx *context.Context, treePathEntry *git.TreeEntry) b
return false return false
} }
if treePathEntry.IsLink() { if treePathEntry.IsLink() {
if res, err := git.EntryFollowLinks(ctx.Repo.Commit, ctx.Repo.TreePath, treePathEntry); err == nil { if res, err := git.EntryFollowLinks(ctx, ctx.Repo.GitRepo, ctx.Repo.Commit, ctx.Repo.TreePath, treePathEntry); err == nil {
redirect := ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(res.TargetFullPath) + "?" + ctx.Req.URL.RawQuery redirect := ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(res.TargetFullPath) + "?" + ctx.Req.URL.RawQuery
ctx.Redirect(redirect) ctx.Redirect(redirect)
return true return true
@@ -425,7 +425,7 @@ func Home(ctx *context.Context) {
prepareHomeTreeSideBarSwitch(ctx) prepareHomeTreeSideBarSwitch(ctx)
// get the current git entry which doer user is currently looking at. // get the current git entry which doer user is currently looking at.
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx, ctx.Repo.GitRepo, ctx.Repo.TreePath)
if err != nil { if err != nil {
HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err)
return return
+6 -6
View File
@@ -66,9 +66,9 @@ func findReadmeFileInEntries(ctx *context.Context, parentDir string, entries []*
for _, entry := range entries { for _, entry := range entries {
if i, ok := util.IsReadmeFileExtension(entry.Name(), exts...); ok { if i, ok := util.IsReadmeFileExtension(entry.Name(), exts...); ok {
fullPath := path.Join(parentDir, entry.Name()) fullPath := path.Join(parentDir, entry.Name())
if readmeFiles[i] == nil || base.NaturalSortCompare(readmeFiles[i].Name(), entry.Blob().Name()) < 0 { if readmeFiles[i] == nil || base.NaturalSortCompare(readmeFiles[i].Name(), entry.Blob(ctx.Repo.GitRepo).Name()) < 0 {
if entry.IsLink() { if entry.IsLink() {
res, err := git.EntryFollowLinks(ctx.Repo.Commit, fullPath, entry) res, err := git.EntryFollowLinks(ctx, ctx.Repo.GitRepo, ctx.Repo.Commit, fullPath, entry)
if err == nil && (res.TargetEntry.IsExecutable() || res.TargetEntry.IsRegular()) { if err == nil && (res.TargetEntry.IsExecutable() || res.TargetEntry.IsRegular()) {
readmeFiles[i] = entry readmeFiles[i] = entry
} }
@@ -92,12 +92,12 @@ func findReadmeFileInEntries(ctx *context.Context, parentDir string, entries []*
if subTreeEntry == nil { if subTreeEntry == nil {
continue continue
} }
subTree := subTreeEntry.Tree() subTree := subTreeEntry.Tree(ctx.Repo.GitRepo)
if subTree == nil { if subTree == nil {
// this should be impossible; if subTreeEntry exists so should this. // this should be impossible; if subTreeEntry exists so should this.
continue continue
} }
childEntries, err := subTree.ListEntries() childEntries, err := subTree.ListEntries(ctx, ctx.Repo.GitRepo)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
@@ -145,7 +145,7 @@ func prepareToRenderReadmeFile(ctx *context.Context, subfolder string, readmeFil
readmeFullPath := path.Join(ctx.Repo.TreePath, subfolder, readmeFile.Name()) readmeFullPath := path.Join(ctx.Repo.TreePath, subfolder, readmeFile.Name())
readmeTargetEntry := readmeFile readmeTargetEntry := readmeFile
if readmeFile.IsLink() { if readmeFile.IsLink() {
if res, err := git.EntryFollowLinks(ctx.Repo.Commit, readmeFullPath, readmeFile); err == nil { if res, err := git.EntryFollowLinks(ctx, ctx.Repo.GitRepo, ctx.Repo.Commit, readmeFullPath, readmeFile); err == nil {
readmeTargetEntry = res.TargetEntry readmeTargetEntry = res.TargetEntry
} else { } else {
readmeTargetEntry = nil // if we cannot resolve the symlink, we cannot render the readme, ignore the error readmeTargetEntry = nil // if we cannot resolve the symlink, we cannot render the readme, ignore the error
@@ -160,7 +160,7 @@ func prepareToRenderReadmeFile(ctx *context.Context, subfolder string, readmeFil
ctx.Data["ReadmeExist"] = true ctx.Data["ReadmeExist"] = true
ctx.Data["FileIsSymlink"] = readmeFile.IsLink() ctx.Data["FileIsSymlink"] = readmeFile.IsLink()
buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, readmeTargetEntry.Blob()) buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, readmeTargetEntry.Blob(ctx.Repo.GitRepo))
if err != nil { if err != nil {
ctx.ServerError("getFileReader", err) ctx.ServerError("getFileReader", err)
return return
+3 -2
View File
@@ -48,11 +48,12 @@ data 12
commit, err := gitRepo.GetBranchCommit("master") commit, err := gitRepo.GetBranchCommit("master")
require.NoError(t, err) require.NoError(t, err)
entries, err := commit.ListEntries() entries, err := commit.Tree().ListEntries(t.Context(), gitRepo)
require.NoError(t, err) require.NoError(t, err)
ctx, _ := contexttest.MockContext(t, "/") ctx, _ := contexttest.MockContext(t, "/")
ctx.Repo.Commit = commit ctx.Repo.Commit = commit
ctx.Repo.GitRepo = gitRepo
foundDir, foundReadme, err := findReadmeFileInEntries(ctx, "", entries, true) foundDir, foundReadme, err := findReadmeFileInEntries(ctx, "", entries, true)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, foundReadme) require.NotNil(t, foundReadme)
@@ -62,7 +63,7 @@ data 12
assert.True(t, foundReadme.IsLink()) assert.True(t, foundReadme.IsLink())
// Verify that it can follow the link // Verify that it can follow the link
res, err := git.EntryFollowLinks(commit, path.Join(foundDir, foundReadme.Name()), foundReadme) res, err := git.EntryFollowLinks(t.Context(), gitRepo, commit, path.Join(foundDir, foundReadme.Name()), foundReadme)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "target.md", res.TargetFullPath) assert.Equal(t, "target.md", res.TargetFullPath)
}) })
+29 -28
View File
@@ -6,6 +6,7 @@ package repo
import ( import (
"bytes" "bytes"
gocontext "context"
"html/template" "html/template"
"io" "io"
"net/http" "net/http"
@@ -78,8 +79,8 @@ type PageMeta struct {
} }
// findEntryForFile finds the tree entry for a target filepath. // findEntryForFile finds the tree entry for a target filepath.
func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) { func findEntryForFile(ctx gocontext.Context, wikiRepo *git.Repository, commit *git.Commit, target string) (*git.TreeEntry, error) {
entry, err := commit.GetTreeEntryByPath(target) entry, err := commit.GetTreeEntryByPath(ctx, wikiRepo, target)
if err != nil && !git.IsErrNotExist(err) { if err != nil && !git.IsErrNotExist(err) {
return nil, err return nil, err
} }
@@ -92,7 +93,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
if unescapedTarget, err = url.QueryUnescape(target); err != nil { if unescapedTarget, err = url.QueryUnescape(target); err != nil {
return nil, err return nil, err
} }
return commit.GetTreeEntryByPath(unescapedTarget) return commit.GetTreeEntryByPath(ctx, wikiRepo, unescapedTarget)
} }
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) { func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
@@ -126,8 +127,8 @@ func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, err
// wikiContentsByEntry returns the contents of the wiki page referenced by the // wikiContentsByEntry returns the contents of the wiki page referenced by the
// given tree entry. Writes to ctx if an error occurs. // given tree entry. Writes to ctx if an error occurs.
func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte { func wikiContentsByEntry(ctx *context.Context, wikiRepo *git.Repository, entry *git.TreeEntry) []byte {
reader, err := entry.Blob().DataAsync() reader, err := entry.Blob(wikiRepo).DataAsync()
if err != nil { if err != nil {
ctx.ServerError("Blob.Data", err) ctx.ServerError("Blob.Data", err)
return nil return nil
@@ -144,10 +145,10 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
// wikiEntryByName returns the entry of a wiki page, along with a boolean // wikiEntryByName returns the entry of a wiki page, along with a boolean
// indicating whether the entry exists. Writes to ctx if an error occurs. // indicating whether the entry exists. Writes to ctx if an error occurs.
// The last return value indicates whether the file should be returned as a raw file // The last return value indicates whether the file should be returned as a raw file
func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) (*git.TreeEntry, string, bool, bool) { func wikiEntryByName(ctx *context.Context, wikiRepo *git.Repository, commit *git.Commit, wikiName wiki_service.WebPath) (*git.TreeEntry, string, bool, bool) {
isRaw := false isRaw := false
gitFilename := wiki_service.WebPathToGitPath(wikiName) gitFilename := wiki_service.WebPathToGitPath(wikiName)
entry, err := findEntryForFile(commit, gitFilename) entry, err := findEntryForFile(ctx, wikiRepo, commit, gitFilename)
if err != nil && !git.IsErrNotExist(err) { if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err) ctx.ServerError("findEntryForFile", err)
return nil, "", false, false return nil, "", false, false
@@ -155,7 +156,7 @@ func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_ser
if entry == nil { if entry == nil {
// check if the file without ".md" suffix exists // check if the file without ".md" suffix exists
gitFilename := strings.TrimSuffix(gitFilename, ".md") gitFilename := strings.TrimSuffix(gitFilename, ".md")
entry, err = findEntryForFile(commit, gitFilename) entry, err = findEntryForFile(ctx, wikiRepo, commit, gitFilename)
if err != nil && !git.IsErrNotExist(err) { if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err) ctx.ServerError("findEntryForFile", err)
return nil, "", false, false return nil, "", false, false
@@ -170,12 +171,12 @@ func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_ser
// wikiContentsByName returns the contents of a wiki page, along with a boolean // wikiContentsByName returns the contents of a wiki page, along with a boolean
// indicating whether the page exists. Writes to ctx if an error occurs. // indicating whether the page exists. Writes to ctx if an error occurs.
func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) { func wikiContentsByName(ctx *context.Context, wikiRepo *git.Repository, commit *git.Commit, wikiName wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) {
entry, gitFilename, noEntry, _ := wikiEntryByName(ctx, commit, wikiName) entry, gitFilename, noEntry, _ := wikiEntryByName(ctx, wikiRepo, commit, wikiName)
if entry == nil { if entry == nil {
return nil, nil, "", true return nil, nil, "", true
} }
return wikiContentsByEntry(ctx, entry), entry, gitFilename, noEntry return wikiContentsByEntry(ctx, wikiRepo, entry), entry, gitFilename, noEntry
} }
func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
@@ -188,7 +189,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
} }
// get the wiki pages list. // get the wiki pages list.
entries, err := commit.ListEntries() entries, err := commit.Tree().ListEntries(ctx, wikiGitRepo)
if err != nil { if err != nil {
ctx.ServerError("ListEntries", err) ctx.ServerError("ListEntries", err)
return nil, nil return nil, nil
@@ -233,7 +234,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
isFooter := pageName == "_Footer" isFooter := pageName == "_Footer"
// lookup filename in wiki - get gitTree entry , real filename // lookup filename in wiki - get gitTree entry , real filename
entry, pageFilename, noEntry, isRaw := wikiEntryByName(ctx, commit, pageName) entry, pageFilename, noEntry, isRaw := wikiEntryByName(ctx, wikiGitRepo, commit, pageName)
if noEntry { if noEntry {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages") ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
} }
@@ -245,7 +246,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
} }
// get page content // get page content
data := wikiContentsByEntry(ctx, entry) data := wikiContentsByEntry(ctx, wikiGitRepo, entry)
if ctx.Written() { if ctx.Written() {
return nil, nil return nil, nil
} }
@@ -283,7 +284,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
} }
if !isSideBar { if !isSideBar {
sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar") sidebarContent, _, _, _ := wikiContentsByName(ctx, wikiGitRepo, commit, "_Sidebar")
if ctx.Written() { if ctx.Written() {
return nil, nil return nil, nil
} }
@@ -295,7 +296,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
} }
if !isFooter { if !isFooter {
footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer") footerContent, _, _, _ := wikiContentsByName(ctx, wikiGitRepo, commit, "_Footer")
if ctx.Written() { if ctx.Written() {
return nil, nil return nil, nil
} }
@@ -335,7 +336,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
ctx.Data["title"] = displayName ctx.Data["title"] = displayName
// lookup filename in wiki - get page content, gitTree entry , real filename // lookup filename in wiki - get page content, gitTree entry , real filename
_, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName) _, entry, pageFilename, noEntry := wikiContentsByName(ctx, wikiGitRepo, commit, pageName)
if noEntry { if noEntry {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages") ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
} }
@@ -375,7 +376,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
} }
func renderEditPage(ctx *context.Context) { func renderEditPage(ctx *context.Context) {
_, commit, err := findWikiRepoCommit(ctx) wikiGitRepo, commit, err := findWikiRepoCommit(ctx)
if err != nil { if err != nil {
if !git.IsErrNotExist(err) { if !git.IsErrNotExist(err) {
ctx.ServerError("GetBranchCommit", err) ctx.ServerError("GetBranchCommit", err)
@@ -396,7 +397,7 @@ func renderEditPage(ctx *context.Context) {
ctx.Data["title"] = displayName ctx.Data["title"] = displayName
// lookup filename in wiki - gitTree entry , real filename // lookup filename in wiki - gitTree entry , real filename
entry, _, noEntry, isRaw := wikiEntryByName(ctx, commit, pageName) entry, _, noEntry, isRaw := wikiEntryByName(ctx, wikiGitRepo, commit, pageName)
if noEntry { if noEntry {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages") ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
} }
@@ -408,7 +409,7 @@ func renderEditPage(ctx *context.Context) {
} }
// get wiki page content // get wiki page content
data := wikiContentsByEntry(ctx, entry) data := wikiContentsByEntry(ctx, wikiGitRepo, entry)
if ctx.Written() { if ctx.Written() {
return return
} }
@@ -543,27 +544,27 @@ func WikiPages(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.pages") ctx.Data["Title"] = ctx.Tr("repo.wiki.pages")
ctx.Data["CanWriteWiki"] = ctx.Repo.Permission.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived ctx.Data["CanWriteWiki"] = ctx.Repo.Permission.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
_, commit, err := findWikiRepoCommit(ctx) wikiGitRepo, commit, err := findWikiRepoCommit(ctx)
if err != nil { if err != nil {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki") ctx.Redirect(ctx.Repo.RepoLink + "/wiki")
return return
} }
treePath := "" // To support list sub folders' pages in the future treePath := "" // To support list sub folders' pages in the future
tree, err := commit.SubTree(treePath) tree, err := commit.SubTree(ctx, wikiGitRepo, treePath)
if err != nil { if err != nil {
ctx.ServerError("SubTree", err) ctx.ServerError("SubTree", err)
return return
} }
allEntries, err := tree.ListEntries() allEntries, err := tree.ListEntries(ctx, wikiGitRepo)
if err != nil { if err != nil {
ctx.ServerError("ListEntries", err) ctx.ServerError("ListEntries", err)
return return
} }
allEntries.CustomSort(base.NaturalSortCompare) allEntries.CustomSort(base.NaturalSortCompare)
entries, _, err := allEntries.GetCommitsInfo(ctx, ctx.Repo.RepoLink, commit, treePath) entries, _, err := allEntries.GetCommitsInfo(ctx, ctx.Repo.RepoLink, wikiGitRepo, commit, treePath)
if err != nil { if err != nil {
ctx.ServerError("GetCommitsInfo", err) ctx.ServerError("GetCommitsInfo", err)
return return
@@ -597,7 +598,7 @@ func WikiPages(ctx *context.Context) {
// WikiRaw outputs raw blob requested by user (image for example) // WikiRaw outputs raw blob requested by user (image for example)
func WikiRaw(ctx *context.Context) { func WikiRaw(ctx *context.Context) {
_, commit, err := findWikiRepoCommit(ctx) wikiGitRepo, commit, err := findWikiRepoCommit(ctx)
if err != nil { if err != nil {
if git.IsErrNotExist(err) { if git.IsErrNotExist(err) {
ctx.NotFound(nil) ctx.NotFound(nil)
@@ -612,7 +613,7 @@ func WikiRaw(ctx *context.Context) {
var entry *git.TreeEntry var entry *git.TreeEntry
if commit != nil { if commit != nil {
// Try to find a file with that name // Try to find a file with that name
entry, err = findEntryForFile(commit, providedGitPath) entry, err = findEntryForFile(ctx, wikiGitRepo, commit, providedGitPath)
if err != nil && !git.IsErrNotExist(err) { if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err) ctx.ServerError("findFile", err)
return return
@@ -621,7 +622,7 @@ func WikiRaw(ctx *context.Context) {
if entry == nil { if entry == nil {
// Try to find a wiki page with that name // Try to find a wiki page with that name
providedGitPath = strings.TrimSuffix(providedGitPath, ".md") providedGitPath = strings.TrimSuffix(providedGitPath, ".md")
entry, err = findEntryForFile(commit, providedGitPath) entry, err = findEntryForFile(ctx, wikiGitRepo, commit, providedGitPath)
if err != nil && !git.IsErrNotExist(err) { if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err) ctx.ServerError("findFile", err)
return return
@@ -630,7 +631,7 @@ func WikiRaw(ctx *context.Context) {
} }
if entry != nil { if entry != nil {
if err = common.ServeBlob(ctx.Base, ctx.Repo.Repository, ctx.Repo.TreePath, entry.Blob(), nil); err != nil { if err = common.ServeBlob(ctx.Base, ctx.Repo.Repository, ctx.Repo.TreePath, entry.Blob(wikiGitRepo), nil); err != nil {
ctx.ServerError("ServeBlob", err) ctx.ServerError("ServeBlob", err)
} }
return return
+13 -9
View File
@@ -28,28 +28,30 @@ const (
message = "Wiki commit message for unit tests" message = "Wiki commit message for unit tests"
) )
func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) *git.TreeEntry { func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) (*git.Repository, *git.TreeEntry) {
wikiRepo, err := gitrepo.OpenRepository(t.Context(), repo.WikiStorageRepo()) wikiRepo, err := gitrepo.OpenRepository(t.Context(), repo.WikiStorageRepo())
assert.NoError(t, err) assert.NoError(t, err)
defer wikiRepo.Close() t.Cleanup(func() {
defer wikiRepo.Close()
})
commit, err := wikiRepo.GetBranchCommit("master") commit, err := wikiRepo.GetBranchCommit("master")
assert.NoError(t, err) assert.NoError(t, err)
entries, err := commit.ListEntries() entries, err := commit.Tree().ListEntries(t.Context(), wikiRepo)
assert.NoError(t, err) assert.NoError(t, err)
for _, entry := range entries { for _, entry := range entries {
if entry.Name() == wiki_service.WebPathToGitPath(wikiName) { if entry.Name() == wiki_service.WebPathToGitPath(wikiName) {
return entry return wikiRepo, entry
} }
} }
return nil return wikiRepo, nil
} }
func wikiContent(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) string { func wikiContent(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) string {
entry := wikiEntry(t, repo, wikiName) wikiRepo, entry := wikiEntry(t, repo, wikiName)
if !assert.NotNil(t, entry) { if !assert.NotNil(t, entry) {
return "" return ""
} }
reader, err := entry.Blob().DataAsync() reader, err := entry.Blob(wikiRepo).DataAsync()
assert.NoError(t, err) assert.NoError(t, err)
defer reader.Close() defer reader.Close()
bytes, err := io.ReadAll(reader) bytes, err := io.ReadAll(reader)
@@ -58,11 +60,13 @@ func wikiContent(t *testing.T, repo *repo_model.Repository, wikiName wiki_servic
} }
func assertWikiExists(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) { func assertWikiExists(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) {
assert.NotNil(t, wikiEntry(t, repo, wikiName)) _, entry := wikiEntry(t, repo, wikiName)
assert.NotNil(t, entry)
} }
func assertWikiNotExists(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) { func assertWikiNotExists(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) {
assert.Nil(t, wikiEntry(t, repo, wikiName)) _, entry := wikiEntry(t, repo, wikiName)
assert.Nil(t, entry)
} }
func assertPagesMetas(t *testing.T, expectedNames []string, metas any) { func assertPagesMetas(t *testing.T, expectedNames []string, metas any) {
+1 -1
View File
@@ -122,7 +122,7 @@ func FindOwnerProfileReadme(ctx *context.Context, doer *user_model.User, optProf
return nil, nil return nil, nil
} }
profileReadmeBlob, _ = commit.GetBlobByPath("README.md") // no need to handle this error profileReadmeBlob, _ = commit.GetBlobByPath(ctx, profileGitRepo, "README.md") // no need to handle this error
return profileDbRepo, profileReadmeBlob return profileDbRepo, profileReadmeBlob
} }
+4 -3
View File
@@ -185,7 +185,7 @@ func notify(ctx context.Context, input *notifyInput) error {
var detectedWorkflows []*actions_module.DetectedWorkflow var detectedWorkflows []*actions_module.DetectedWorkflow
var filteredWorkflows []*actions_module.DetectedWorkflow var filteredWorkflows []*actions_module.DetectedWorkflow
actionsConfig := input.Repo.MustGetUnit(ctx, unit_model.TypeActions).ActionsConfig() actionsConfig := input.Repo.MustGetUnit(ctx, unit_model.TypeActions).ActionsConfig()
workflows, schedules, filtered, err := actions_module.DetectWorkflows(gitRepo, commit, workflows, schedules, filtered, err := actions_module.DetectWorkflows(ctx, gitRepo, commit,
input.Event, input.Event,
input.Payload, input.Payload,
shouldDetectSchedules, shouldDetectSchedules,
@@ -231,7 +231,7 @@ func notify(ctx context.Context, input *notifyInput) error {
if err != nil { if err != nil {
return fmt.Errorf("gitRepo.GetCommit: %w", err) return fmt.Errorf("gitRepo.GetCommit: %w", err)
} }
baseWorkflows, _, baseFiltered, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload, false) baseWorkflows, _, baseFiltered, err := actions_module.DetectWorkflows(ctx, gitRepo, baseCommit, input.Event, input.Payload, false)
if err != nil { if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err) return fmt.Errorf("DetectWorkflows: %w", err)
} }
@@ -602,7 +602,7 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository)
if err != nil { if err != nil {
return fmt.Errorf("gitRepo.GetCommit: %w", err) return fmt.Errorf("gitRepo.GetCommit: %w", err)
} }
scheduleWorkflows, err := actions_module.DetectScheduledWorkflows(gitRepo, commit) scheduleWorkflows, err := actions_module.DetectScheduledWorkflows(ctx, gitRepo, commit)
if err != nil { if err != nil {
return fmt.Errorf("detect schedule workflows: %w", err) return fmt.Errorf("detect schedule workflows: %w", err)
} }
@@ -743,6 +743,7 @@ func detectScopedWorkflowsForSource(
sourceRepo *repo_model.Repository, sourceRepo *repo_model.Repository,
) (sourceCommitSHA string, detected, filtered []*actions_module.DetectedWorkflow, err error) { ) (sourceCommitSHA string, detected, filtered []*actions_module.DetectedWorkflow, err error) {
// scoped workflow content is always taken from the source repo's default branch; the parse is cached per (source, default-branch SHA) and reused across consuming repos/events // scoped workflow content is always taken from the source repo's default branch; the parse is cached per (source, default-branch SHA) and reused across consuming repos/events
sourceCommitSHA, parsed, err := LoadParsedScopedWorkflows(ctx, sourceRepo) sourceCommitSHA, parsed, err := LoadParsedScopedWorkflows(ctx, sourceRepo)
if err != nil { if err != nil {
return "", nil, nil, err return "", nil, nil, err
+1 -1
View File
@@ -89,7 +89,7 @@ func readWorkflowFromRepo(ctx context.Context, repo *repo_model.Repository, refO
if err != nil { if err != nil {
return nil, "", fmt.Errorf("get commit %q in %s: %w", refOrSHA, repo.FullName(), err) return nil, "", fmt.Errorf("get commit %q in %s: %w", refOrSHA, repo.FullName(), err)
} }
str, err := commit.GetFileContent(path, 1024*1024) str, err := commit.GetFileContent(ctx, gitRepo, path, 1024*1024)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("read %s@%s:%s: %w", repo.FullName(), refOrSHA, path, err) return nil, "", fmt.Errorf("read %s@%s:%s: %w", repo.FullName(), refOrSHA, path, err)
} }
+1 -1
View File
@@ -60,7 +60,7 @@ func LoadParsedScopedWorkflows(ctx context.Context, sourceRepo *repo_model.Repos
if err != nil { if err != nil {
return "", nil, fmt.Errorf("get source commit %s: %w", sha, err) return "", nil, fmt.Errorf("get source commit %s: %w", sha, err)
} }
parsed, err = actions_module.ParseScopedWorkflows(sourceCommit) parsed, err = actions_module.ParseScopedWorkflows(ctx, sourceGitRepo, sourceCommit)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
+4 -4
View File
@@ -119,7 +119,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
} }
// resolve the workflow content and record its source on the run (scoped runs read from the source repo) // resolve the workflow content and record its source on the run (scoped runs read from the source repo)
content, err := resolveDispatchWorkflowContent(ctx, repo, runTargetCommit, workflowID, scopedWorkflowSourceRepoID, isScoped, run) content, err := resolveDispatchWorkflowContent(ctx, repo, gitRepo, runTargetCommit, workflowID, scopedWorkflowSourceRepoID, isScoped, run)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@@ -172,18 +172,18 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
// resolveDispatchWorkflowContent returns the YAML for a dispatched workflow and records its source on the run. // resolveDispatchWorkflowContent returns the YAML for a dispatched workflow and records its source on the run.
// - Repo-level: from the consumer's runTargetCommit. // - Repo-level: from the consumer's runTargetCommit.
// - Scoped: from the source repo's default branch. // - Scoped: from the source repo's default branch.
func resolveDispatchWorkflowContent(ctx reqctx.RequestContext, repo *repo_model.Repository, runTargetCommit *git.Commit, workflowID string, sourceRepoID int64, isScoped bool, run *actions_model.ActionRun) ([]byte, error) { func resolveDispatchWorkflowContent(ctx reqctx.RequestContext, repo *repo_model.Repository, gitRepo *git.Repository, runTargetCommit *git.Commit, workflowID string, sourceRepoID int64, isScoped bool, run *actions_model.ActionRun) ([]byte, error) {
if isScoped { if isScoped {
return resolveScopedDispatchContent(ctx, repo, sourceRepoID, workflowID, run) return resolveScopedDispatchContent(ctx, repo, sourceRepoID, workflowID, run)
} }
_, entries, err := actions.ListWorkflows(runTargetCommit) _, entries, err := actions.ListWorkflows(ctx, gitRepo, runTargetCommit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, e := range entries { for _, e := range entries {
if e.Name() == workflowID { if e.Name() == workflowID {
return actions.GetContentFromEntry(e) return actions.GetContentFromEntry(gitRepo, e)
} }
} }
return nil, util.ErrorWrapTranslatable( return nil, util.ErrorWrapTranslatable(
+2 -2
View File
@@ -37,7 +37,7 @@ func TestParseCommitWithSSHSignature(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
t.Run("UserSSHKey", func(t *testing.T) { t.Run("UserSSHKey", func(t *testing.T) {
commit, err := git.CommitFromReader(nil, git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree a3b1fad553e0f9a2b4a58327bebde36c7da75aa2 commit, err := git.CommitFromReader(git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree a3b1fad553e0f9a2b4a58327bebde36c7da75aa2
author user2 <user2@example.com> 1752194028 -0700 author user2 <user2@example.com> 1752194028 -0700
committer user2 <user2@example.com> 1752194028 -0700 committer user2 <user2@example.com> 1752194028 -0700
gpgsig -----BEGIN SSH SIGNATURE----- gpgsig -----BEGIN SSH SIGNATURE-----
@@ -68,7 +68,7 @@ init project
defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "gitea@fake.local")() defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "gitea@fake.local")()
defer test.MockVariableValue(&setting.Repository.Signing.TrustedSSHKeys, []string{"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH6Y4idVaW3E+bLw1uqoAfJD7o5Siu+HqS51E9oQLPE9"})() defer test.MockVariableValue(&setting.Repository.Signing.TrustedSSHKeys, []string{"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH6Y4idVaW3E+bLw1uqoAfJD7o5Siu+HqS51E9oQLPE9"})()
commit, err := git.CommitFromReader(nil, git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree 9a93ffa76e8b72bdb6431910b3a506fa2b39f42e commit, err := git.CommitFromReader(git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree 9a93ffa76e8b72bdb6431910b3a506fa2b39f42e
author User Two <user2@example.com> 1749230009 +0200 author User Two <user2@example.com> 1749230009 +0200
committer User Two <user2@example.com> 1749230009 +0200 committer User Two <user2@example.com> 1749230009 +0200
gpgsig -----BEGIN SSH SIGNATURE----- gpgsig -----BEGIN SSH SIGNATURE-----
+1 -1
View File
@@ -365,7 +365,7 @@ func AllHeadCommitsVerified(ctx context.Context, pr *issues_model.PullRequest, g
if err != nil { if err != nil {
return false, err return false, err
} }
commitList, err := headCommit.CommitsBeforeUntil(git.RefNameFromCommit(mergeBaseCommit)) commitList, err := headCommit.CommitsBeforeUntil(gitRepo, git.RefNameFromCommit(mergeBaseCommit))
if err != nil { if err != nil {
return false, err return false, err
} }
+4 -4
View File
@@ -291,7 +291,7 @@ func (r *Repository) RefTypeNameSubURL() string {
// GetEditorconfig returns the .editorconfig definition if found in the // GetEditorconfig returns the .editorconfig definition if found in the
// HEAD of the default repo branch. // HEAD of the default repo branch.
func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (cfg *editorconfig.Editorconfig, warning, err error) { func (r *Repository) GetEditorconfig(ctx context.Context, optCommit ...*git.Commit) (cfg *editorconfig.Editorconfig, warning, err error) {
if r.GitRepo == nil { if r.GitRepo == nil {
return nil, nil, nil return nil, nil, nil
} }
@@ -306,14 +306,14 @@ func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (cfg *editorconfi
return nil, nil, err return nil, nil, err
} }
} }
treeEntry, err := commit.GetTreeEntryByPath(".editorconfig") treeEntry, err := commit.GetTreeEntryByPath(ctx, r.GitRepo, ".editorconfig")
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if treeEntry.Blob().Size() >= setting.UI.MaxDisplayFileSize { if treeEntry.Blob(r.GitRepo).Size() >= setting.UI.MaxDisplayFileSize {
return nil, nil, git.ErrNotExist{ID: "", RelPath: ".editorconfig"} return nil, nil, git.ErrNotExist{ID: "", RelPath: ".editorconfig"}
} }
reader, err := treeEntry.Blob().DataAsync() reader, err := treeEntry.Blob(r.GitRepo).DataAsync()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
+13 -13
View File
@@ -523,7 +523,7 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
}, nil }, nil
} }
func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, refName git.RefName, folder string, entry *git.TreeEntry) *api.ActionWorkflow { func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, refName git.RefName, folder string, entry *git.TreeEntry) *api.ActionWorkflow {
cfgUnit := repo.MustGetUnit(ctx, unit.TypeActions) cfgUnit := repo.MustGetUnit(ctx, unit.TypeActions)
cfg := cfgUnit.ActionsConfig() cfg := cfgUnit.ActionsConfig()
@@ -554,7 +554,7 @@ func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, co
createdAt := commit.Author.When createdAt := commit.Author.When
updatedAt := commit.Author.When updatedAt := commit.Author.When
content, err := actions.GetContentFromEntry(entry) content, err := actions.GetContentFromEntry(gitRepo, entry)
name := entry.Name() name := entry.Name()
if err == nil { if err == nil {
workflow, err := model.ReadWorkflow(bytes.NewReader(content)) workflow, err := model.ReadWorkflow(bytes.NewReader(content))
@@ -589,26 +589,26 @@ func ListActionWorkflows(ctx context.Context, gitrepo *git.Repository, repo *rep
return nil, err return nil, err
} }
folder, entries, err := actions.ListWorkflows(defaultBranchCommit) folder, entries, err := actions.ListWorkflows(ctx, gitrepo, defaultBranchCommit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
workflows := make([]*api.ActionWorkflow, len(entries)) workflows := make([]*api.ActionWorkflow, len(entries))
for i, entry := range entries { for i, entry := range entries {
workflows[i] = getActionWorkflowEntry(ctx, repo, defaultBranchCommit, git.RefNameFromBranch(repo.DefaultBranch), folder, entry) workflows[i] = getActionWorkflowEntry(ctx, repo, gitrepo, defaultBranchCommit, git.RefNameFromBranch(repo.DefaultBranch), folder, entry)
} }
return workflows, nil return workflows, nil
} }
func GetActionWorkflow(ctx context.Context, gitrepo *git.Repository, repo *repo_model.Repository, workflowID string) (*api.ActionWorkflow, error) { func GetActionWorkflow(ctx context.Context, gitRepo *git.Repository, repo *repo_model.Repository, workflowID string) (*api.ActionWorkflow, error) {
defaultBranchCommit, err := gitrepo.GetBranchCommit(repo.DefaultBranch) defaultBranchCommit, err := gitRepo.GetBranchCommit(repo.DefaultBranch)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return getActionWorkflowFromCommit(ctx, repo, defaultBranchCommit, git.RefNameFromBranch(repo.DefaultBranch), workflowID) return getActionWorkflowFromCommit(ctx, repo, gitRepo, defaultBranchCommit, git.RefNameFromBranch(repo.DefaultBranch), workflowID)
} }
func GetActionWorkflowByRef(ctx context.Context, gitrepo *git.Repository, repo *repo_model.Repository, workflowID string, ref git.RefName) (*api.ActionWorkflow, error) { func GetActionWorkflowByRef(ctx context.Context, gitrepo *git.Repository, repo *repo_model.Repository, workflowID string, ref git.RefName) (*api.ActionWorkflow, error) {
@@ -625,18 +625,18 @@ func GetActionWorkflowByRef(ctx context.Context, gitrepo *git.Repository, repo *
return nil, err return nil, err
} }
return getActionWorkflowFromCommit(ctx, repo, refCommit, ref, workflowID) return getActionWorkflowFromCommit(ctx, repo, gitrepo, refCommit, ref, workflowID)
} }
func getActionWorkflowFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, refName git.RefName, workflowID string) (*api.ActionWorkflow, error) { func getActionWorkflowFromCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, refName git.RefName, workflowID string) (*api.ActionWorkflow, error) {
folder, entries, err := actions.ListWorkflows(commit) folder, entries, err := actions.ListWorkflows(ctx, gitRepo, commit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, entry := range entries { for _, entry := range entries {
if entry.Name() == workflowID { if entry.Name() == workflowID {
return getActionWorkflowEntry(ctx, repo, commit, refName, folder, entry), nil return getActionWorkflowEntry(ctx, repo, gitRepo, commit, refName, folder, entry), nil
} }
} }
@@ -650,7 +650,7 @@ func GetScopedActionWorkflow(ctx context.Context, sourceGitRepo *git.Repository,
return nil, err return nil, err
} }
folder, entries, err := actions.ListScopedWorkflows(commit) folder, entries, err := actions.ListScopedWorkflows(ctx, sourceGitRepo, commit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -658,7 +658,7 @@ func GetScopedActionWorkflow(ctx context.Context, sourceGitRepo *git.Repository,
for _, entry := range entries { for _, entry := range entries {
if entry.Name() == workflowID { if entry.Name() == workflowID {
// An empty ref pins HTMLURL to commit (the run's WorkflowCommitSHA) rather than the moving default branch. // An empty ref pins HTMLURL to commit (the run's WorkflowCommitSHA) rather than the moving default branch.
wf := getActionWorkflowEntry(ctx, sourceRepo, commit, git.RefName(""), folder, entry) wf := getActionWorkflowEntry(ctx, sourceRepo, sourceGitRepo, commit, "", folder, entry)
// TODO: a scoped workflow has no repo-level representation on the source: the workflow API scans WORKFLOW_DIRS (not SCOPED_WORKFLOW_DIRS), // TODO: a scoped workflow has no repo-level representation on the source: the workflow API scans WORKFLOW_DIRS (not SCOPED_WORKFLOW_DIRS),
// and the badge only reflects the source's repo-level runs, so neither link resolves a scoped workflow. // and the badge only reflects the source's repo-level runs, so neither link resolves a scoped workflow.
// Blank them for now and populate once a scoped-aware workflow/badge endpoint exists. // Blank them for now and populate once a scoped-aware workflow/badge endpoint exists.
+1 -1
View File
@@ -100,7 +100,7 @@ func validateGitDiffTreeArguments(gitRepo *git.Repository, useMergeBase bool, ba
return false, objectFormat.EmptyTree().String(), headCommitID, nil return false, objectFormat.EmptyTree().String(), headCommitID, nil
} }
baseCommit, err := headCommit.Parent(0) baseCommit, err := headCommit.Parent(gitRepo, 0)
if err != nil { if err != nil {
return false, "", "", fmt.Errorf("baseSha is '', attempted to use parent of commit %s, got error: %v", headCommit.ID.String(), err) return false, "", "", fmt.Errorf("baseSha is '', attempted to use parent of commit %s, got error: %v", headCommit.ID.String(), err)
} }
+11 -11
View File
@@ -477,17 +477,17 @@ type DiffLimitedContent struct {
} }
// GetTailSectionAndLimitedContent creates a fake DiffLineSection if the last section is not the end of the file // GetTailSectionAndLimitedContent creates a fake DiffLineSection if the last section is not the end of the file
func (diffFile *DiffFile) GetTailSectionAndLimitedContent(leftCommit, rightCommit *git.Commit) (_ *DiffSection, diffLimitedContent DiffLimitedContent) { func (diffFile *DiffFile) GetTailSectionAndLimitedContent(ctx context.Context, gitRepo *git.Repository, leftCommit, rightCommit *git.Commit) (_ *DiffSection, diffLimitedContent DiffLimitedContent) {
var leftLineCount, rightLineCount int var leftLineCount, rightLineCount int
diffLimitedContent = DiffLimitedContent{} diffLimitedContent = DiffLimitedContent{}
if diffFile.IsBin || diffFile.IsLFSFile { if diffFile.IsBin || diffFile.IsLFSFile {
return nil, diffLimitedContent return nil, diffLimitedContent
} }
if (diffFile.Type == DiffFileDel || diffFile.Type == DiffFileChange) && leftCommit != nil { if (diffFile.Type == DiffFileDel || diffFile.Type == DiffFileChange) && leftCommit != nil {
leftLineCount, diffLimitedContent.LeftContent = getCommitFileLineCountAndLimitedContent(leftCommit, diffFile.OldName) leftLineCount, diffLimitedContent.LeftContent = getCommitFileLineCountAndLimitedContent(ctx, gitRepo, leftCommit, diffFile.OldName)
} }
if (diffFile.Type == DiffFileAdd || diffFile.Type == DiffFileChange) && rightCommit != nil { if (diffFile.Type == DiffFileAdd || diffFile.Type == DiffFileChange) && rightCommit != nil {
rightLineCount, diffLimitedContent.RightContent = getCommitFileLineCountAndLimitedContent(rightCommit, diffFile.OldName) rightLineCount, diffLimitedContent.RightContent = getCommitFileLineCountAndLimitedContent(ctx, gitRepo, rightCommit, diffFile.OldName)
} }
if len(diffFile.Sections) == 0 || diffFile.Type != DiffFileChange { if len(diffFile.Sections) == 0 || diffFile.Type != DiffFileChange {
return nil, diffLimitedContent return nil, diffLimitedContent
@@ -577,8 +577,8 @@ func (l *limitByteWriter) Write(p []byte) (n int, err error) {
return l.buf.Write(p) return l.buf.Write(p)
} }
func getCommitFileLineCountAndLimitedContent(commit *git.Commit, filePath string) (lineCount int, limitWriter *limitByteWriter) { func getCommitFileLineCountAndLimitedContent(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, filePath string) (lineCount int, limitWriter *limitByteWriter) {
blob, err := commit.GetBlobByPath(filePath) blob, err := commit.GetBlobByPath(ctx, gitRepo, filePath)
if err != nil { if err != nil {
return 0, nil return 0, nil
} }
@@ -1256,7 +1256,7 @@ func guessBeforeCommitForDiff(gitRepo *git.Repository, beforeCommitID string, af
actualBeforeCommitID = commitObjectFormat.EmptyTree() actualBeforeCommitID = commitObjectFormat.EmptyTree()
} else { } else {
if isBeforeCommitIDEmpty { if isBeforeCommitIDEmpty {
actualBeforeCommit, err = afterCommit.Parent(0) actualBeforeCommit, err = afterCommit.Parent(gitRepo, 0)
} else { } else {
actualBeforeCommit, err = gitRepo.GetCommit(beforeCommitID) actualBeforeCommit, err = gitRepo.GetCommit(beforeCommitID)
} }
@@ -1360,7 +1360,7 @@ func GetDiffForRender(ctx context.Context, repoLink string, gitRepo *git.Reposit
// Populate Submodule URLs // Populate Submodule URLs
if diffFile.SubmoduleDiffInfo != nil { if diffFile.SubmoduleDiffInfo != nil {
diffFile.SubmoduleDiffInfo.PopulateURL(repoLink, diffFile, beforeCommit, afterCommit) diffFile.SubmoduleDiffInfo.PopulateURL(ctx, repoLink, gitRepo, diffFile, beforeCommit, afterCommit)
} }
if !isVendored.Has() { if !isVendored.Has() {
@@ -1372,7 +1372,7 @@ func GetDiffForRender(ctx context.Context, repoLink string, gitRepo *git.Reposit
isGenerated = optional.Some(analyze.IsGenerated(diffFile.Name)) isGenerated = optional.Some(analyze.IsGenerated(diffFile.Name))
} }
diffFile.IsGenerated = isGenerated.Value() diffFile.IsGenerated = isGenerated.Value()
tailSection, limitedContent := diffFile.GetTailSectionAndLimitedContent(beforeCommit, afterCommit) tailSection, limitedContent := diffFile.GetTailSectionAndLimitedContent(ctx, gitRepo, beforeCommit, afterCommit)
if tailSection != nil { if tailSection != nil {
diffFile.Sections = append(diffFile.Sections, tailSection) diffFile.Sections = append(diffFile.Sections, tailSection)
} }
@@ -1542,18 +1542,18 @@ func CommentAsDiff(ctx context.Context, c *issues_model.Comment) (*Diff, error)
} }
// GeneratePatchForUnchangedLine creates a patch showing code context for an unchanged line // GeneratePatchForUnchangedLine creates a patch showing code context for an unchanged line
func GeneratePatchForUnchangedLine(gitRepo *git.Repository, commitID, treePath string, line int64, contextLines int) (string, error) { func GeneratePatchForUnchangedLine(ctx context.Context, gitRepo *git.Repository, commitID, treePath string, line int64, contextLines int) (string, error) {
commit, err := gitRepo.GetCommit(commitID) commit, err := gitRepo.GetCommit(commitID)
if err != nil { if err != nil {
return "", fmt.Errorf("GetCommit: %w", err) return "", fmt.Errorf("GetCommit: %w", err)
} }
entry, err := commit.GetTreeEntryByPath(treePath) entry, err := commit.GetTreeEntryByPath(ctx, gitRepo, treePath)
if err != nil { if err != nil {
return "", fmt.Errorf("GetTreeEntryByPath: %w", err) return "", fmt.Errorf("GetTreeEntryByPath: %w", err)
} }
blob := entry.Blob() blob := entry.Blob(gitRepo)
dataRc, err := blob.DataAsync() dataRc, err := blob.DataAsync()
if err != nil { if err != nil {
return "", fmt.Errorf("DataAsync: %w", err) return "", fmt.Errorf("DataAsync: %w", err)
+2 -2
View File
@@ -20,7 +20,7 @@ type SubmoduleDiffInfo struct {
PreviousRefID string PreviousRefID string
} }
func (si *SubmoduleDiffInfo) PopulateURL(repoLink string, diffFile *DiffFile, leftCommit, rightCommit *git.Commit) { func (si *SubmoduleDiffInfo) PopulateURL(ctx context.Context, repoLink string, gitRepo *git.Repository, diffFile *DiffFile, leftCommit, rightCommit *git.Commit) {
si.SubmoduleName = diffFile.Name si.SubmoduleName = diffFile.Name
submoduleCommit := rightCommit // If the submodule is added or updated, check at the right commit submoduleCommit := rightCommit // If the submodule is added or updated, check at the right commit
if diffFile.IsDeleted { if diffFile.IsDeleted {
@@ -31,7 +31,7 @@ func (si *SubmoduleDiffInfo) PopulateURL(repoLink string, diffFile *DiffFile, le
} }
submoduleFullPath := diffFile.GetDiffFileName() submoduleFullPath := diffFile.GetDiffFileName()
submodule, err := submoduleCommit.GetSubModule(submoduleFullPath) submodule, err := submoduleCommit.GetSubModule(ctx, gitRepo, submoduleFullPath)
if err != nil { if err != nil {
log.Error("Unable to PopulateURL for submodule %q: GetSubModule: %v", submoduleFullPath, err) log.Error("Unable to PopulateURL for submodule %q: GetSubModule: %v", submoduleFullPath, err)
return // ignore the error, do not cause 500 errors for end users return // ignore the error, do not cause 500 errors for end users
+1 -1
View File
@@ -68,7 +68,7 @@ func PullRequestCodeOwnersReview(ctx context.Context, pr *issues_model.PullReque
var data string var data string
for _, file := range codeOwnerFiles { for _, file := range codeOwnerFiles {
if blob, err := commit.GetBlobByPath(file); err == nil { if blob, err := commit.GetBlobByPath(ctx, repo, file); err == nil {
data, err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize) data, err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
if err == nil { if err == nil {
break break
+16 -15
View File
@@ -4,6 +4,7 @@
package issue package issue
import ( import (
"context"
"fmt" "fmt"
"net/url" "net/url"
"path" "path"
@@ -47,17 +48,17 @@ func GetDefaultTemplateConfig() api.IssueConfig {
// GetTemplateConfig loads the given issue config file. // GetTemplateConfig loads the given issue config file.
// It never returns a nil config. // It never returns a nil config.
func GetTemplateConfig(gitRepo *git.Repository, path string, commit *git.Commit) (api.IssueConfig, error) { func GetTemplateConfig(ctx context.Context, gitRepo *git.Repository, path string, commit *git.Commit) (api.IssueConfig, error) {
if gitRepo == nil { if gitRepo == nil {
return GetDefaultTemplateConfig(), nil return GetDefaultTemplateConfig(), nil
} }
treeEntry, err := commit.GetTreeEntryByPath(path) treeEntry, err := commit.GetTreeEntryByPath(ctx, gitRepo, path)
if err != nil { if err != nil {
return GetDefaultTemplateConfig(), err return GetDefaultTemplateConfig(), err
} }
reader, err := treeEntry.Blob().DataAsync() reader, err := treeEntry.Blob(gitRepo).DataAsync()
if err != nil { if err != nil {
log.Debug("DataAsync: %v", err) log.Debug("DataAsync: %v", err)
return GetDefaultTemplateConfig(), nil return GetDefaultTemplateConfig(), nil
@@ -109,7 +110,7 @@ func IsTemplateConfig(path string) bool {
// ParseTemplatesFromDefaultBranch parses the issue templates in the repo's default branch, // ParseTemplatesFromDefaultBranch parses the issue templates in the repo's default branch,
// returns valid templates and the errors of invalid template files (the errors map is guaranteed to be non-nil). // returns valid templates and the errors of invalid template files (the errors map is guaranteed to be non-nil).
func ParseTemplatesFromDefaultBranch(repo *repo.Repository, gitRepo *git.Repository) (ret struct { func ParseTemplatesFromDefaultBranch(ctx context.Context, repo *repo.Repository, gitRepo *git.Repository) (ret struct {
IssueTemplates []*api.IssueTemplate IssueTemplates []*api.IssueTemplate
TemplateErrors map[string]error TemplateErrors map[string]error
}, },
@@ -125,12 +126,12 @@ func ParseTemplatesFromDefaultBranch(repo *repo.Repository, gitRepo *git.Reposit
} }
for _, dirName := range templateDirCandidates { for _, dirName := range templateDirCandidates {
tree, err := commit.SubTree(dirName) tree, err := commit.SubTree(ctx, gitRepo, dirName)
if err != nil { if err != nil {
log.Debug("get sub tree of %s: %v", dirName, err) log.Debug("get sub tree of %s: %v", dirName, err)
continue continue
} }
entries, err := tree.ListEntries() entries, err := tree.ListEntries(ctx, gitRepo)
if err != nil { if err != nil {
log.Debug("list entries in %s: %v", dirName, err) log.Debug("list entries in %s: %v", dirName, err)
return ret return ret
@@ -140,7 +141,7 @@ func ParseTemplatesFromDefaultBranch(repo *repo.Repository, gitRepo *git.Reposit
continue continue
} }
fullName := path.Join(dirName, entry.Name()) fullName := path.Join(dirName, entry.Name())
if it, err := template.UnmarshalFromEntry(entry, dirName); err != nil { if it, err := template.UnmarshalFromEntry(gitRepo, entry, dirName); err != nil {
ret.TemplateErrors[fullName] = err ret.TemplateErrors[fullName] = err
} else { } else {
if !strings.HasPrefix(it.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/<ref> if !strings.HasPrefix(it.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/<ref>
@@ -155,7 +156,7 @@ func ParseTemplatesFromDefaultBranch(repo *repo.Repository, gitRepo *git.Reposit
// GetTemplateConfigFromDefaultBranch returns the issue config for this repo. // GetTemplateConfigFromDefaultBranch returns the issue config for this repo.
// It never returns a nil config. // It never returns a nil config.
func GetTemplateConfigFromDefaultBranch(repo *repo.Repository, gitRepo *git.Repository) (api.IssueConfig, error) { func GetTemplateConfigFromDefaultBranch(ctx context.Context, repo *repo.Repository, gitRepo *git.Repository) (api.IssueConfig, error) {
if repo.IsEmpty { if repo.IsEmpty {
return GetDefaultTemplateConfig(), nil return GetDefaultTemplateConfig(), nil
} }
@@ -166,24 +167,24 @@ func GetTemplateConfigFromDefaultBranch(repo *repo.Repository, gitRepo *git.Repo
} }
for _, configName := range templateConfigCandidates { for _, configName := range templateConfigCandidates {
if _, err := commit.GetTreeEntryByPath(configName + ".yaml"); err == nil { if _, err := commit.GetTreeEntryByPath(ctx, gitRepo, configName+".yaml"); err == nil {
return GetTemplateConfig(gitRepo, configName+".yaml", commit) return GetTemplateConfig(ctx, gitRepo, configName+".yaml", commit)
} }
if _, err := commit.GetTreeEntryByPath(configName + ".yml"); err == nil { if _, err := commit.GetTreeEntryByPath(ctx, gitRepo, configName+".yml"); err == nil {
return GetTemplateConfig(gitRepo, configName+".yml", commit) return GetTemplateConfig(ctx, gitRepo, configName+".yml", commit)
} }
} }
return GetDefaultTemplateConfig(), nil return GetDefaultTemplateConfig(), nil
} }
func HasTemplatesOrContactLinks(repo *repo.Repository, gitRepo *git.Repository) bool { func HasTemplatesOrContactLinks(ctx context.Context, repo *repo.Repository, gitRepo *git.Repository) bool {
ret := ParseTemplatesFromDefaultBranch(repo, gitRepo) ret := ParseTemplatesFromDefaultBranch(ctx, repo, gitRepo)
if len(ret.IssueTemplates) > 0 { if len(ret.IssueTemplates) > 0 {
return true return true
} }
issueConfig, _ := GetTemplateConfigFromDefaultBranch(repo, gitRepo) issueConfig, _ := GetTemplateConfigFromDefaultBranch(ctx, repo, gitRepo)
return len(issueConfig.ContactLinks) > 0 return len(issueConfig.ContactLinks) > 0
} }
+1 -1
View File
@@ -62,7 +62,7 @@ func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePrevie
} }
language, _ := languagestats.GetFileLanguage(ctx, gitRepo, opts.CommitID, opts.FilePath) language, _ := languagestats.GetFileLanguage(ctx, gitRepo, opts.CommitID, opts.FilePath)
blob, err := commit.GetBlobByPath(opts.FilePath) blob, err := commit.GetBlobByPath(ctx, gitRepo, opts.FilePath)
if err != nil { if err != nil {
return "", err return "", err
} }
+1 -1
View File
@@ -72,7 +72,7 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
templateContent, err := commit.GetFileContent(templateFilepath, setting.Repository.PullRequest.DefaultMergeMessageSize) templateContent, err := commit.GetFileContent(ctx, baseGitRepo, templateFilepath, setting.Repository.PullRequest.DefaultMergeMessageSize)
if err != nil { if err != nil {
if !git.IsErrNotExist(err) { if !git.IsErrNotExist(err) {
return "", "", err return "", "", err
+1 -1
View File
@@ -1046,7 +1046,7 @@ func IsHeadEqualWithBranch(ctx context.Context, pr *issues_model.PullRequest, br
return false, err return false, err
} }
} }
return baseCommit.HasPreviousCommit(headCommit.ID) return baseCommit.HasPreviousCommit(ctx, baseGitRepo, headCommit.ID)
} }
type CommitInfo struct { type CommitInfo struct {
+1 -1
View File
@@ -284,7 +284,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo
// If patch is still empty (unchanged line), generate code context // If patch is still empty (unchanged line), generate code context
if patch == "" && commitID != "" { if patch == "" && commitID != "" {
patch, err = gitdiff.GeneratePatchForUnchangedLine(gitRepo, commitID, treePath, line, setting.UI.CodeCommentLines) patch, err = gitdiff.GeneratePatchForUnchangedLine(ctx, gitRepo, commitID, treePath, line, setting.UI.CodeCommentLines)
if err != nil { if err != nil {
// Log the error but don't fail comment creation // Log the error but don't fail comment creation
log.Debug("Unable to generate patch for unchanged line (file=%s, line=%d, commit=%s): %v", treePath, line, commitID, err) log.Debug("Unable to generate patch for unchanged line (file=%s, line=%d, commit=%s): %v", treePath, line, commitID, err)
+2 -2
View File
@@ -526,7 +526,7 @@ func UpdateBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git
return nil return nil
} }
isForcePush, err := newCommit.IsForcePush(branch.CommitID) isForcePush, err := newCommit.IsForcePush(ctx, gitRepo, branch.CommitID)
if err != nil { if err != nil {
return err return err
} }
@@ -811,7 +811,7 @@ func GetBranchDivergingInfo(ctx reqctx.RequestContext, baseRepo *repo_model.Repo
if err != nil { if err != nil {
return nil, err return nil, err
} }
hasPreviousCommit, _ := headCommit.HasPreviousCommit(baseCommitID) hasPreviousCommit, _ := headCommit.HasPreviousCommit(ctx, headGitRepo, baseCommitID)
info.BaseHasNewCommits = !hasPreviousCommit info.BaseHasNewCommits = !hasPreviousCommit
return info, nil return info, nil
} }
+1 -1
View File
@@ -29,5 +29,5 @@ func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
gitRepo.LastCommitCache = git.NewLastCommitCache(commitsCount, repo.FullName(), gitRepo, cache.GetCache()) gitRepo.LastCommitCache = git.NewLastCommitCache(commitsCount, repo.FullName(), gitRepo, cache.GetCache())
} }
return commit.CacheCommit(ctx) return commit.CacheCommit(ctx, gitRepo)
} }
+1 -1
View File
@@ -147,7 +147,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
return nil, err return nil, err
} }
fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil fileCommitResponse, _ := GetFileCommitResponse(repo, gitRepo, commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(ctx, commit) verification := GetPayloadCommitVerification(ctx, commit)
fileResponse := &structs.FileResponse{ fileResponse := &structs.FileResponse{
Commit: fileCommitResponse, Commit: fileCommitResponse,

Some files were not shown because too many files have changed in this diff Show More