code.gitea.io/gitea@v1.19.3/modules/git/repo_ref_nogogit.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  //go:build !gogit
     5  
     6  package git
     7  
     8  import (
     9  	"bufio"
    10  	"io"
    11  	"strings"
    12  )
    13  
    14  // GetRefsFiltered returns all references of the repository that matches patterm exactly or starting with.
    15  func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
    16  	stdoutReader, stdoutWriter := io.Pipe()
    17  	defer func() {
    18  		_ = stdoutReader.Close()
    19  		_ = stdoutWriter.Close()
    20  	}()
    21  
    22  	go func() {
    23  		stderrBuilder := &strings.Builder{}
    24  		err := NewCommand(repo.Ctx, "for-each-ref").Run(&RunOpts{
    25  			Dir:    repo.Path,
    26  			Stdout: stdoutWriter,
    27  			Stderr: stderrBuilder,
    28  		})
    29  		if err != nil {
    30  			_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))
    31  		} else {
    32  			_ = stdoutWriter.Close()
    33  		}
    34  	}()
    35  
    36  	refs := make([]*Reference, 0)
    37  	bufReader := bufio.NewReader(stdoutReader)
    38  	for {
    39  		// The output of for-each-ref is simply a list:
    40  		// <sha> SP <type> TAB <ref> LF
    41  		sha, err := bufReader.ReadString(' ')
    42  		if err == io.EOF {
    43  			break
    44  		}
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		sha = sha[:len(sha)-1]
    49  
    50  		typ, err := bufReader.ReadString('\t')
    51  		if err == io.EOF {
    52  			// This should not happen, but we'll tolerate it
    53  			break
    54  		}
    55  		if err != nil {
    56  			return nil, err
    57  		}
    58  		typ = typ[:len(typ)-1]
    59  
    60  		refName, err := bufReader.ReadString('\n')
    61  		if err == io.EOF {
    62  			// This should not happen, but we'll tolerate it
    63  			break
    64  		}
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  		refName = refName[:len(refName)-1]
    69  
    70  		// refName cannot be HEAD but can be remotes or stash
    71  		if strings.HasPrefix(refName, RemotePrefix) || refName == "/refs/stash" {
    72  			continue
    73  		}
    74  
    75  		if pattern == "" || strings.HasPrefix(refName, pattern) {
    76  			r := &Reference{
    77  				Name:   refName,
    78  				Object: MustIDFromString(sha),
    79  				Type:   typ,
    80  				repo:   repo,
    81  			}
    82  			refs = append(refs, r)
    83  		}
    84  	}
    85  
    86  	return refs, nil
    87  }