Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bundle: Implement a DirectoryLoader for fs.FS (#3493)
To make it possible to create a DirectoryLoader based on the fs.FS interface. This interface requires go version 1.16 or above. Fixes: #3489 Signed-off-by: Simon Gottschlag <simon.gottschlag@xenit.se>
- Loading branch information
1 parent
c6cbe7a
commit 32ee3b7
Showing
2 changed files
with
99 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// +build go1.16 | ||
|
||
package bundle | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"io/fs" | ||
"sync" | ||
) | ||
|
||
const ( | ||
defaultFSLoaderRoot = "." | ||
) | ||
|
||
type dirLoaderFS struct { | ||
sync.Mutex | ||
filesystem fs.FS | ||
files []string | ||
idx int | ||
} | ||
|
||
// NewFSLoader returns a basic DirectoryLoader implementation | ||
// that will load files from a fs.FS interface | ||
func NewFSLoader(filesystem fs.FS) (DirectoryLoader, error) { | ||
d := dirLoaderFS{ | ||
filesystem: filesystem, | ||
} | ||
|
||
err := fs.WalkDir(d.filesystem, defaultFSLoaderRoot, d.walkDir) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to list files: %w", err) | ||
} | ||
|
||
return &d, nil | ||
} | ||
|
||
func (d *dirLoaderFS) walkDir(path string, dirEntry fs.DirEntry, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if dirEntry != nil && dirEntry.Type().IsRegular() { | ||
d.files = append(d.files, path) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// NextFile iterates to the next file in the directory tree | ||
// and returns a file Descriptor for the file. | ||
func (d *dirLoaderFS) NextFile() (*Descriptor, error) { | ||
d.Lock() | ||
defer d.Unlock() | ||
|
||
// If done reading files then just return io.EOF | ||
// errors for each NextFile() call | ||
if d.idx >= len(d.files) { | ||
return nil, io.EOF | ||
} | ||
|
||
fileName := d.files[d.idx] | ||
d.idx++ | ||
|
||
fh, err := d.filesystem.Open(fileName) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to open file %s: %w", fileName, err) | ||
} | ||
|
||
fileNameWithSlash := fmt.Sprintf("/%s", fileName) | ||
f := newDescriptor(fileNameWithSlash, fileNameWithSlash, fh).withCloser(fh) | ||
return f, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// +build go1.16 | ||
|
||
package bundle | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
"testing/fstest" | ||
) | ||
|
||
func TestFSLoader(t *testing.T) { | ||
archiveFS := make(fstest.MapFS) | ||
for k, v := range archiveFiles { | ||
file := strings.TrimPrefix(k, "/") | ||
archiveFS[file] = &fstest.MapFile{ | ||
Data: []byte(v), | ||
} | ||
} | ||
|
||
loader, err := NewFSLoader(archiveFS) | ||
if err != nil { | ||
t.Fatalf("Unexpected error: %s", err) | ||
} | ||
|
||
testLoader(t, loader, "", archiveFiles) | ||
} |