Skip to content

Commit 8e2e491

Browse files
committed
fix
1 parent 06b9eb3 commit 8e2e491

File tree

9 files changed

+217
-245
lines changed

9 files changed

+217
-245
lines changed

modules/git/batch_reader.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,15 +242,15 @@ func BinToHex(objectFormat ObjectFormat, sha, out []byte) []byte {
242242
return out
243243
}
244244

245-
// ParseTreeLine reads an entry from a tree in a cat-file --batch stream
245+
// ParseCatFileTreeLine reads an entry from a tree in a cat-file --batch stream
246246
// This carefully avoids allocations - except where fnameBuf is too small.
247247
// It is recommended therefore to pass in an fnameBuf large enough to avoid almost all allocations
248248
//
249249
// Each line is composed of:
250250
// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <binary HASH>
251251
//
252252
// We don't attempt to convert the raw HASH to save a lot of time
253-
func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) {
253+
func ParseCatFileTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) {
254254
var readBytes []byte
255255

256256
// Read the Mode & fname
@@ -260,7 +260,7 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu
260260
}
261261
idx := bytes.IndexByte(readBytes, ' ')
262262
if idx < 0 {
263-
log.Debug("missing space in readBytes ParseTreeLine: %s", readBytes)
263+
log.Debug("missing space in readBytes ParseCatFileTreeLine: %s", readBytes)
264264
return mode, fname, sha, n, &ErrNotExist{}
265265
}
266266

modules/git/commit_submodule_file.go

Lines changed: 0 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@
55
package git
66

77
import (
8-
"bufio"
9-
"context"
108
"fmt"
11-
"io"
129
"net"
1310
"net/url"
1411
"path"
1512
"regexp"
1613
"strings"
17-
18-
"code.gitea.io/gitea/modules/log"
1914
)
2015

2116
var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+@)?([a-zA-Z0-9._-]+):(.*)$`)
@@ -114,101 +109,3 @@ func (sf *CommitSubModuleFile) RefURL(urlPrefix, repoFullName, sshDomain string)
114109
func (sf *CommitSubModuleFile) RefID() string {
115110
return sf.refID
116111
}
117-
118-
// SubModuleCommit submodule name and commit from a repository
119-
type SubModuleCommit struct {
120-
Name string
121-
Commit string
122-
}
123-
124-
// GetSubmoduleCommits Returns a list of active submodules in the repository
125-
func GetSubmoduleCommits(ctx context.Context, repoPath string) []SubModuleCommit {
126-
stdoutReader, stdoutWriter := io.Pipe()
127-
defer func() {
128-
_ = stdoutReader.Close()
129-
_ = stdoutWriter.Close()
130-
}()
131-
132-
go func() {
133-
stderrBuilder := strings.Builder{}
134-
err := NewCommand(ctx, "config", "-f", ".gitmodules", "--list", "--name-only").Run(&RunOpts{
135-
Timeout: -1,
136-
Dir: repoPath,
137-
Stdout: stdoutWriter,
138-
Stderr: &stderrBuilder,
139-
})
140-
141-
if err != nil {
142-
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))
143-
} else {
144-
_ = stdoutWriter.Close()
145-
}
146-
}()
147-
148-
var submodules []SubModuleCommit
149-
bufReader := bufio.NewReader(stdoutReader)
150-
151-
for {
152-
line, err := bufReader.ReadString('\n')
153-
if err != nil {
154-
break
155-
}
156-
157-
if len(line) < len("submodule.x.url\n") ||
158-
!strings.HasPrefix(line, "submodule.") ||
159-
!strings.HasSuffix(line, ".url\n") {
160-
161-
continue
162-
}
163-
164-
name := line[len("submodule.") : len(line)-len(".url\n")]
165-
name = strings.TrimSpace(name)
166-
167-
if len(name) == 0 {
168-
log.Debug("Submodule skipped because it has no name")
169-
continue
170-
}
171-
172-
// If no commit was found for the module skip it
173-
commit, _, err := NewCommand(ctx, "submodule", "status").AddDynamicArguments(name).RunStdString(&RunOpts{Dir: repoPath})
174-
if err != nil {
175-
log.Debug("Submodule %s skipped because it has no commit", name)
176-
continue
177-
}
178-
179-
if len(commit) > 0 {
180-
commit = commit[1:]
181-
}
182-
183-
fields := strings.Fields(commit)
184-
185-
if len(fields) == 0 {
186-
log.Debug("Submodule %s skipped because it has no valid commit", name)
187-
continue
188-
}
189-
190-
commit = fields[0]
191-
192-
if len(commit) != 40 {
193-
log.Debug("Submodule %s skipped due to malformed commit hash", name)
194-
continue
195-
}
196-
197-
submodules = append(submodules, SubModuleCommit{name, commit})
198-
}
199-
200-
return submodules
201-
}
202-
203-
// AddSubmoduleIndexes Adds the given submodules to the git index. Requires the .gitmodules file to be already present.
204-
func AddSubmoduleIndexes(ctx context.Context, repoPath string, submodules []SubModuleCommit) error {
205-
for _, submodule := range submodules {
206-
if stdout, _, err := NewCommand(ctx, "update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Name).
207-
RunStdString(&RunOpts{Dir: repoPath}); err != nil {
208-
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Name, repoPath, stdout, err)
209-
return err
210-
}
211-
}
212-
213-
return nil
214-
}

modules/git/commit_submodule_file_test.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
package git
55

66
import (
7-
"path/filepath"
87
"testing"
98

10-
"code.gitea.io/gitea/modules/util"
119
"github.com/stretchr/testify/assert"
1210
)
1311

@@ -42,20 +40,3 @@ func TestCommitSubModuleFileGetRefURL(t *testing.T) {
4240
assert.EqualValues(t, kase.expect, getRefURL(kase.refURL, kase.prefixURL, kase.parentPath, kase.SSHDomain))
4341
}
4442
}
45-
46-
func TestRepository_GetSubmoduleCommits(t *testing.T) {
47-
bareRepo1Path := filepath.Join(testReposDir, "repo4_submodules")
48-
clonedPath, err := cloneRepo(bareRepo1Path, "repo4_TestRepository_GetSubmoduleCommits")
49-
assert.NoError(t, err)
50-
defer util.RemoveAll(clonedPath)
51-
52-
submodules := GetSubmoduleCommits(DefaultContext, clonedPath)
53-
54-
assert.EqualValues(t, len(submodules), 2)
55-
56-
assert.EqualValues(t, submodules[0].Name, "libtest")
57-
assert.EqualValues(t, submodules[0].Commit, "1234567890123456789012345678901234567890")
58-
59-
assert.EqualValues(t, submodules[1].Name, "<°)))><")
60-
assert.EqualValues(t, submodules[1].Commit, "d2932de67963f23d43e1c7ecf20173e92ee6c43c")
61-
}

modules/git/parse_nogogit.go

Lines changed: 62 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -23,68 +23,79 @@ func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
2323

2424
var sepSpace = []byte{' '}
2525

26-
func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
26+
func parseLsTreeLine(line []byte) (*TreeEntry, error) {
27+
// expect line to be of the form:
28+
// <mode> <type> <sha> <space-padded-size>\t<filename>
29+
// <mode> <type> <sha>\t<filename>
30+
2731
var err error
32+
posTab := bytes.IndexByte(line, '\t')
33+
if posTab == -1 {
34+
return nil, fmt.Errorf("invalid ls-tree output (no tab): %q", line)
35+
}
36+
37+
entry := new(TreeEntry)
38+
39+
entryAttrs := line[:posTab]
40+
entryName := line[posTab+1:]
41+
42+
entryMode, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
43+
_ /* entryType */, entryAttrs, _ = bytes.Cut(entryAttrs, sepSpace) // the type is not used, the mode is enough to determine the type
44+
entryObjectID, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
45+
if len(entryAttrs) > 0 {
46+
entrySize := entryAttrs // the last field is the space-padded-size
47+
entry.size, _ = strconv.ParseInt(strings.TrimSpace(string(entrySize)), 10, 64)
48+
entry.sized = true
49+
}
50+
51+
switch string(entryMode) {
52+
case "100644":
53+
entry.entryMode = EntryModeBlob
54+
case "100755":
55+
entry.entryMode = EntryModeExec
56+
case "120000":
57+
entry.entryMode = EntryModeSymlink
58+
case "160000":
59+
entry.entryMode = EntryModeCommit
60+
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
61+
entry.entryMode = EntryModeTree
62+
default:
63+
return nil, fmt.Errorf("unknown type: %v", string(entryMode))
64+
}
65+
66+
entry.ID, err = NewIDFromString(string(entryObjectID))
67+
if err != nil {
68+
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
69+
}
70+
71+
if len(entryName) > 0 && entryName[0] == '"' {
72+
entry.name, err = strconv.Unquote(string(entryName))
73+
if err != nil {
74+
return nil, fmt.Errorf("invalid ls-tree output (invalid name): %q, err: %w", line, err)
75+
}
76+
} else {
77+
entry.name = string(entryName)
78+
}
79+
return entry, nil
80+
}
81+
82+
// parseTreeEntries FIXME this function's design is not right, it should make the caller read all data into memory
83+
func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
2884
entries := make([]*TreeEntry, 0, bytes.Count(data, []byte{'\n'})+1)
2985
for pos := 0; pos < len(data); {
30-
// expect line to be of the form:
31-
// <mode> <type> <sha> <space-padded-size>\t<filename>
32-
// <mode> <type> <sha>\t<filename>
3386
posEnd := bytes.IndexByte(data[pos:], '\n')
3487
if posEnd == -1 {
3588
posEnd = len(data)
3689
} else {
3790
posEnd += pos
3891
}
39-
line := data[pos:posEnd]
40-
posTab := bytes.IndexByte(line, '\t')
41-
if posTab == -1 {
42-
return nil, fmt.Errorf("invalid ls-tree output (no tab): %q", line)
43-
}
44-
45-
entry := new(TreeEntry)
46-
entry.ptree = ptree
4792

48-
entryAttrs := line[:posTab]
49-
entryName := line[posTab+1:]
50-
51-
entryMode, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
52-
_ /* entryType */, entryAttrs, _ = bytes.Cut(entryAttrs, sepSpace) // the type is not used, the mode is enough to determine the type
53-
entryObjectID, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
54-
if len(entryAttrs) > 0 {
55-
entrySize := entryAttrs // the last field is the space-padded-size
56-
entry.size, _ = strconv.ParseInt(strings.TrimSpace(string(entrySize)), 10, 64)
57-
entry.sized = true
58-
}
59-
60-
switch string(entryMode) {
61-
case "100644":
62-
entry.entryMode = EntryModeBlob
63-
case "100755":
64-
entry.entryMode = EntryModeExec
65-
case "120000":
66-
entry.entryMode = EntryModeSymlink
67-
case "160000":
68-
entry.entryMode = EntryModeCommit
69-
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
70-
entry.entryMode = EntryModeTree
71-
default:
72-
return nil, fmt.Errorf("unknown type: %v", string(entryMode))
73-
}
74-
75-
entry.ID, err = NewIDFromString(string(entryObjectID))
93+
line := data[pos:posEnd]
94+
entry, err := parseLsTreeLine(line)
7695
if err != nil {
77-
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
78-
}
79-
80-
if len(entryName) > 0 && entryName[0] == '"' {
81-
entry.name, err = strconv.Unquote(string(entryName))
82-
if err != nil {
83-
return nil, fmt.Errorf("invalid ls-tree output (invalid name): %q, err: %w", line, err)
84-
}
85-
} else {
86-
entry.name = string(entryName)
96+
return nil, err
8797
}
98+
entry.ptree = ptree
8899

89100
pos = posEnd + 1
90101
entries = append(entries, entry)
@@ -100,7 +111,7 @@ func catBatchParseTreeEntries(objectFormat ObjectFormat, ptree *Tree, rd *bufio.
100111

101112
loop:
102113
for sz > 0 {
103-
mode, fname, sha, count, err := ParseTreeLine(objectFormat, rd, modeBuf, fnameBuf, shaBuf)
114+
mode, fname, sha, count, err := ParseCatFileTreeLine(objectFormat, rd, modeBuf, fnameBuf, shaBuf)
104115
if err != nil {
105116
if err == io.EOF {
106117
break loop

modules/git/pipeline/lfs_nogogit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
114114
case "tree":
115115
var n int64
116116
for n < size {
117-
mode, fname, binObjectID, count, err := git.ParseTreeLine(objectID.Type(), batchReader, modeBuf, fnameBuf, workingShaBuf)
117+
mode, fname, binObjectID, count, err := git.ParseCatFileTreeLine(objectID.Type(), batchReader, modeBuf, fnameBuf, workingShaBuf)
118118
if err != nil {
119119
return nil, err
120120
}

modules/git/submodule.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package git
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"fmt"
7+
"os"
8+
9+
"code.gitea.io/gitea/modules/log"
10+
)
11+
12+
// SubModuleCommit submodule name and commit from a repository
13+
type SubModuleCommit struct {
14+
Path string
15+
Commit string
16+
}
17+
18+
// GetSubmoduleCommits returns a list of submodules paths and their commits from a repository
19+
// This function is only for generating new repos based on existing template, the template couldn't be too large.
20+
func GetSubmoduleCommits(ctx context.Context, repoPath string) (submoduleCommits []SubModuleCommit, _ error) {
21+
stdoutReader, stdoutWriter, err := os.Pipe()
22+
if err != nil {
23+
return nil, err
24+
}
25+
opts := &RunOpts{
26+
Dir: repoPath,
27+
Stdout: stdoutWriter,
28+
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
29+
_ = stdoutWriter.Close()
30+
defer stdoutReader.Close()
31+
32+
scanner := bufio.NewScanner(stdoutReader)
33+
for scanner.Scan() {
34+
entry, err := parseLsTreeLine(scanner.Bytes())
35+
if err != nil {
36+
cancel()
37+
return err
38+
}
39+
if entry.IsSubModule() {
40+
submoduleCommits = append(submoduleCommits, SubModuleCommit{Path: entry.Name(), Commit: entry.ID.String()})
41+
}
42+
}
43+
return scanner.Err()
44+
},
45+
}
46+
err = NewCommand(ctx, "ls-tree", "-r", "--", "HEAD").Run(opts)
47+
if err != nil {
48+
return nil, fmt.Errorf("GetSubmoduleCommits: error running git ls-tree: %v", err)
49+
}
50+
return submoduleCommits, nil
51+
}
52+
53+
// AddSubmoduleIndexes Adds the given submodules to the git index. Requires the .gitmodules file to be already present.
54+
func AddSubmoduleIndexes(ctx context.Context, repoPath string, submodules []SubModuleCommit) error {
55+
for _, submodule := range submodules {
56+
cmd := NewCommand(ctx, "update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path)
57+
if stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath}); err != nil {
58+
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, repoPath, stdout, err)
59+
return err
60+
}
61+
}
62+
return nil
63+
}

0 commit comments

Comments
 (0)