1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package mapfs file provides an implementation of the FileSystem
6 // interface based on the contents of a map[string]string.
7 package mapfs // import "golang.org/x/tools/godoc/vfs/mapfs"
18 "golang.org/x/tools/godoc/vfs"
21 // New returns a new FileSystem from the provided map.
22 // Map keys must be forward slash-separated paths with
23 // no leading slash, such as "file1.txt" or "dir/file2.txt".
24 // New panics if any of the paths contain a leading slash.
25 func New(m map[string]string) vfs.FileSystem {
26 // Verify all provided paths are relative before proceeding.
27 var pathsWithLeadingSlash []string
29 if strings.HasPrefix(p, "/") {
30 pathsWithLeadingSlash = append(pathsWithLeadingSlash, p)
33 if len(pathsWithLeadingSlash) > 0 {
34 panic(fmt.Errorf("mapfs.New: invalid paths with a leading slash: %q", pathsWithLeadingSlash))
40 // mapFS is the map based implementation of FileSystem
41 type mapFS map[string]string
43 func (fs mapFS) String() string { return "mapfs" }
45 func (fs mapFS) RootType(p string) vfs.RootType {
49 func (fs mapFS) Close() error { return nil }
51 func filename(p string) string {
52 return strings.TrimPrefix(p, "/")
55 func (fs mapFS) Open(p string) (vfs.ReadSeekCloser, error) {
56 b, ok := fs[filename(p)]
58 return nil, os.ErrNotExist
60 return nopCloser{strings.NewReader(b)}, nil
63 func fileInfo(name, contents string) os.FileInfo {
64 return mapFI{name: pathpkg.Base(name), size: len(contents)}
67 func dirInfo(name string) os.FileInfo {
68 return mapFI{name: pathpkg.Base(name), dir: true}
71 func (fs mapFS) Lstat(p string) (os.FileInfo, error) {
72 b, ok := fs[filename(p)]
74 return fileInfo(p, b), nil
76 ents, _ := fs.ReadDir(p)
78 return dirInfo(p), nil
80 return nil, os.ErrNotExist
83 func (fs mapFS) Stat(p string) (os.FileInfo, error) {
87 // slashdir returns path.Dir(p), but special-cases paths not beginning
88 // with a slash to be in the root.
89 func slashdir(p string) string {
94 if strings.HasPrefix(p, "/") {
100 func (fs mapFS) ReadDir(p string) ([]os.FileInfo, error) {
103 fim := make(map[string]os.FileInfo) // base -> fi
104 for fn, b := range fs {
112 base = pathpkg.Base(fn)
114 if fim[base] == nil {
121 ents = append(ents, base)
129 lastBase = pathpkg.Base(dir)
130 dir = pathpkg.Dir(dir)
135 return nil, os.ErrNotExist
139 var list []os.FileInfo
140 for _, dir := range ents {
141 list = append(list, fim[dir])
146 // mapFI is the map-based implementation of FileInfo.
153 func (fi mapFI) IsDir() bool { return fi.dir }
154 func (fi mapFI) ModTime() time.Time { return time.Time{} }
155 func (fi mapFI) Mode() os.FileMode {
157 return 0755 | os.ModeDir
161 func (fi mapFI) Name() string { return pathpkg.Base(fi.name) }
162 func (fi mapFI) Size() int64 { return int64(fi.size) }
163 func (fi mapFI) Sys() interface{} { return nil }
165 type nopCloser struct {
169 func (nc nopCloser) Close() error { return nil }