Skip to content

Commit 61ad4c6

Browse files
fuxiaoheiGiteaBot
andauthored
fix minio storage iterator path (#24691)
minio storage iterator shows different behavior with local fs iterator. in local fs storage: ``` go s.IterateObjects("prefix", func(path,obj) println(path) // show "prefix/xxx.file" }) ``` in minio storage: ```go s.IterateObjects("prefix", func(path,obj) println(path) // show "xxx.file" }) ``` I think local fs is correct, minio use wrong `basePath` to trim storage path prefix. --------- Co-authored-by: Giteabot <[email protected]>
1 parent 4810fe5 commit 61ad4c6

File tree

6 files changed

+87
-43
lines changed

6 files changed

+87
-43
lines changed

.github/workflows/pull-db-tests.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ jobs:
102102
--health-retries 10
103103
ports:
104104
- 6379:6379
105+
minio:
106+
image: bitnami/minio:2021.3.17
107+
env:
108+
MINIO_ACCESS_KEY: 123456
109+
MINIO_SECRET_KEY: 12345678
110+
ports:
111+
- "9000:9000"
105112
steps:
106113
- uses: actions/checkout@v3
107114
- uses: actions/setup-go@v4

modules/storage/local.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ func (l *LocalStorage) URL(path, name string) (*url.URL, error) {
133133
}
134134

135135
// IterateObjects iterates across the objects in the local storage
136-
func (l *LocalStorage) IterateObjects(prefix string, fn func(path string, obj Object) error) error {
137-
dir := l.buildLocalPath(prefix)
136+
func (l *LocalStorage) IterateObjects(dirName string, fn func(path string, obj Object) error) error {
137+
dir := l.buildLocalPath(dirName)
138138
return filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
139139
if err != nil {
140140
return err

modules/storage/local_test.go

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
package storage
55

66
import (
7-
"bytes"
8-
"context"
97
"os"
108
"path/filepath"
119
"testing"
@@ -57,38 +55,5 @@ func TestBuildLocalPath(t *testing.T) {
5755

5856
func TestLocalStorageIterator(t *testing.T) {
5957
dir := filepath.Join(os.TempDir(), "TestLocalStorageIteratorTestDir")
60-
l, err := NewLocalStorage(context.Background(), LocalStorageConfig{Path: dir})
61-
assert.NoError(t, err)
62-
63-
testFiles := [][]string{
64-
{"a/1.txt", "a1"},
65-
{"/a/1.txt", "aa1"}, // same as above, but with leading slash that will be trim
66-
{"b/1.txt", "b1"},
67-
{"b/2.txt", "b2"},
68-
{"b/3.txt", "b3"},
69-
{"b/x 4.txt", "bx4"},
70-
}
71-
for _, f := range testFiles {
72-
_, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1)
73-
assert.NoError(t, err)
74-
}
75-
76-
expectedList := map[string][]string{
77-
"a": {"a/1.txt"},
78-
"b": {"b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
79-
"": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
80-
"/": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
81-
"a/b/../../a": {"a/1.txt"},
82-
}
83-
for dir, expected := range expectedList {
84-
count := 0
85-
err = l.IterateObjects(dir, func(path string, f Object) error {
86-
defer f.Close()
87-
assert.Contains(t, expected, path)
88-
count++
89-
return nil
90-
})
91-
assert.NoError(t, err)
92-
assert.Len(t, expected, count)
93-
}
58+
testStorageIterator(t, string(LocalStorageType), LocalStorageConfig{Path: dir})
9459
}

modules/storage/minio.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
129129
}
130130

131131
func (m *MinioStorage) buildMinioPath(p string) string {
132-
return util.PathJoinRelX(m.basePath, p)
132+
p = util.PathJoinRelX(m.basePath, p)
133+
if p == "." {
134+
p = "" // minio doesn't use dot as relative path
135+
}
136+
return p
133137
}
134138

135139
// Open opens a file
@@ -224,14 +228,15 @@ func (m *MinioStorage) URL(path, name string) (*url.URL, error) {
224228
}
225229

226230
// IterateObjects iterates across the objects in the miniostorage
227-
func (m *MinioStorage) IterateObjects(prefix string, fn func(path string, obj Object) error) error {
231+
func (m *MinioStorage) IterateObjects(dirName string, fn func(path string, obj Object) error) error {
228232
opts := minio.GetObjectOptions{}
229233
lobjectCtx, cancel := context.WithCancel(m.ctx)
230234
defer cancel()
231235

232236
basePath := m.basePath
233-
if prefix != "" {
234-
basePath = m.buildMinioPath(prefix)
237+
if dirName != "" {
238+
// ending slash is required for avoiding matching like "foo/" and "foobar/" with prefix "foo"
239+
basePath = m.buildMinioPath(dirName) + "/"
235240
}
236241

237242
for mObjInfo := range m.client.ListObjects(lobjectCtx, m.bucket, minio.ListObjectsOptions{
@@ -244,7 +249,7 @@ func (m *MinioStorage) IterateObjects(prefix string, fn func(path string, obj Ob
244249
}
245250
if err := func(object *minio.Object, fn func(path string, obj Object) error) error {
246251
defer object.Close()
247-
return fn(strings.TrimPrefix(mObjInfo.Key, basePath), &minioObject{object})
252+
return fn(strings.TrimPrefix(mObjInfo.Key, m.basePath), &minioObject{object})
248253
}(object, fn); err != nil {
249254
return convertMinioErr(err)
250255
}

modules/storage/minio_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package storage
5+
6+
import (
7+
"testing"
8+
)
9+
10+
func TestMinioStorageIterator(t *testing.T) {
11+
testStorageIterator(t, string(MinioStorageType), MinioStorageConfig{
12+
Endpoint: "127.0.0.1:9000",
13+
AccessKeyID: "123456",
14+
SecretAccessKey: "12345678",
15+
Bucket: "gitea",
16+
Location: "us-east-1",
17+
})
18+
}

modules/storage/storage_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package storage
5+
6+
import (
7+
"bytes"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func testStorageIterator(t *testing.T, typStr string, cfg interface{}) {
14+
l, err := NewStorage(typStr, cfg)
15+
assert.NoError(t, err)
16+
17+
testFiles := [][]string{
18+
{"a/1.txt", "a1"},
19+
{"/a/1.txt", "aa1"}, // same as above, but with leading slash that will be trim
20+
{"ab/1.txt", "ab1"},
21+
{"b/1.txt", "b1"},
22+
{"b/2.txt", "b2"},
23+
{"b/3.txt", "b3"},
24+
{"b/x 4.txt", "bx4"},
25+
}
26+
for _, f := range testFiles {
27+
_, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1)
28+
assert.NoError(t, err)
29+
}
30+
31+
expectedList := map[string][]string{
32+
"a": {"a/1.txt"},
33+
"b": {"b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
34+
"": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt", "ab/1.txt"},
35+
"/": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt", "ab/1.txt"},
36+
"a/b/../../a": {"a/1.txt"},
37+
}
38+
for dir, expected := range expectedList {
39+
count := 0
40+
err = l.IterateObjects(dir, func(path string, f Object) error {
41+
defer f.Close()
42+
assert.Contains(t, expected, path)
43+
count++
44+
return nil
45+
})
46+
assert.NoError(t, err)
47+
assert.Len(t, expected, count)
48+
}
49+
}

0 commit comments

Comments
 (0)