123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- // 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.
-
- //go:build !gogit
-
- package git
-
- import (
- "bufio"
- "bytes"
- "context"
- "io"
- "strings"
-
- "code.gitea.io/gitea/modules/log"
- )
-
- // IsObjectExist returns true if given reference exists in the repository.
- func (repo *Repository) IsObjectExist(name string) bool {
- if name == "" {
- return false
- }
-
- wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
- defer cancel()
- _, err := wr.Write([]byte(name + "\n"))
- if err != nil {
- log.Debug("Error writing to CatFileBatchCheck %v", err)
- return false
- }
- sha, _, _, err := ReadBatchLine(rd)
- return err == nil && bytes.HasPrefix(sha, []byte(strings.TrimSpace(name)))
- }
-
- // IsReferenceExist returns true if given reference exists in the repository.
- func (repo *Repository) IsReferenceExist(name string) bool {
- if name == "" {
- return false
- }
-
- wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
- defer cancel()
- _, err := wr.Write([]byte(name + "\n"))
- if err != nil {
- log.Debug("Error writing to CatFileBatchCheck %v", err)
- return false
- }
- _, _, _, err = ReadBatchLine(rd)
- return err == nil
- }
-
- // IsBranchExist returns true if given branch exists in current repository.
- func (repo *Repository) IsBranchExist(name string) bool {
- if name == "" {
- return false
- }
-
- return repo.IsReferenceExist(BranchPrefix + name)
- }
-
- // GetBranchNames returns branches from the repository, skipping skip initial branches and
- // returning at most limit branches, or all branches if limit is 0.
- func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
- return callShowRef(repo.Ctx, repo.Path, BranchPrefix, "--heads", skip, limit)
- }
-
- // WalkReferences walks all the references from the repository
- func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
- return walkShowRef(ctx, repoPath, "", 0, 0, walkfn)
- }
-
- // 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:
- arg = "--tags"
- case ObjectBranch:
- arg = "--heads"
- default:
- arg = ""
- }
-
- return walkShowRef(repo.Ctx, repo.Path, arg, skip, limit, walkfn)
- }
-
- // callShowRef return refs, if limit = 0 it will not limit
- func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) {
- countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(_, branchName string) error {
- branchName = strings.TrimPrefix(branchName, prefix)
- branchNames = append(branchNames, branchName)
-
- return nil
- })
- return
- }
-
- func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
- stdoutReader, stdoutWriter := io.Pipe()
- defer func() {
- _ = stdoutReader.Close()
- _ = stdoutWriter.Close()
- }()
-
- go func() {
- stderrBuilder := &strings.Builder{}
- args := []string{"show-ref"}
- if arg != "" {
- args = append(args, arg)
- }
- err := NewCommand(ctx, args...).Run(&RunOpts{
- Dir: repoPath,
- Stdout: stdoutWriter,
- Stderr: stderrBuilder,
- })
- if err != nil {
- if stderrBuilder.Len() == 0 {
- _ = stdoutWriter.Close()
- return
- }
- _ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))
- } else {
- _ = stdoutWriter.Close()
- }
- }()
-
- i := 0
- bufReader := bufio.NewReader(stdoutReader)
- for i < skip {
- _, isPrefix, err := bufReader.ReadLine()
- if err == io.EOF {
- return i, nil
- }
- if err != nil {
- return 0, err
- }
- if !isPrefix {
- i++
- }
- }
- for limit == 0 || i < skip+limit {
- // The output of show-ref is simply a list:
- // <sha> SP <ref> LF
- sha, err := bufReader.ReadString(' ')
- if err == io.EOF {
- return i, nil
- }
- if err != nil {
- return 0, err
- }
-
- branchName, err := bufReader.ReadString('\n')
- if err == io.EOF {
- // This shouldn't happen... but we'll tolerate it for the sake of peace
- return i, nil
- }
- if err != nil {
- return i, err
- }
-
- if len(branchName) > 0 {
- branchName = branchName[:len(branchName)-1]
- }
-
- if len(sha) > 0 {
- sha = sha[:len(sha)-1]
- }
-
- err = walkfn(sha, branchName)
- if err != nil {
- return i, err
- }
- i++
- }
- // count all refs
- for limit != 0 {
- _, isPrefix, err := bufReader.ReadLine()
- if err == io.EOF {
- return i, nil
- }
- if err != nil {
- return 0, err
- }
- if !isPrefix {
- i++
- }
- }
- return i, nil
- }
|