2020-12-17 17:00:47 +03:00
// Copyright 2017 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-12-17 17:00:47 +03:00
2021-08-24 19:47:09 +03:00
//go:build !gogit
2020-12-17 17:00:47 +03:00
package git
import (
2021-06-07 02:44:58 +03:00
"context"
2020-12-17 17:00:47 +03:00
"fmt"
"io"
"path"
"sort"
2021-06-25 19:54:08 +03:00
"code.gitea.io/gitea/modules/log"
2020-12-17 17:00:47 +03:00
)
// GetCommitsInfo gets information of all commits that are corresponding to these entries
2022-07-25 18:39:42 +03:00
func ( tes Entries ) GetCommitsInfo ( ctx context . Context , commit * Commit , treePath string ) ( [ ] CommitInfo , * Commit , error ) {
2020-12-17 17:00:47 +03:00
entryPaths := make ( [ ] string , len ( tes ) + 1 )
// Get the commit for the treePath itself
entryPaths [ 0 ] = ""
for i , entry := range tes {
entryPaths [ i + 1 ] = entry . Name ( )
}
var err error
var revs map [ string ] * Commit
2022-07-25 18:39:42 +03:00
if commit . repo . LastCommitCache != nil {
2020-12-17 17:00:47 +03:00
var unHitPaths [ ] string
2022-07-25 18:39:42 +03:00
revs , unHitPaths , err = getLastCommitForPathsByCache ( ctx , commit . ID . String ( ) , treePath , entryPaths , commit . repo . LastCommitCache )
2020-12-17 17:00:47 +03:00
if err != nil {
return nil , nil , err
}
if len ( unHitPaths ) > 0 {
sort . Strings ( unHitPaths )
2022-07-25 18:39:42 +03:00
commits , err := GetLastCommitForPaths ( ctx , commit , treePath , unHitPaths )
2020-12-17 17:00:47 +03:00
if err != nil {
return nil , nil , err
}
2021-06-21 01:00:46 +03:00
for pth , found := range commits {
revs [ pth ] = found
2020-12-17 17:00:47 +03:00
}
}
} else {
sort . Strings ( entryPaths )
2022-07-25 18:39:42 +03:00
revs , err = GetLastCommitForPaths ( ctx , commit , treePath , entryPaths )
2020-12-17 17:00:47 +03:00
}
if err != nil {
return nil , nil , err
}
commitsInfo := make ( [ ] CommitInfo , len ( tes ) )
for i , entry := range tes {
commitsInfo [ i ] = CommitInfo {
Entry : entry ,
}
2021-10-08 16:08:22 +03:00
// Check if we have found a commit for this entry in time
2020-12-17 17:00:47 +03:00
if entryCommit , ok := revs [ entry . Name ( ) ] ; ok {
commitsInfo [ i ] . Commit = entryCommit
2021-06-21 01:00:46 +03:00
} else {
2021-06-25 19:54:08 +03:00
log . Debug ( "missing commit for %s" , entry . Name ( ) )
2020-12-17 17:00:47 +03:00
}
2021-10-08 16:08:22 +03:00
// If the entry if a submodule add a submodule file for this
if entry . IsSubModule ( ) {
subModuleURL := ""
var fullPath string
if len ( treePath ) > 0 {
fullPath = treePath + "/" + entry . Name ( )
} else {
fullPath = entry . Name ( )
}
if subModule , err := commit . GetSubModule ( fullPath ) ; err != nil {
return nil , nil , err
} else if subModule != nil {
subModuleURL = subModule . URL
}
subModuleFile := NewSubModuleFile ( commitsInfo [ i ] . Commit , subModuleURL , entry . ID . String ( ) )
commitsInfo [ i ] . SubModuleFile = subModuleFile
}
2020-12-17 17:00:47 +03:00
}
// Retrieve the commit for the treePath itself (see above). We basically
// 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.
var treeCommit * Commit
var ok bool
if treePath == "" {
treeCommit = commit
} else if treeCommit , ok = revs [ "" ] ; ok {
treeCommit . repo = commit . repo
}
return commitsInfo , treeCommit , nil
}
2021-06-07 02:44:58 +03:00
func getLastCommitForPathsByCache ( ctx context . Context , commitID , treePath string , paths [ ] string , cache * LastCommitCache ) ( map [ string ] * Commit , [ ] string , error ) {
2020-12-17 17:00:47 +03:00
var unHitEntryPaths [ ] string
2022-01-20 20:46:10 +03:00
results := make ( map [ string ] * Commit )
2020-12-17 17:00:47 +03:00
for _ , p := range paths {
2022-07-25 18:39:42 +03:00
lastCommit , err := cache . Get ( commitID , path . Join ( treePath , p ) )
2020-12-17 17:00:47 +03:00
if err != nil {
return nil , nil , err
}
if lastCommit != nil {
2022-07-25 18:39:42 +03:00
results [ p ] = lastCommit
2020-12-17 17:00:47 +03:00
continue
}
unHitEntryPaths = append ( unHitEntryPaths , p )
}
return results , unHitEntryPaths , nil
}
// GetLastCommitForPaths returns last commit information
2022-07-25 18:39:42 +03:00
func GetLastCommitForPaths ( ctx context . Context , commit * Commit , treePath string , paths [ ] string ) ( map [ string ] * Commit , error ) {
2020-12-17 17:00:47 +03:00
// We read backwards from the commit to obtain all of the commits
2022-07-25 18:39:42 +03:00
revs , err := WalkGitLog ( ctx , commit . repo , commit , treePath , paths ... )
2021-06-21 01:00:46 +03:00
if err != nil {
return nil , err
}
2020-12-17 17:00:47 +03:00
2021-11-30 23:06:32 +03:00
batchStdinWriter , batchReader , cancel := commit . repo . CatFileBatch ( ctx )
2021-03-04 05:57:01 +03:00
defer cancel ( )
2020-12-17 17:00:47 +03:00
2021-06-21 01:00:46 +03:00
commitsMap := map [ string ] * Commit { }
2020-12-17 17:00:47 +03:00
commitsMap [ commit . ID . String ( ) ] = commit
2021-06-21 01:00:46 +03:00
commitCommits := map [ string ] * Commit { }
for path , commitID := range revs {
2020-12-17 17:00:47 +03:00
c , ok := commitsMap [ commitID ]
if ok {
2021-06-21 01:00:46 +03:00
commitCommits [ path ] = c
2020-12-17 17:00:47 +03:00
continue
}
if len ( commitID ) == 0 {
continue
}
_ , err := batchStdinWriter . Write ( [ ] byte ( commitID + "\n" ) )
if err != nil {
return nil , err
}
_ , typ , size , err := ReadBatchLine ( batchReader )
if err != nil {
return nil , err
}
if typ != "commit" {
return nil , fmt . Errorf ( "unexpected type: %s for commit id: %s" , typ , commitID )
}
2022-06-20 13:02:49 +03:00
c , err = CommitFromReader ( commit . repo , MustIDFromString ( commitID ) , io . LimitReader ( batchReader , size ) )
2020-12-17 17:00:47 +03:00
if err != nil {
return nil , err
}
2021-05-10 04:27:03 +03:00
if _ , err := batchReader . Discard ( 1 ) ; err != nil {
return nil , err
}
2021-06-21 01:00:46 +03:00
commitCommits [ path ] = c
2020-12-17 17:00:47 +03:00
}
2021-06-21 01:00:46 +03:00
return commitCommits , nil
2020-12-17 17:00:47 +03:00
}