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  }