code.gitea.io/gitea@v1.22.3/modules/git/repo_branch_nogogit.go (about) 1 // Copyright 2015 The Gogs Authors. All rights reserved. 2 // Copyright 2018 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 //go:build !gogit 6 7 package git 8 9 import ( 10 "bufio" 11 "bytes" 12 "context" 13 "io" 14 "strings" 15 16 "code.gitea.io/gitea/modules/log" 17 ) 18 19 // IsObjectExist returns true if the given object exists in the repository. 20 func (repo *Repository) IsObjectExist(name string) bool { 21 if name == "" { 22 return false 23 } 24 25 wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx) 26 if err != nil { 27 log.Debug("Error writing to CatFileBatchCheck %v", err) 28 return false 29 } 30 defer cancel() 31 _, err = wr.Write([]byte(name + "\n")) 32 if err != nil { 33 log.Debug("Error writing to CatFileBatchCheck %v", err) 34 return false 35 } 36 sha, _, _, err := ReadBatchLine(rd) 37 return err == nil && bytes.HasPrefix(sha, []byte(strings.TrimSpace(name))) 38 } 39 40 // IsReferenceExist returns true if given reference exists in the repository. 41 func (repo *Repository) IsReferenceExist(name string) bool { 42 if name == "" { 43 return false 44 } 45 46 wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx) 47 if err != nil { 48 log.Debug("Error writing to CatFileBatchCheck %v", err) 49 return false 50 } 51 defer cancel() 52 _, err = wr.Write([]byte(name + "\n")) 53 if err != nil { 54 log.Debug("Error writing to CatFileBatchCheck %v", err) 55 return false 56 } 57 _, _, _, err = ReadBatchLine(rd) 58 return err == nil 59 } 60 61 // IsBranchExist returns true if given branch exists in current repository. 62 func (repo *Repository) IsBranchExist(name string) bool { 63 if repo == nil || name == "" { 64 return false 65 } 66 67 return repo.IsReferenceExist(BranchPrefix + name) 68 } 69 70 // GetBranchNames returns branches from the repository, skipping "skip" initial branches and 71 // returning at most "limit" branches, or all branches if "limit" is 0. 72 func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) { 73 return callShowRef(repo.Ctx, repo.Path, BranchPrefix, TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"}, skip, limit) 74 } 75 76 // WalkReferences walks all the references from the repository 77 // refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty. 78 func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) { 79 var args TrustedCmdArgs 80 switch refType { 81 case ObjectTag: 82 args = TrustedCmdArgs{TagPrefix, "--sort=-taggerdate"} 83 case ObjectBranch: 84 args = TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"} 85 } 86 87 return WalkShowRef(repo.Ctx, repo.Path, args, skip, limit, walkfn) 88 } 89 90 // callShowRef return refs, if limit = 0 it will not limit 91 func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs TrustedCmdArgs, skip, limit int) (branchNames []string, countAll int, err error) { 92 countAll, err = WalkShowRef(ctx, repoPath, extraArgs, skip, limit, func(_, branchName string) error { 93 branchName = strings.TrimPrefix(branchName, trimPrefix) 94 branchNames = append(branchNames, branchName) 95 96 return nil 97 }) 98 return branchNames, countAll, err 99 } 100 101 func WalkShowRef(ctx context.Context, repoPath string, extraArgs TrustedCmdArgs, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) { 102 stdoutReader, stdoutWriter := io.Pipe() 103 defer func() { 104 _ = stdoutReader.Close() 105 _ = stdoutWriter.Close() 106 }() 107 108 go func() { 109 stderrBuilder := &strings.Builder{} 110 args := TrustedCmdArgs{"for-each-ref", "--format=%(objectname) %(refname)"} 111 args = append(args, extraArgs...) 112 err := NewCommand(ctx, args...).Run(&RunOpts{ 113 Dir: repoPath, 114 Stdout: stdoutWriter, 115 Stderr: stderrBuilder, 116 }) 117 if err != nil { 118 if stderrBuilder.Len() == 0 { 119 _ = stdoutWriter.Close() 120 return 121 } 122 _ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String())) 123 } else { 124 _ = stdoutWriter.Close() 125 } 126 }() 127 128 i := 0 129 bufReader := bufio.NewReader(stdoutReader) 130 for i < skip { 131 _, isPrefix, err := bufReader.ReadLine() 132 if err == io.EOF { 133 return i, nil 134 } 135 if err != nil { 136 return 0, err 137 } 138 if !isPrefix { 139 i++ 140 } 141 } 142 for limit == 0 || i < skip+limit { 143 // The output of show-ref is simply a list: 144 // <sha> SP <ref> LF 145 sha, err := bufReader.ReadString(' ') 146 if err == io.EOF { 147 return i, nil 148 } 149 if err != nil { 150 return 0, err 151 } 152 153 branchName, err := bufReader.ReadString('\n') 154 if err == io.EOF { 155 // This shouldn't happen... but we'll tolerate it for the sake of peace 156 return i, nil 157 } 158 if err != nil { 159 return i, err 160 } 161 162 if len(branchName) > 0 { 163 branchName = branchName[:len(branchName)-1] 164 } 165 166 if len(sha) > 0 { 167 sha = sha[:len(sha)-1] 168 } 169 170 err = walkfn(sha, branchName) 171 if err != nil { 172 return i, err 173 } 174 i++ 175 } 176 // count all refs 177 for limit != 0 { 178 _, isPrefix, err := bufReader.ReadLine() 179 if err == io.EOF { 180 return i, nil 181 } 182 if err != nil { 183 return 0, err 184 } 185 if !isPrefix { 186 i++ 187 } 188 } 189 return i, nil 190 } 191 192 // GetRefsBySha returns all references filtered with prefix that belong to a sha commit hash 193 func (repo *Repository) GetRefsBySha(sha, prefix string) ([]string, error) { 194 var revList []string 195 _, err := WalkShowRef(repo.Ctx, repo.Path, nil, 0, 0, func(walkSha, refname string) error { 196 if walkSha == sha && strings.HasPrefix(refname, prefix) { 197 revList = append(revList, refname) 198 } 199 return nil 200 }) 201 return revList, err 202 }