blob: c2046c899f811886055c38b96ddf5c0186d98edd [file] [log] [blame]
// Package dirsource implements the file.Source interface for filesystem
// directories.
//
// It is only appropriate for using in tests and demo mode at this time.
package dirsource
import (
"context"
"os"
"path/filepath"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/perf/go/file"
)
// channelSize is the buffer size of the file.File channel.
const channelSize = 10
// DirSource implements the file.Source interface using a filesystem directory.
//
// Caveats: Currently only walks the directory and emits a file.File for each
// file found. It does not watch the directory for changes. It also uses
// modified time in place of created time. This implementation is only useful
// for tests and demo mode.
type DirSource struct {
dir string
started bool
}
// New return a new instance of DirSource.
func New(dir string) (*DirSource, error) {
absDir, err := filepath.Abs(dir)
if err != nil {
return nil, skerr.Wrap(err)
}
return &DirSource{
dir: absDir,
}, nil
}
// Start implements the file.Source interface.
func (d *DirSource) Start(_ context.Context) (<-chan file.File, error) {
if d.started {
return nil, skerr.Fmt("Start can only be called once.")
}
d.started = true
ret := make(chan file.File, channelSize)
go func() {
defer close(ret)
err := filepath.Walk(d.dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return skerr.Wrap(err)
}
f, err := os.Open(path)
if err != nil {
return skerr.Wrap(err)
}
if info.IsDir() {
return nil
}
ret <- file.File{
Name: path,
Contents: f,
Created: info.ModTime(), // Obviously not created time.
}
return nil
})
if err != nil {
sklog.Errorf("Error walking the path %q: %s", d.dir, err)
}
}()
return ret, nil
}
// Confirm *DirSource implements the file.Source interface.
var _ file.Source = (*DirSource)(nil)