code.gitea.io/gitea@v1.19.3/modules/git/commit_info_nogogit.go (about) 1 // Copyright 2017 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 //go:build !gogit 5 6 package git 7 8 import ( 9 "context" 10 "fmt" 11 "io" 12 "path" 13 "sort" 14 15 "code.gitea.io/gitea/modules/log" 16 ) 17 18 // GetCommitsInfo gets information of all commits that are corresponding to these entries 19 func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) { 20 entryPaths := make([]string, len(tes)+1) 21 // Get the commit for the treePath itself 22 entryPaths[0] = "" 23 for i, entry := range tes { 24 entryPaths[i+1] = entry.Name() 25 } 26 27 var err error 28 29 var revs map[string]*Commit 30 if commit.repo.LastCommitCache != nil { 31 var unHitPaths []string 32 revs, unHitPaths, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache) 33 if err != nil { 34 return nil, nil, err 35 } 36 if len(unHitPaths) > 0 { 37 sort.Strings(unHitPaths) 38 commits, err := GetLastCommitForPaths(ctx, commit, treePath, unHitPaths) 39 if err != nil { 40 return nil, nil, err 41 } 42 43 for pth, found := range commits { 44 revs[pth] = found 45 } 46 } 47 } else { 48 sort.Strings(entryPaths) 49 revs, err = GetLastCommitForPaths(ctx, commit, treePath, entryPaths) 50 } 51 if err != nil { 52 return nil, nil, err 53 } 54 55 commitsInfo := make([]CommitInfo, len(tes)) 56 for i, entry := range tes { 57 commitsInfo[i] = CommitInfo{ 58 Entry: entry, 59 } 60 61 // Check if we have found a commit for this entry in time 62 if entryCommit, ok := revs[entry.Name()]; ok { 63 commitsInfo[i].Commit = entryCommit 64 } else { 65 log.Debug("missing commit for %s", entry.Name()) 66 } 67 68 // If the entry if a submodule add a submodule file for this 69 if entry.IsSubModule() { 70 subModuleURL := "" 71 var fullPath string 72 if len(treePath) > 0 { 73 fullPath = treePath + "/" + entry.Name() 74 } else { 75 fullPath = entry.Name() 76 } 77 if subModule, err := commit.GetSubModule(fullPath); err != nil { 78 return nil, nil, err 79 } else if subModule != nil { 80 subModuleURL = subModule.URL 81 } 82 subModuleFile := NewSubModuleFile(commitsInfo[i].Commit, subModuleURL, entry.ID.String()) 83 commitsInfo[i].SubModuleFile = subModuleFile 84 } 85 } 86 87 // Retrieve the commit for the treePath itself (see above). We basically 88 // get it for free during the tree traversal and it's used for listing 89 // pages to display information about newest commit for a given path. 90 var treeCommit *Commit 91 var ok bool 92 if treePath == "" { 93 treeCommit = commit 94 } else if treeCommit, ok = revs[""]; ok { 95 treeCommit.repo = commit.repo 96 } 97 return commitsInfo, treeCommit, nil 98 } 99 100 func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) { 101 var unHitEntryPaths []string 102 results := make(map[string]*Commit) 103 for _, p := range paths { 104 lastCommit, err := cache.Get(commitID, path.Join(treePath, p)) 105 if err != nil { 106 return nil, nil, err 107 } 108 if lastCommit != nil { 109 results[p] = lastCommit 110 continue 111 } 112 113 unHitEntryPaths = append(unHitEntryPaths, p) 114 } 115 116 return results, unHitEntryPaths, nil 117 } 118 119 // GetLastCommitForPaths returns last commit information 120 func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) { 121 // We read backwards from the commit to obtain all of the commits 122 revs, err := WalkGitLog(ctx, commit.repo, commit, treePath, paths...) 123 if err != nil { 124 return nil, err 125 } 126 127 batchStdinWriter, batchReader, cancel := commit.repo.CatFileBatch(ctx) 128 defer cancel() 129 130 commitsMap := map[string]*Commit{} 131 commitsMap[commit.ID.String()] = commit 132 133 commitCommits := map[string]*Commit{} 134 for path, commitID := range revs { 135 c, ok := commitsMap[commitID] 136 if ok { 137 commitCommits[path] = c 138 continue 139 } 140 141 if len(commitID) == 0 { 142 continue 143 } 144 145 _, err := batchStdinWriter.Write([]byte(commitID + "\n")) 146 if err != nil { 147 return nil, err 148 } 149 _, typ, size, err := ReadBatchLine(batchReader) 150 if err != nil { 151 return nil, err 152 } 153 if typ != "commit" { 154 return nil, fmt.Errorf("unexpected type: %s for commit id: %s", typ, commitID) 155 } 156 c, err = CommitFromReader(commit.repo, MustIDFromString(commitID), io.LimitReader(batchReader, size)) 157 if err != nil { 158 return nil, err 159 } 160 if _, err := batchReader.Discard(1); err != nil { 161 return nil, err 162 } 163 commitCommits[path] = c 164 } 165 166 return commitCommits, nil 167 }