From b41fa6eb9dac3f912407ceeb90276753557f958f Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Tue, 27 Jul 2021 10:58:06 +0200 Subject: [PATCH] stdlib: add missing wrappers of io/fs for go1.16 Fixes #1195 --- interp/interp_eval_test.go | 79 ++++++++++++++++ stdlib/go1_16_io_fs.go | 188 +++++++++++++++++++++++++++++++++++++ stdlib/stdlib_go1.16.go | 2 +- 3 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 stdlib/go1_16_io_fs.go diff --git a/interp/interp_eval_test.go b/interp/interp_eval_test.go index cc04b0859..3ab053a78 100644 --- a/interp/interp_eval_test.go +++ b/interp/interp_eval_test.go @@ -12,6 +12,7 @@ import ( "os" "path/filepath" "reflect" + "runtime" "strconv" "strings" "sync" @@ -928,6 +929,84 @@ func TestMultiEvalNoName(t *testing.T) { } } +const goMinorVersionTest = 16 + +func TestHasIOFS(t *testing.T) { + code := ` +// +build go1.16 + +package main + +import ( + "errors" + "io/fs" +) + +func main() { + pe := fs.PathError{} + pe.Op = "nothing" + pe.Path = "/nowhere" + pe.Err = errors.New("an error") + println(pe.Error()) +} + +// Output: +// nothing /nowhere: an error +` + + var buf bytes.Buffer + i := interp.New(interp.Options{Stdout: &buf}) + if err := i.Use(interp.Symbols); err != nil { + t.Fatal(err) + } + if err := i.Use(stdlib.Symbols); err != nil { + t.Fatal(err) + } + + if _, err := i.Eval(code); err != nil { + t.Fatal(err) + } + + var expectedOutput string + var minor int + var err error + version := runtime.Version() + fields := strings.Fields(version) + // Go stable + if len(fields) == 1 { + v := strings.Split(version, ".") + if len(v) < 2 { + t.Fatalf("unexpected: %v", version) + } + minor, err = strconv.Atoi(v[1]) + if err != nil { + t.Fatal(err) + } + } else { + // Go devel + if fields[0] != "devel" { + t.Fatalf("unexpected: %v", fields[0]) + } + parts := strings.Split(fields[1], "-") + if len(parts) != 2 { + t.Fatalf("unexpected: %v", fields[1]) + } + minor, err = strconv.Atoi(strings.TrimPrefix(parts[0], "go1.")) + if err != nil { + t.Fatal(err) + } + } + + if minor >= goMinorVersionTest { + expectedOutput = "nothing /nowhere: an error\n" + } + + output := buf.String() + if buf.String() != expectedOutput { + t.Fatalf("got: %v, wanted: %v", output, expectedOutput) + } +} + func TestImportPathIsKey(t *testing.T) { // No need to check the results of Eval, as TestFile already does it. i := interp.New(interp.Options{GoPath: filepath.FromSlash("../_test/testdata/redeclaration-global7")}) diff --git a/stdlib/go1_16_io_fs.go b/stdlib/go1_16_io_fs.go new file mode 100644 index 000000000..86b3cafff --- /dev/null +++ b/stdlib/go1_16_io_fs.go @@ -0,0 +1,188 @@ +// Code generated by 'yaegi extract io/fs'. DO NOT EDIT. + +// +build go1.16 + +package stdlib + +import ( + "io/fs" + "reflect" + "time" +) + +func init() { + Symbols["io/fs/fs"] = map[string]reflect.Value{ + // function, constant and variable definitions + "ErrClosed": reflect.ValueOf(&fs.ErrClosed).Elem(), + "ErrExist": reflect.ValueOf(&fs.ErrExist).Elem(), + "ErrInvalid": reflect.ValueOf(&fs.ErrInvalid).Elem(), + "ErrNotExist": reflect.ValueOf(&fs.ErrNotExist).Elem(), + "ErrPermission": reflect.ValueOf(&fs.ErrPermission).Elem(), + "Glob": reflect.ValueOf(fs.Glob), + "ModeAppend": reflect.ValueOf(fs.ModeAppend), + "ModeCharDevice": reflect.ValueOf(fs.ModeCharDevice), + "ModeDevice": reflect.ValueOf(fs.ModeDevice), + "ModeDir": reflect.ValueOf(fs.ModeDir), + "ModeExclusive": reflect.ValueOf(fs.ModeExclusive), + "ModeIrregular": reflect.ValueOf(fs.ModeIrregular), + "ModeNamedPipe": reflect.ValueOf(fs.ModeNamedPipe), + "ModePerm": reflect.ValueOf(fs.ModePerm), + "ModeSetgid": reflect.ValueOf(fs.ModeSetgid), + "ModeSetuid": reflect.ValueOf(fs.ModeSetuid), + "ModeSocket": reflect.ValueOf(fs.ModeSocket), + "ModeSticky": reflect.ValueOf(fs.ModeSticky), + "ModeSymlink": reflect.ValueOf(fs.ModeSymlink), + "ModeTemporary": reflect.ValueOf(fs.ModeTemporary), + "ModeType": reflect.ValueOf(fs.ModeType), + "ReadDir": reflect.ValueOf(fs.ReadDir), + "ReadFile": reflect.ValueOf(fs.ReadFile), + "SkipDir": reflect.ValueOf(&fs.SkipDir).Elem(), + "Stat": reflect.ValueOf(fs.Stat), + "Sub": reflect.ValueOf(fs.Sub), + "ValidPath": reflect.ValueOf(fs.ValidPath), + "WalkDir": reflect.ValueOf(fs.WalkDir), + + // type definitions + "DirEntry": reflect.ValueOf((*fs.DirEntry)(nil)), + "FS": reflect.ValueOf((*fs.FS)(nil)), + "File": reflect.ValueOf((*fs.File)(nil)), + "FileInfo": reflect.ValueOf((*fs.FileInfo)(nil)), + "FileMode": reflect.ValueOf((*fs.FileMode)(nil)), + "GlobFS": reflect.ValueOf((*fs.GlobFS)(nil)), + "PathError": reflect.ValueOf((*fs.PathError)(nil)), + "ReadDirFS": reflect.ValueOf((*fs.ReadDirFS)(nil)), + "ReadDirFile": reflect.ValueOf((*fs.ReadDirFile)(nil)), + "ReadFileFS": reflect.ValueOf((*fs.ReadFileFS)(nil)), + "StatFS": reflect.ValueOf((*fs.StatFS)(nil)), + "SubFS": reflect.ValueOf((*fs.SubFS)(nil)), + "WalkDirFunc": reflect.ValueOf((*fs.WalkDirFunc)(nil)), + + // interface wrapper definitions + "_DirEntry": reflect.ValueOf((*_io_fs_DirEntry)(nil)), + "_FS": reflect.ValueOf((*_io_fs_FS)(nil)), + "_File": reflect.ValueOf((*_io_fs_File)(nil)), + "_FileInfo": reflect.ValueOf((*_io_fs_FileInfo)(nil)), + "_GlobFS": reflect.ValueOf((*_io_fs_GlobFS)(nil)), + "_ReadDirFS": reflect.ValueOf((*_io_fs_ReadDirFS)(nil)), + "_ReadDirFile": reflect.ValueOf((*_io_fs_ReadDirFile)(nil)), + "_ReadFileFS": reflect.ValueOf((*_io_fs_ReadFileFS)(nil)), + "_StatFS": reflect.ValueOf((*_io_fs_StatFS)(nil)), + "_SubFS": reflect.ValueOf((*_io_fs_SubFS)(nil)), + } +} + +// _io_fs_DirEntry is an interface wrapper for DirEntry type +type _io_fs_DirEntry struct { + IValue interface{} + WInfo func() (fs.FileInfo, error) + WIsDir func() bool + WName func() string + WType func() fs.FileMode +} + +func (W _io_fs_DirEntry) Info() (fs.FileInfo, error) { return W.WInfo() } +func (W _io_fs_DirEntry) IsDir() bool { return W.WIsDir() } +func (W _io_fs_DirEntry) Name() string { return W.WName() } +func (W _io_fs_DirEntry) Type() fs.FileMode { return W.WType() } + +// _io_fs_FS is an interface wrapper for FS type +type _io_fs_FS struct { + IValue interface{} + WOpen func(name string) (fs.File, error) +} + +func (W _io_fs_FS) Open(name string) (fs.File, error) { return W.WOpen(name) } + +// _io_fs_File is an interface wrapper for File type +type _io_fs_File struct { + IValue interface{} + WClose func() error + WRead func(a0 []byte) (int, error) + WStat func() (fs.FileInfo, error) +} + +func (W _io_fs_File) Close() error { return W.WClose() } +func (W _io_fs_File) Read(a0 []byte) (int, error) { return W.WRead(a0) } +func (W _io_fs_File) Stat() (fs.FileInfo, error) { return W.WStat() } + +// _io_fs_FileInfo is an interface wrapper for FileInfo type +type _io_fs_FileInfo struct { + IValue interface{} + WIsDir func() bool + WModTime func() time.Time + WMode func() fs.FileMode + WName func() string + WSize func() int64 + WSys func() interface{} +} + +func (W _io_fs_FileInfo) IsDir() bool { return W.WIsDir() } +func (W _io_fs_FileInfo) ModTime() time.Time { return W.WModTime() } +func (W _io_fs_FileInfo) Mode() fs.FileMode { return W.WMode() } +func (W _io_fs_FileInfo) Name() string { return W.WName() } +func (W _io_fs_FileInfo) Size() int64 { return W.WSize() } +func (W _io_fs_FileInfo) Sys() interface{} { return W.WSys() } + +// _io_fs_GlobFS is an interface wrapper for GlobFS type +type _io_fs_GlobFS struct { + IValue interface{} + WGlob func(pattern string) ([]string, error) + WOpen func(name string) (fs.File, error) +} + +func (W _io_fs_GlobFS) Glob(pattern string) ([]string, error) { return W.WGlob(pattern) } +func (W _io_fs_GlobFS) Open(name string) (fs.File, error) { return W.WOpen(name) } + +// _io_fs_ReadDirFS is an interface wrapper for ReadDirFS type +type _io_fs_ReadDirFS struct { + IValue interface{} + WOpen func(name string) (fs.File, error) + WReadDir func(name string) ([]fs.DirEntry, error) +} + +func (W _io_fs_ReadDirFS) Open(name string) (fs.File, error) { return W.WOpen(name) } +func (W _io_fs_ReadDirFS) ReadDir(name string) ([]fs.DirEntry, error) { return W.WReadDir(name) } + +// _io_fs_ReadDirFile is an interface wrapper for ReadDirFile type +type _io_fs_ReadDirFile struct { + IValue interface{} + WClose func() error + WRead func(a0 []byte) (int, error) + WReadDir func(n int) ([]fs.DirEntry, error) + WStat func() (fs.FileInfo, error) +} + +func (W _io_fs_ReadDirFile) Close() error { return W.WClose() } +func (W _io_fs_ReadDirFile) Read(a0 []byte) (int, error) { return W.WRead(a0) } +func (W _io_fs_ReadDirFile) ReadDir(n int) ([]fs.DirEntry, error) { return W.WReadDir(n) } +func (W _io_fs_ReadDirFile) Stat() (fs.FileInfo, error) { return W.WStat() } + +// _io_fs_ReadFileFS is an interface wrapper for ReadFileFS type +type _io_fs_ReadFileFS struct { + IValue interface{} + WOpen func(name string) (fs.File, error) + WReadFile func(name string) ([]byte, error) +} + +func (W _io_fs_ReadFileFS) Open(name string) (fs.File, error) { return W.WOpen(name) } +func (W _io_fs_ReadFileFS) ReadFile(name string) ([]byte, error) { return W.WReadFile(name) } + +// _io_fs_StatFS is an interface wrapper for StatFS type +type _io_fs_StatFS struct { + IValue interface{} + WOpen func(name string) (fs.File, error) + WStat func(name string) (fs.FileInfo, error) +} + +func (W _io_fs_StatFS) Open(name string) (fs.File, error) { return W.WOpen(name) } +func (W _io_fs_StatFS) Stat(name string) (fs.FileInfo, error) { return W.WStat(name) } + +// _io_fs_SubFS is an interface wrapper for SubFS type +type _io_fs_SubFS struct { + IValue interface{} + WOpen func(name string) (fs.File, error) + WSub func(dir string) (fs.FS, error) +} + +func (W _io_fs_SubFS) Open(name string) (fs.File, error) { return W.WOpen(name) } +func (W _io_fs_SubFS) Sub(dir string) (fs.FS, error) { return W.WSub(dir) } diff --git a/stdlib/stdlib_go1.16.go b/stdlib/stdlib_go1.16.go index 4f0e19a57..ab2416205 100644 --- a/stdlib/stdlib_go1.16.go +++ b/stdlib/stdlib_go1.16.go @@ -2,4 +2,4 @@ package stdlib -//go:generate ../internal/cmd/extract/extract embed testing/fstest +//go:generate ../internal/cmd/extract/extract embed io/fs testing/fstest