Skip to content

Commit

Permalink
bundle: Implement a DirectoryLoader for fs.FS (#3493)
Browse files Browse the repository at this point in the history
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
simongottschlag committed May 31, 2021
1 parent c6cbe7a commit 32ee3b7
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
73 changes: 73 additions & 0 deletions bundle/filefs.go
@@ -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
}
26 changes: 26 additions & 0 deletions bundle/filefs_test.go
@@ -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)
}

0 comments on commit 32ee3b7

Please sign in to comment.