mirror of https://github.com/spf13/afero.git
Make mem.File implement fs.ReadDirFile
This commit is contained in:
parent
0aa65edf44
commit
2a70f2bb2d
|
@ -18,6 +18,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
iofs "io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -530,22 +531,43 @@ func TestReaddirSimple(t *testing.T) {
|
||||||
|
|
||||||
func TestReaddir(t *testing.T) {
|
func TestReaddir(t *testing.T) {
|
||||||
defer removeAllTestFiles(t)
|
defer removeAllTestFiles(t)
|
||||||
for num := 0; num < 6; num++ {
|
const nums = 6
|
||||||
|
for num := 0; num < nums; num++ {
|
||||||
outputs := make([]string, len(Fss))
|
outputs := make([]string, len(Fss))
|
||||||
infos := make([]string, len(Fss))
|
infos := make([]string, len(Fss))
|
||||||
for i, fs := range Fss {
|
for i, fs := range Fss {
|
||||||
testSubDir := setupTestDir(t, fs)
|
testSubDir := setupTestDir(t, fs)
|
||||||
//tDir := filepath.Dir(testSubDir)
|
|
||||||
root, err := fs.Open(testSubDir)
|
root, err := fs.Open(testSubDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer root.Close()
|
|
||||||
|
|
||||||
for j := 0; j < 6; j++ {
|
infosn := make([]string, nums)
|
||||||
|
|
||||||
|
for j := 0; j < nums; j++ {
|
||||||
info, err := root.Readdir(num)
|
info, err := root.Readdir(num)
|
||||||
outputs[i] += fmt.Sprintf("%v Error: %v\n", myFileInfo(info), err)
|
outputs[i] += fmt.Sprintf("%v Error: %v\n", myFileInfo(info), err)
|
||||||
infos[i] += fmt.Sprintln(len(info), err)
|
s := fmt.Sprintln(len(info), err)
|
||||||
|
infosn[j] = s
|
||||||
|
infos[i] += s
|
||||||
|
}
|
||||||
|
root.Close()
|
||||||
|
|
||||||
|
// Also check fs.ReadDirFile interface if implemented
|
||||||
|
if _, ok := root.(iofs.ReadDirFile); ok {
|
||||||
|
root, err = fs.Open(testSubDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer root.Close()
|
||||||
|
|
||||||
|
for j := 0; j < nums; j++ {
|
||||||
|
dirEntries, err := root.(iofs.ReadDirFile).ReadDir(num)
|
||||||
|
s := fmt.Sprintln(len(dirEntries), err)
|
||||||
|
if s != infosn[j] {
|
||||||
|
t.Fatalf("%s: %s != %s", fs.Name(), s, infosn[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright © 2022 Steve Francia <spf@spf13.com>.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package common
|
||||||
|
|
||||||
|
import "io/fs"
|
||||||
|
|
||||||
|
// FileInfoDirEntry provides an adapter from os.FileInfo to fs.DirEntry
|
||||||
|
type FileInfoDirEntry struct {
|
||||||
|
fs.FileInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.DirEntry = FileInfoDirEntry{}
|
||||||
|
|
||||||
|
func (d FileInfoDirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
|
||||||
|
|
||||||
|
func (d FileInfoDirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }
|
17
iofs.go
17
iofs.go
|
@ -10,6 +10,8 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/afero/internal/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IOFS adopts afero.Fs to stdlib io/fs.FS
|
// IOFS adopts afero.Fs to stdlib io/fs.FS
|
||||||
|
@ -92,7 +94,7 @@ func (iofs IOFS) ReadDir(name string) ([]fs.DirEntry, error) {
|
||||||
|
|
||||||
ret := make([]fs.DirEntry, len(items))
|
ret := make([]fs.DirEntry, len(items))
|
||||||
for i := range items {
|
for i := range items {
|
||||||
ret[i] = dirEntry{items[i]}
|
ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
@ -127,17 +129,6 @@ func (IOFS) wrapError(op, path string, err error) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// dirEntry provides adapter from os.FileInfo to fs.DirEntry
|
|
||||||
type dirEntry struct {
|
|
||||||
fs.FileInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ fs.DirEntry = dirEntry{}
|
|
||||||
|
|
||||||
func (d dirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
|
|
||||||
|
|
||||||
func (d dirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }
|
|
||||||
|
|
||||||
// readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open
|
// readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open
|
||||||
type readDirFile struct {
|
type readDirFile struct {
|
||||||
File
|
File
|
||||||
|
@ -153,7 +144,7 @@ func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) {
|
||||||
|
|
||||||
ret := make([]fs.DirEntry, len(items))
|
ret := make([]fs.DirEntry, len(items))
|
||||||
for i := range items {
|
for i := range items {
|
||||||
ret[i] = dirEntry{items[i]}
|
ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
|
@ -16,6 +16,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/afero/internal/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIOFS(t *testing.T) {
|
func TestIOFS(t *testing.T) {
|
||||||
|
@ -105,7 +107,7 @@ func TestIOFSNativeDirEntryWhenPossible(t *testing.T) {
|
||||||
t.Fatalf("expected %d, got %d", numFiles, len(entries))
|
t.Fatalf("expected %d, got %d", numFiles, len(entries))
|
||||||
}
|
}
|
||||||
for i, entry := range entries {
|
for i, entry := range entries {
|
||||||
if _, ok := entry.(dirEntry); ok {
|
if _, ok := entry.(common.FileInfoDirEntry); ok {
|
||||||
t.Fatal("DirEntry not native")
|
t.Fatal("DirEntry not native")
|
||||||
}
|
}
|
||||||
if ordered && entry.Name() != fmt.Sprintf("test%d.txt", i) {
|
if ordered && entry.Name() != fmt.Sprintf("test%d.txt", i) {
|
||||||
|
@ -138,7 +140,7 @@ func TestIOFSNativeDirEntryWhenPossible(t *testing.T) {
|
||||||
fileCount++
|
fileCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := d.(dirEntry); ok {
|
if _, ok := d.(common.FileInfoDirEntry); ok {
|
||||||
t.Fatal("DirEntry not native")
|
t.Fatal("DirEntry not native")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
mem/file.go
18
mem/file.go
|
@ -18,15 +18,20 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/afero/internal/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const FilePathSeparator = string(filepath.Separator)
|
const FilePathSeparator = string(filepath.Separator)
|
||||||
|
|
||||||
|
var _ fs.ReadDirFile = &File{}
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
// atomic requires 64-bit alignment for struct field access
|
// atomic requires 64-bit alignment for struct field access
|
||||||
at int64
|
at int64
|
||||||
|
@ -183,6 +188,19 @@ func (f *File) Readdirnames(n int) (names []string, err error) {
|
||||||
return names, err
|
return names, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements fs.ReadDirFile
|
||||||
|
func (f *File) ReadDir(n int) ([]fs.DirEntry, error) {
|
||||||
|
fi, err := f.Readdir(n)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
di := make([]fs.DirEntry, len(fi))
|
||||||
|
for i, f := range fi {
|
||||||
|
di[i] = common.FileInfoDirEntry{FileInfo: f}
|
||||||
|
}
|
||||||
|
return di, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) Read(b []byte) (n int, err error) {
|
func (f *File) Read(b []byte) (n int, err error) {
|
||||||
f.fileData.Lock()
|
f.fileData.Lock()
|
||||||
defer f.fileData.Unlock()
|
defer f.fileData.Unlock()
|
||||||
|
|
Loading…
Reference in New Issue