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 }