github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/godoc/vfs/mapfs/mapfs.go (about) 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. 4 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" 8 9 import ( 10 "io" 11 "os" 12 pathpkg "path" 13 "sort" 14 "strings" 15 "time" 16 17 "golang.org/x/tools/godoc/vfs" 18 ) 19 20 // New returns a new FileSystem from the provided map. 21 // Map keys should be forward slash-separated pathnames 22 // and not contain a leading slash. 23 func New(m map[string]string) vfs.FileSystem { 24 return mapFS(m) 25 } 26 27 // mapFS is the map based implementation of FileSystem 28 type mapFS map[string]string 29 30 func (fs mapFS) String() string { return "mapfs" } 31 32 func (fs mapFS) Close() error { return nil } 33 34 func filename(p string) string { 35 return strings.TrimPrefix(p, "/") 36 } 37 38 func (fs mapFS) Open(p string) (vfs.ReadSeekCloser, error) { 39 b, ok := fs[filename(p)] 40 if !ok { 41 return nil, os.ErrNotExist 42 } 43 return nopCloser{strings.NewReader(b)}, nil 44 } 45 46 func fileInfo(name, contents string) os.FileInfo { 47 return mapFI{name: pathpkg.Base(name), size: len(contents)} 48 } 49 50 func dirInfo(name string) os.FileInfo { 51 return mapFI{name: pathpkg.Base(name), dir: true} 52 } 53 54 func (fs mapFS) Lstat(p string) (os.FileInfo, error) { 55 b, ok := fs[filename(p)] 56 if ok { 57 return fileInfo(p, b), nil 58 } 59 ents, _ := fs.ReadDir(p) 60 if len(ents) > 0 { 61 return dirInfo(p), nil 62 } 63 return nil, os.ErrNotExist 64 } 65 66 func (fs mapFS) Stat(p string) (os.FileInfo, error) { 67 return fs.Lstat(p) 68 } 69 70 // slashdir returns path.Dir(p), but special-cases paths not beginning 71 // with a slash to be in the root. 72 func slashdir(p string) string { 73 d := pathpkg.Dir(p) 74 if d == "." { 75 return "/" 76 } 77 if strings.HasPrefix(p, "/") { 78 return d 79 } 80 return "/" + d 81 } 82 83 func (fs mapFS) ReadDir(p string) ([]os.FileInfo, error) { 84 p = pathpkg.Clean(p) 85 var ents []string 86 fim := make(map[string]os.FileInfo) // base -> fi 87 for fn, b := range fs { 88 dir := slashdir(fn) 89 isFile := true 90 var lastBase string 91 for { 92 if dir == p { 93 base := lastBase 94 if isFile { 95 base = pathpkg.Base(fn) 96 } 97 if fim[base] == nil { 98 var fi os.FileInfo 99 if isFile { 100 fi = fileInfo(fn, b) 101 } else { 102 fi = dirInfo(base) 103 } 104 ents = append(ents, base) 105 fim[base] = fi 106 } 107 } 108 if dir == "/" { 109 break 110 } else { 111 isFile = false 112 lastBase = pathpkg.Base(dir) 113 dir = pathpkg.Dir(dir) 114 } 115 } 116 } 117 if len(ents) == 0 { 118 return nil, os.ErrNotExist 119 } 120 121 sort.Strings(ents) 122 var list []os.FileInfo 123 for _, dir := range ents { 124 list = append(list, fim[dir]) 125 } 126 return list, nil 127 } 128 129 // mapFI is the map-based implementation of FileInfo. 130 type mapFI struct { 131 name string 132 size int 133 dir bool 134 } 135 136 func (fi mapFI) IsDir() bool { return fi.dir } 137 func (fi mapFI) ModTime() time.Time { return time.Time{} } 138 func (fi mapFI) Mode() os.FileMode { 139 if fi.IsDir() { 140 return 0755 | os.ModeDir 141 } 142 return 0444 143 } 144 func (fi mapFI) Name() string { return pathpkg.Base(fi.name) } 145 func (fi mapFI) Size() int64 { return int64(fi.size) } 146 func (fi mapFI) Sys() interface{} { return nil } 147 148 type nopCloser struct { 149 io.ReadSeeker 150 } 151 152 func (nc nopCloser) Close() error { return nil }