Skip to content

Commit 2a70f2b

Browse files
committed
Make mem.File implement fs.ReadDirFile
1 parent 0aa65ed commit 2a70f2b

File tree

5 files changed

+80
-20
lines changed

5 files changed

+80
-20
lines changed

afero_test.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bytes"
1919
"fmt"
2020
"io"
21+
iofs "io/fs"
2122
"io/ioutil"
2223
"os"
2324
"path/filepath"
@@ -530,22 +531,43 @@ func TestReaddirSimple(t *testing.T) {
530531

531532
func TestReaddir(t *testing.T) {
532533
defer removeAllTestFiles(t)
533-
for num := 0; num < 6; num++ {
534+
const nums = 6
535+
for num := 0; num < nums; num++ {
534536
outputs := make([]string, len(Fss))
535537
infos := make([]string, len(Fss))
536538
for i, fs := range Fss {
537539
testSubDir := setupTestDir(t, fs)
538-
//tDir := filepath.Dir(testSubDir)
539540
root, err := fs.Open(testSubDir)
540541
if err != nil {
541542
t.Fatal(err)
542543
}
543-
defer root.Close()
544544

545-
for j := 0; j < 6; j++ {
545+
infosn := make([]string, nums)
546+
547+
for j := 0; j < nums; j++ {
546548
info, err := root.Readdir(num)
547549
outputs[i] += fmt.Sprintf("%v Error: %v\n", myFileInfo(info), err)
548-
infos[i] += fmt.Sprintln(len(info), err)
550+
s := fmt.Sprintln(len(info), err)
551+
infosn[j] = s
552+
infos[i] += s
553+
}
554+
root.Close()
555+
556+
// Also check fs.ReadDirFile interface if implemented
557+
if _, ok := root.(iofs.ReadDirFile); ok {
558+
root, err = fs.Open(testSubDir)
559+
if err != nil {
560+
t.Fatal(err)
561+
}
562+
defer root.Close()
563+
564+
for j := 0; j < nums; j++ {
565+
dirEntries, err := root.(iofs.ReadDirFile).ReadDir(num)
566+
s := fmt.Sprintln(len(dirEntries), err)
567+
if s != infosn[j] {
568+
t.Fatalf("%s: %s != %s", fs.Name(), s, infosn[j])
569+
}
570+
}
549571
}
550572
}
551573

internal/common/adapters.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright © 2022 Steve Francia <[email protected]>.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package common
15+
16+
import "io/fs"
17+
18+
// FileInfoDirEntry provides an adapter from os.FileInfo to fs.DirEntry
19+
type FileInfoDirEntry struct {
20+
fs.FileInfo
21+
}
22+
23+
var _ fs.DirEntry = FileInfoDirEntry{}
24+
25+
func (d FileInfoDirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
26+
27+
func (d FileInfoDirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }

iofs.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"path"
1111
"sort"
1212
"time"
13+
14+
"github.com/spf13/afero/internal/common"
1315
)
1416

1517
// IOFS adopts afero.Fs to stdlib io/fs.FS
@@ -92,7 +94,7 @@ func (iofs IOFS) ReadDir(name string) ([]fs.DirEntry, error) {
9294

9395
ret := make([]fs.DirEntry, len(items))
9496
for i := range items {
95-
ret[i] = dirEntry{items[i]}
97+
ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
9698
}
9799

98100
return ret, nil
@@ -127,17 +129,6 @@ func (IOFS) wrapError(op, path string, err error) error {
127129
}
128130
}
129131

130-
// dirEntry provides adapter from os.FileInfo to fs.DirEntry
131-
type dirEntry struct {
132-
fs.FileInfo
133-
}
134-
135-
var _ fs.DirEntry = dirEntry{}
136-
137-
func (d dirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
138-
139-
func (d dirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }
140-
141132
// readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open
142133
type readDirFile struct {
143134
File
@@ -153,7 +144,7 @@ func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) {
153144

154145
ret := make([]fs.DirEntry, len(items))
155146
for i := range items {
156-
ret[i] = dirEntry{items[i]}
147+
ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
157148
}
158149

159150
return ret, nil

iofs_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"testing"
1717
"testing/fstest"
1818
"time"
19+
20+
"github.com/spf13/afero/internal/common"
1921
)
2022

2123
func TestIOFS(t *testing.T) {
@@ -105,7 +107,7 @@ func TestIOFSNativeDirEntryWhenPossible(t *testing.T) {
105107
t.Fatalf("expected %d, got %d", numFiles, len(entries))
106108
}
107109
for i, entry := range entries {
108-
if _, ok := entry.(dirEntry); ok {
110+
if _, ok := entry.(common.FileInfoDirEntry); ok {
109111
t.Fatal("DirEntry not native")
110112
}
111113
if ordered && entry.Name() != fmt.Sprintf("test%d.txt", i) {
@@ -138,7 +140,7 @@ func TestIOFSNativeDirEntryWhenPossible(t *testing.T) {
138140
fileCount++
139141
}
140142

141-
if _, ok := d.(dirEntry); ok {
143+
if _, ok := d.(common.FileInfoDirEntry); ok {
142144
t.Fatal("DirEntry not native")
143145
}
144146

mem/file.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,20 @@ import (
1818
"bytes"
1919
"errors"
2020
"io"
21+
"io/fs"
2122
"os"
2223
"path/filepath"
2324
"sync"
2425
"sync/atomic"
2526
"time"
27+
28+
"github.com/spf13/afero/internal/common"
2629
)
2730

2831
const FilePathSeparator = string(filepath.Separator)
2932

33+
var _ fs.ReadDirFile = &File{}
34+
3035
type File struct {
3136
// atomic requires 64-bit alignment for struct field access
3237
at int64
@@ -183,6 +188,19 @@ func (f *File) Readdirnames(n int) (names []string, err error) {
183188
return names, err
184189
}
185190

191+
// Implements fs.ReadDirFile
192+
func (f *File) ReadDir(n int) ([]fs.DirEntry, error) {
193+
fi, err := f.Readdir(n)
194+
if err != nil {
195+
return nil, err
196+
}
197+
di := make([]fs.DirEntry, len(fi))
198+
for i, f := range fi {
199+
di[i] = common.FileInfoDirEntry{FileInfo: f}
200+
}
201+
return di, nil
202+
}
203+
186204
func (f *File) Read(b []byte) (n int, err error) {
187205
f.fileData.Lock()
188206
defer f.fileData.Unlock()

0 commit comments

Comments
 (0)