2020-12-17 17:00:47 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2021-08-24 19:47:09 +03:00
//go:build !gogit
2020-12-17 17:00:47 +03:00
package git
import (
"bufio"
2021-06-21 01:39:12 +03:00
"bytes"
2021-11-30 23:06:32 +03:00
"context"
2020-12-17 17:00:47 +03:00
"io"
"strings"
2021-06-25 19:54:08 +03:00
"code.gitea.io/gitea/modules/log"
2020-12-17 17:00:47 +03:00
)
2021-06-21 01:39:12 +03:00
// IsObjectExist returns true if given reference exists in the repository.
func ( repo * Repository ) IsObjectExist ( name string ) bool {
if name == "" {
return false
}
2021-11-30 23:06:32 +03:00
wr , rd , cancel := repo . CatFileBatchCheck ( repo . Ctx )
2021-06-21 01:39:12 +03:00
defer cancel ( )
_ , err := wr . Write ( [ ] byte ( name + "\n" ) )
if err != nil {
2021-06-25 19:54:08 +03:00
log . Debug ( "Error writing to CatFileBatchCheck %v" , err )
2021-06-21 01:39:12 +03:00
return false
}
sha , _ , _ , err := ReadBatchLine ( rd )
return err == nil && bytes . HasPrefix ( sha , [ ] byte ( strings . TrimSpace ( name ) ) )
}
2021-05-10 04:27:03 +03:00
// IsReferenceExist returns true if given reference exists in the repository.
func ( repo * Repository ) IsReferenceExist ( name string ) bool {
if name == "" {
return false
}
2021-11-30 23:06:32 +03:00
wr , rd , cancel := repo . CatFileBatchCheck ( repo . Ctx )
2021-05-10 04:27:03 +03:00
defer cancel ( )
_ , err := wr . Write ( [ ] byte ( name + "\n" ) )
if err != nil {
2021-06-25 19:54:08 +03:00
log . Debug ( "Error writing to CatFileBatchCheck %v" , err )
2021-05-10 04:27:03 +03:00
return false
}
_ , _ , _ , err = ReadBatchLine ( rd )
return err == nil
}
2020-12-17 17:00:47 +03:00
// IsBranchExist returns true if given branch exists in current repository.
func ( repo * Repository ) IsBranchExist ( name string ) bool {
if name == "" {
return false
}
2021-05-10 04:27:03 +03:00
return repo . IsReferenceExist ( BranchPrefix + name )
2020-12-17 17:00:47 +03:00
}
2021-12-08 22:08:16 +03:00
// GetBranchNames returns branches from the repository, skipping skip initial branches and
2021-02-03 22:06:13 +03:00
// returning at most limit branches, or all branches if limit is 0.
2021-12-08 22:08:16 +03:00
func ( repo * Repository ) GetBranchNames ( skip , limit int ) ( [ ] string , int , error ) {
2022-09-14 15:11:24 +03:00
return callShowRef ( repo . Ctx , repo . Path , BranchPrefix , BranchPrefix + " --sort=-committerdate" , skip , limit )
2020-12-17 17:00:47 +03:00
}
2021-12-08 22:08:16 +03:00
// WalkReferences walks all the references from the repository
2022-03-29 20:12:33 +03:00
func WalkReferences ( ctx context . Context , repoPath string , walkfn func ( sha1 , refname string ) error ) ( int , error ) {
2021-12-08 22:08:16 +03:00
return walkShowRef ( ctx , repoPath , "" , 0 , 0 , walkfn )
}
2022-03-29 20:12:33 +03:00
// WalkReferences walks all the references from the repository
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
func ( repo * Repository ) WalkReferences ( refType ObjectType , skip , limit int , walkfn func ( sha1 , refname string ) error ) ( int , error ) {
var arg string
switch refType {
case ObjectTag :
2022-09-14 15:11:24 +03:00
arg = TagPrefix + " --sort=-taggerdate"
2022-03-29 20:12:33 +03:00
case ObjectBranch :
2022-09-14 15:11:24 +03:00
arg = BranchPrefix + " --sort=-committerdate"
2022-03-29 20:12:33 +03:00
default :
arg = ""
}
return walkShowRef ( repo . Ctx , repo . Path , arg , skip , limit , walkfn )
}
2021-02-03 22:06:13 +03:00
// callShowRef return refs, if limit = 0 it will not limit
2021-11-30 23:06:32 +03:00
func callShowRef ( ctx context . Context , repoPath , prefix , arg string , skip , limit int ) ( branchNames [ ] string , countAll int , err error ) {
2022-03-29 20:12:33 +03:00
countAll , err = walkShowRef ( ctx , repoPath , arg , skip , limit , func ( _ , branchName string ) error {
2021-12-08 22:08:16 +03:00
branchName = strings . TrimPrefix ( branchName , prefix )
branchNames = append ( branchNames , branchName )
return nil
} )
2022-06-20 13:02:49 +03:00
return branchNames , countAll , err
2021-12-08 22:08:16 +03:00
}
2022-03-29 20:12:33 +03:00
func walkShowRef ( ctx context . Context , repoPath , arg string , skip , limit int , walkfn func ( sha1 , refname string ) error ) ( countAll int , err error ) {
2020-12-17 17:00:47 +03:00
stdoutReader , stdoutWriter := io . Pipe ( )
defer func ( ) {
_ = stdoutReader . Close ( )
_ = stdoutWriter . Close ( )
} ( )
go func ( ) {
stderrBuilder := & strings . Builder { }
2022-09-14 15:11:24 +03:00
args := [ ] string { "for-each-ref" , "--format=%(objectname) %(refname)" }
2021-12-08 22:08:16 +03:00
if arg != "" {
2022-09-14 15:11:24 +03:00
args = append ( args , strings . Fields ( arg ) ... )
2021-12-08 22:08:16 +03:00
}
2022-04-01 05:55:30 +03:00
err := NewCommand ( ctx , args ... ) . Run ( & RunOpts {
Dir : repoPath ,
Stdout : stdoutWriter ,
Stderr : stderrBuilder ,
2022-02-11 15:47:22 +03:00
} )
2020-12-17 17:00:47 +03:00
if err != nil {
if stderrBuilder . Len ( ) == 0 {
_ = stdoutWriter . Close ( )
return
}
_ = stdoutWriter . CloseWithError ( ConcatenateError ( err , stderrBuilder . String ( ) ) )
} else {
_ = stdoutWriter . Close ( )
}
} ( )
2021-02-03 22:06:13 +03:00
i := 0
2020-12-17 17:00:47 +03:00
bufReader := bufio . NewReader ( stdoutReader )
2021-02-03 22:06:13 +03:00
for i < skip {
_ , isPrefix , err := bufReader . ReadLine ( )
if err == io . EOF {
2021-12-08 22:08:16 +03:00
return i , nil
2021-02-03 22:06:13 +03:00
}
if err != nil {
2021-12-08 22:08:16 +03:00
return 0 , err
2021-02-03 22:06:13 +03:00
}
if ! isPrefix {
i ++
}
}
for limit == 0 || i < skip + limit {
2020-12-17 17:00:47 +03:00
// The output of show-ref is simply a list:
// <sha> SP <ref> LF
2022-03-29 20:12:33 +03:00
sha , err := bufReader . ReadString ( ' ' )
2020-12-17 17:00:47 +03:00
if err == io . EOF {
2021-12-08 22:08:16 +03:00
return i , nil
2020-12-17 17:00:47 +03:00
}
if err != nil {
2021-12-08 22:08:16 +03:00
return 0 , err
2020-12-17 17:00:47 +03:00
}
branchName , err := bufReader . ReadString ( '\n' )
if err == io . EOF {
// This shouldn't happen... but we'll tolerate it for the sake of peace
2021-12-08 22:08:16 +03:00
return i , nil
2020-12-17 17:00:47 +03:00
}
if err != nil {
2021-12-08 22:08:16 +03:00
return i , err
2020-12-17 17:00:47 +03:00
}
2021-12-08 22:08:16 +03:00
2020-12-17 17:00:47 +03:00
if len ( branchName ) > 0 {
branchName = branchName [ : len ( branchName ) - 1 ]
}
2022-03-29 20:12:33 +03:00
if len ( sha ) > 0 {
sha = sha [ : len ( sha ) - 1 ]
}
err = walkfn ( sha , branchName )
2021-12-08 22:08:16 +03:00
if err != nil {
return i , err
}
2021-02-03 22:06:13 +03:00
i ++
}
// count all refs
for limit != 0 {
_ , isPrefix , err := bufReader . ReadLine ( )
if err == io . EOF {
2021-12-08 22:08:16 +03:00
return i , nil
2021-02-03 22:06:13 +03:00
}
if err != nil {
2021-12-08 22:08:16 +03:00
return 0 , err
2021-02-03 22:06:13 +03:00
}
if ! isPrefix {
i ++
}
2020-12-17 17:00:47 +03:00
}
2021-12-08 22:08:16 +03:00
return i , nil
2020-12-17 17:00:47 +03:00
}
2022-05-07 20:05:52 +03:00
// GetRefsBySha returns all references filtered with prefix that belong to a sha commit hash
func ( repo * Repository ) GetRefsBySha ( sha , prefix string ) ( [ ] string , error ) {
var revList [ ] string
_ , err := walkShowRef ( repo . Ctx , repo . Path , "" , 0 , 0 , func ( walkSha , refname string ) error {
if walkSha == sha && strings . HasPrefix ( refname , prefix ) {
revList = append ( revList , refname )
}
return nil
} )
return revList , err
}