QBitRun/lib/workflow/open.go

96 lines
2 KiB
Go

package workflow
import (
"errors"
"io"
"io/fs"
"os"
"path/filepath"
lop "github.com/samber/lo/parallel"
"gopkg.in/yaml.v3"
)
type WorkflowFiles []io.Reader
func (wo WorkflowFiles) Close() error {
var errs []error
for _, reader := range wo {
if reader, ok := reader.(io.ReadCloser); ok {
errs = append(errs, reader.Close())
}
}
return errors.Join(errs...)
}
func (wo WorkflowFiles) Workflows() ([]Workflow, error) {
var (
errs = []error{}
workflows = make([]Workflow, 0, len(wo))
)
lop.ForEach(wo, func(reader io.Reader, _ int) {
var w Workflow
if err := yaml.NewDecoder(reader).Decode(&w); err != nil {
errs = append(errs, err)
} else {
workflows = append(workflows, w)
}
if rc, ok := reader.(io.ReadCloser); ok {
if err := rc.Close(); err != nil {
errs = append(errs, err)
}
}
})
return workflows, errors.Join(errs...)
}
type DirFilter = func(path string, d fs.FileInfo) bool
// OpenDir opens a directory and returns a WorkflowInput.
//
// Set filter to filter out unwanted files.
func OpenDir(dir string, filters ...DirFilter) (WorkflowFiles, error) {
var files []io.Reader
err := filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
ok := true
for _, filter := range filters {
ok = filter(path, info)
if !ok {
break
}
}
if ok {
file, err := os.Open(path)
if err != nil {
return err
}
files = append(files, file)
}
return nil
})
if err != nil {
return nil, err
}
return WorkflowFiles(files), nil
}
// WorkflowFromReaders creates a WorkflowInput from a list of io.Reader.
//
// If the Reader implements io.ReadCloser, it will be used as is.
// If not, it will be wrapped with io.NopCloser.
//
// WorkflowFromReaders assumes ownership of the Readers and will close (if implements io.ReadCloser)
// all of them after the WorkflowInput is consumed (whether successfully or not).
func WorkflowFromReaders(readers ...io.Reader) WorkflowFiles {
return WorkflowFiles(readers)
}