mirror of https://github.com/docker/cli.git
72 lines
1.4 KiB
Go
72 lines
1.4 KiB
Go
|
package fsutil
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"io"
|
||
|
"os"
|
||
|
"path"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
type FS interface {
|
||
|
Walk(context.Context, filepath.WalkFunc) error
|
||
|
Open(string) (io.ReadCloser, error)
|
||
|
}
|
||
|
|
||
|
func NewFS(root string, opt *WalkOpt) FS {
|
||
|
return &fs{
|
||
|
root: root,
|
||
|
opt: opt,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type fs struct {
|
||
|
root string
|
||
|
opt *WalkOpt
|
||
|
}
|
||
|
|
||
|
func (fs *fs) Walk(ctx context.Context, fn filepath.WalkFunc) error {
|
||
|
return Walk(ctx, fs.root, fs.opt, fn)
|
||
|
}
|
||
|
|
||
|
func (fs *fs) Open(p string) (io.ReadCloser, error) {
|
||
|
return os.Open(filepath.Join(fs.root, p))
|
||
|
}
|
||
|
|
||
|
func SubDirFS(fs FS, stat Stat) FS {
|
||
|
return &subDirFS{fs: fs, stat: stat}
|
||
|
}
|
||
|
|
||
|
type subDirFS struct {
|
||
|
fs FS
|
||
|
stat Stat
|
||
|
}
|
||
|
|
||
|
func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error {
|
||
|
main := &StatInfo{Stat: &fs.stat}
|
||
|
if !main.IsDir() {
|
||
|
return errors.Errorf("fs subdir not mode directory")
|
||
|
}
|
||
|
if main.Name() != fs.stat.Path {
|
||
|
return errors.Errorf("subdir path must be single file")
|
||
|
}
|
||
|
if err := fn(fs.stat.Path, main, nil); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return fs.fs.Walk(ctx, func(p string, fi os.FileInfo, err error) error {
|
||
|
stat, ok := fi.Sys().(*Stat)
|
||
|
if !ok {
|
||
|
return errors.Wrapf(err, "invalid fileinfo without stat info: %s", p)
|
||
|
}
|
||
|
stat.Path = path.Join(fs.stat.Path, stat.Path)
|
||
|
return fn(filepath.Join(fs.stat.Path, p), &StatInfo{stat}, nil)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (fs *subDirFS) Open(p string) (io.ReadCloser, error) {
|
||
|
return fs.fs.Open(strings.TrimPrefix(p, fs.stat.Path+"/"))
|
||
|
}
|