@@ -6,77 +6,68 @@ import (
66 "io"
77 "io/fs"
88 "log/slog"
9- "path"
10- )
119
12- type dotFS struct {
13- fs fs.FS
14- log * slog.Logger
15- opened map [fs.File ]struct {}
16- }
10+ "github.com/spf13/afero"
11+ )
1712
1813// Dir
1914type Dir struct {
20- dot * dotFS
21- path string
15+ fs afero.Fs
16+ log * slog.Logger
17+ opened map [afero.File ]struct {}
2218}
2319
24- // Dir returns a
25- func (d Dir ) Dir (name string ) (Dir , error ) {
26- name = path .Clean (name )
27- if st , err := d .Stat (name ); err != nil {
28- return Dir {}, err
29- } else if ! st .IsDir () {
30- return Dir {}, fmt .Errorf ("not a directory: %s" , name )
20+ // Chroot returns a copy of the filesystem with root changed to path.
21+ func (d Dir ) Chroot (path string ) (Dir , error ) {
22+ if _ , err := d .fs .Stat (path ); err != nil {
23+ return Dir {}, fmt .Errorf ("failed to chroot to %#v: %w" , path , err )
3124 }
32- return Dir {dot : d .dot , path : path .Join (d .path , name )}, nil
25+ fs := afero .NewBasePathFs (d .fs , path )
26+ return Dir {
27+ fs : fs ,
28+ log : d .log ,
29+ opened : d .opened ,
30+ }, nil
3331}
3432
35- // List reads and returns a slice of names from the given directory relative to
36- // the FS root.
37- func (d Dir ) List (name string ) ([]fs.DirEntry , error ) {
38- return fs .ReadDir (d .dot .fs , path .Join (d .path , path .Clean (name )))
33+ // ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.
34+ func (d Dir ) ReadDir (path string ) ([]fs.FileInfo , error ) {
35+ return afero .ReadDir (d .fs , path )
3936}
4037
4138// Exists returns true if filename can be opened successfully.
42- func (d Dir ) Exists (name string ) bool {
43- name = path .Join (d .path , path .Clean (name ))
44- file , err := d .Open (name )
45- if err == nil {
46- file .Close ()
47- return true
48- }
49- return false
39+ func (d Dir ) Exists (filename string ) bool {
40+ _ , err := d .fs .Stat (filename )
41+ return err == nil
5042}
5143
5244// Stat returns Stat of a filename.
5345//
5446// Note: if you intend to read the file, afterwards, calling .Open instead may
5547// be more efficient.
56- func (d Dir ) Stat (name string ) (fs.FileInfo , error ) {
57- name = path .Join (d .path , path .Clean (name ))
58- file , err := d .dot .fs .Open (name )
59- if err != nil {
60- return nil , err
61- }
62- defer file .Close ()
63- return file .Stat ()
48+ func (d Dir ) Stat (filename string ) (fs.FileInfo , error ) {
49+ return d .fs .Stat (filename )
6450}
6551
6652// Read returns the contents of a filename relative to the FS root as a string.
6753func (d Dir ) Read (name string ) (string , error ) {
68- name = path .Join (d .path , path .Clean (name ))
69-
7054 buf := bufPool .Get ().(* bytes.Buffer )
7155 buf .Reset ()
7256 defer bufPool .Put (buf )
57+ defer buf .Reset ()
7358
74- file , err := d .dot . fs .Open (name )
59+ file , err := d .fs .Open (name )
7560 if err != nil {
7661 return "" , err
7762 }
7863 defer file .Close ()
7964
65+ stat , err := file .Stat ()
66+ if err != nil {
67+ return "" , err
68+ }
69+ buf .Grow (int (stat .Size ()))
70+
8071 _ , err = io .Copy (buf , file )
8172 if err != nil {
8273 return "" , err
@@ -86,16 +77,14 @@ func (d Dir) Read(name string) (string, error) {
8677}
8778
8879// Open opens the file
89- func (d Dir ) Open (name string ) (fs.File , error ) {
90- name = path .Join (d .path , path .Clean (name ))
91-
92- file , err := d .dot .fs .Open (name )
80+ func (d Dir ) Open (filename string ) (afero.File , error ) {
81+ file , err := d .fs .Open (filename )
9382 if err != nil {
94- return nil , fmt .Errorf ("failed to open file at path '%s' : %w" , name , err )
83+ return nil , fmt .Errorf ("failed to open file at path %#v : %w" , filename , err )
9584 }
9685
97- d .dot . log .Debug ("opened file" , slog .String ("path " , name ))
98- d .dot . opened [file ] = struct {}{}
86+ d .log .Debug ("opened file" , slog .String ("filename " , filename ))
87+ d .opened [file ] = struct {}{}
9988
100- return d . dot . fs . Open ( name )
89+ return file , nil
10190}
0 commit comments