C2FO / vfs

Pluggable, extensible virtual file system for Go

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Update vfs to implement io/fs's fs.FS interface

funkyshu opened this issue · comments

Is your feature request related to a problem? Please describe.
Implement https://pkg.go.dev/io/fs#FS should consist of adding the following func

Open(name string) (File, error)

which returns a File:

type File interface {
	Stat() (FileInfo, error)
	Read([]byte) (int, error)
	Close() error
}

where Stat() can return a FileInfo:

type FileInfo interface {
	Name() string       // base name of the file
	Size() int64        // length in bytes for regular files; system-dependent for others
	Mode() FileMode     // file mode bits
	ModTime() time.Time // modification time
	IsDir() bool        // abbreviation for Mode().IsDir()
	Sys() any           // underlying data source (can return nil)
}

Describe the solution you'd like
I think it makes the most sense to:

  • add Stat() (FileInfo, error) to the vfs.File interface
  • add Open(name string) (File, error) to the Location interface.

The implementation of Open could simply be:

func (loc *Location) Open(name string) (fs.File, error){
	return loc.NewFile(name)
}

The the overall usage would be like:

osfs := os.NewFilesystem()

// setup location
loc, _ := osfs.NewLocation("c:", "/some/path/")

// use fs.FS func
file, _ := Open("somefile.txt")

// use fs.File func
fileinfo, _ := file.Stat()

fmt.Printf("name: '%s' size: %d", fileinfo.Name(), fileinfo.Size())			// name: 'somefile.txt' size: 123
fmt.Printf("name: '%s' size: %d", file.(*os.File).Name(), file.(*os.File).Size())	// name: 'somefile.txt' size: 123

or for S3:

s3fs := s3.NewFilesystem()        
s3fs= s3fs.(*s3.Filesystem).WithOptions(
            s3.Options{
                AccessKeyID:     "AKIAIOSFODNN7EXAMPLE",
                SecretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
                Region:          "us-west-2",
                ACL:             "bucket-owner-full-control",
            },
        )

// setup location
loc, _ := s3fs.NewLocation("myBucket", "/some/path/")

// use fs.FS func
file, _ := Open("somefile.txt")

// use fs.File func
fileinfo, _ := file.Stat()

fmt.Printf("name: '%s' size: %d", fileinfo.Name(), fileinfo.Size())			// name: 'somefile.txt' size: 123
fmt.Printf("name: '%s' size: %d", file.(*s3.File).Name(), file.(*s3.File).Size())	// name: 'somefile.txt' size: 123

Alternatively:

We could make vfs.Filesystem implement fs.FS so that you specify a the schema-less portion of the uri (authority + path) with Open(). Then both vfs.Location and vfs.File would implement fs.File.

osfs := os.NewFileSystem()

// open a dir
loc, _ := osfs.Open("c:/some/path/)
fileinfo,_ := loc.Stat()
fmt.Printf("name: '%s'", fileinfo.Name())		// name: 'path'
fmt.Printf("name: '%s'", loc.(*os.Location).Name())	// name: 'path'

// open a file
file, _ := osfs.Open("c:/some/path/to/file.txt")
fileinfo,_ := file.Stat()
fmt.Printf("name: '%s'", fileinfo.Name())		// name: 'file.txt'
fmt.Printf("name: '%s'", file.(*os.File).Name())	// name: 'file.txt'

or for s3:

s3fs := s3.NewFileSystem()
s3fs = s3fs.(*s3.Filiesystem).WithOptions(
            s3.Options{
                AccessKeyID:     "AKIAIOSFODNN7EXAMPLE",
                SecretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
                Region:          "us-west-2",
                ACL:             "bucket-owner-full-control",
            },
        )

// open a dir
loc, _ := s3fs.Open("myBucket/some/path/)
fileinfo,_ := loc.Stat()
fmt.Printf("name: '%s'", loc.Name())			// name: 'path'
fmt.Printf("name: '%s'", loc.(*s3.Location).Name())	// name: 'path'

// open a file
file, _ := s3fs.Open("myBucket/some/path/to/file.txt")
fileinfo,_ := file.Stat()
fmt.Printf("name: '%s'", fileinfo.Name())		// name: 'file.txt'
fmt.Printf("name: '%s'", file.(*s3.File).Name())	// name: 'file.txt'