From 123adc86bcb6c2a95bc058e93df2f247c11a9629 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Feb 2021 14:28:42 -0500 Subject: [PATCH] godoc/vfs: add io/fs adapter Change-Id: Iaeea108ce2803d3ee1ece5d2d67fbe353576fbd7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/291669 gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Trust: Russ Cox Run-TryBot: Russ Cox --- godoc/vfs/fs.go | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 godoc/vfs/fs.go diff --git a/godoc/vfs/fs.go b/godoc/vfs/fs.go new file mode 100644 index 000000000..b0336665e --- /dev/null +++ b/godoc/vfs/fs.go @@ -0,0 +1,79 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.16 + +package vfs + +import ( + "io/fs" + "os" + "path" + "strings" +) + +// FromFS converts an fs.FS to the FileSystem interface. +func FromFS(fsys fs.FS) FileSystem { + return &fsysToFileSystem{fsys} +} + +type fsysToFileSystem struct { + fsys fs.FS +} + +func (f *fsysToFileSystem) fsPath(name string) string { + name = path.Clean(name) + if name == "/" { + return "." + } + return strings.TrimPrefix(name, "/") +} + +func (f *fsysToFileSystem) Open(name string) (ReadSeekCloser, error) { + file, err := f.fsys.Open(f.fsPath(name)) + if err != nil { + return nil, err + } + if rsc, ok := file.(ReadSeekCloser); ok { + return rsc, nil + } + return &noSeekFile{f.fsPath(name), file}, nil +} + +func (f *fsysToFileSystem) Lstat(name string) (os.FileInfo, error) { + return fs.Stat(f.fsys, f.fsPath(name)) +} + +func (f *fsysToFileSystem) Stat(name string) (os.FileInfo, error) { + return fs.Stat(f.fsys, f.fsPath(name)) +} + +func (f *fsysToFileSystem) RootType(name string) RootType { return "" } + +func (f *fsysToFileSystem) ReadDir(name string) ([]os.FileInfo, error) { + dirs, err := fs.ReadDir(f.fsys, f.fsPath(name)) + var infos []os.FileInfo + for _, d := range dirs { + info, err1 := d.Info() + if err1 != nil { + if err == nil { + err = err1 + } + continue + } + infos = append(infos, info) + } + return infos, err +} + +func (f *fsysToFileSystem) String() string { return "io/fs" } + +type noSeekFile struct { + path string + fs.File +} + +func (f *noSeekFile) Seek(offset int64, whence int) (int64, error) { + return 0, &fs.PathError{Op: "seek", Path: f.path, Err: fs.ErrInvalid} +}