-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
// 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, []CmdArg{BranchPrefix, "--sort=-committerdate"}, 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, nil, 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 args []CmdArg
switch refType {
case ObjectTag:
args = []CmdArg{TagPrefix, "--sort=-taggerdate"}
case ObjectBranch:
args = []CmdArg{BranchPrefix, "--sort=-committerdate"}
}
return walkShowRef(repo.Ctx, repo.Path, args, skip, limit, walkfn)
}
// callShowRef return refs, if limit = 0 it will not limit
func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs []CmdArg, skip, limit int) (branchNames []string, countAll int, err error) {
countAll, err = walkShowRef(ctx, repoPath, extraArgs, skip, limit, func(_, branchName string) error {
branchName = strings.TrimPrefix(branchName, trimPrefix)
branchNames = append(branchNames, branchName)
return nil
})
return branchNames, countAll, err
}
func walkShowRef(ctx context.Context, repoPath string, extraArgs []CmdArg, 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 := []CmdArg{"for-each-ref", "--format=%(objectname) %(refname)"}
args = append(args, extraArgs...)
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
}
// GetRefsBySha returns all references filtered with prefix that belong to a sha commit hash
func (repo *Repository) GetRefsBySha(sha, prefix string) ([]string, error) {
var revList []string
_, err := walkShowRef(repo.Ctx, repo.Path, nil, 0, 0, func(walkSha, refname string) error {
if walkSha == sha && strings.HasPrefix(refname, prefix) {
revList = append(revList, refname)
}
return nil
})
return revList, err
}