gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
// Copyright 2020 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
// +build !gogit

package git

import (
	"bufio"
	"io"
	"strings"
)

// GetRefsFiltered returns all references of the repository that matches patterm exactly or starting with.
func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
	stdoutReader, stdoutWriter := io.Pipe()
	defer func() {
		_ = stdoutReader.Close()
		_ = stdoutWriter.Close()
	}()

	go func() {
		stderrBuilder := &strings.Builder{}
		err := NewCommand(repo.Ctx, "for-each-ref").RunWithContext(&RunContext{
			Timeout: -1,
			Dir:     repo.Path,
			Stdout:  stdoutWriter,
			Stderr:  stderrBuilder,
		})
		if err != nil {
			_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))
		} else {
			_ = stdoutWriter.Close()
		}
	}()

	refs := make([]*Reference, 0)
	bufReader := bufio.NewReader(stdoutReader)
	for {
		// The output of for-each-ref is simply a list:
		// <sha> SP <type> TAB <ref> LF
		sha, err := bufReader.ReadString(' ')
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		sha = sha[:len(sha)-1]

		typ, err := bufReader.ReadString('\t')
		if err == io.EOF {
			// This should not happen, but we'll tolerate it
			break
		}
		if err != nil {
			return nil, err
		}
		typ = typ[:len(typ)-1]

		refName, err := bufReader.ReadString('\n')
		if err == io.EOF {
			// This should not happen, but we'll tolerate it
			break
		}
		if err != nil {
			return nil, err
		}
		refName = refName[:len(refName)-1]

		// refName cannot be HEAD but can be remotes or stash
		if strings.HasPrefix(refName, RemotePrefix) || refName == "/refs/stash" {
			continue
		}

		if pattern == "" || strings.HasPrefix(refName, pattern) {
			r := &Reference{
				Name:   refName,
				Object: MustIDFromString(sha),
				Type:   typ,
				repo:   repo,
			}
			refs = append(refs, r)
		}
	}

	return refs, nil
}