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