1
0
mirror of https://github.com/golang/go synced 2024-10-01 13:08:32 -06:00
go/godoc/vfs/mapfs/mapfs.go
Brad Fitzpatrick 964f0f559c godoc: feed indexer concurrently, add selective indexing hook, tests
On big corpuses, the indexer was spending most of its time waiting
for filesystem operations (especially with network filesystems)
and not actually indexing.  This keeps the filesystem busy and indexer
running in different goroutines.

Also, add a hook to let godoc hosts disable indexing of certain
directories.

And finally, start adding tests for godoc, which required
fleshing out (and testing) the mapfs code.

R=golang-dev, adg, bgarcia
CC=golang-dev
https://golang.org/cl/21520045
2013-11-05 09:35:58 -05:00

153 lines
3.2 KiB
Go

// Copyright 2013 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.
// Package mapfs file provides an implementation of the FileSystem
// interface based on the contents of a map[string]string.
package mapfs
import (
"io"
"os"
pathpkg "path"
"sort"
"strings"
"time"
"code.google.com/p/go.tools/godoc/vfs"
)
// New returns a new FileSystem from the provided map.
// Map keys should be forward slash-separated pathnames
// and not contain a leading slash.
func New(m map[string]string) vfs.FileSystem {
return mapFS(m)
}
// mapFS is the map based implementation of FileSystem
type mapFS map[string]string
func (fs mapFS) String() string { return "mapfs" }
func (fs mapFS) Close() error { return nil }
func filename(p string) string {
return strings.TrimPrefix(p, "/")
}
func (fs mapFS) Open(p string) (vfs.ReadSeekCloser, error) {
b, ok := fs[filename(p)]
if !ok {
return nil, os.ErrNotExist
}
return nopCloser{strings.NewReader(b)}, nil
}
func fileInfo(name, contents string) os.FileInfo {
return mapFI{name: pathpkg.Base(name), size: len(contents)}
}
func dirInfo(name string) os.FileInfo {
return mapFI{name: pathpkg.Base(name), dir: true}
}
func (fs mapFS) Lstat(p string) (os.FileInfo, error) {
b, ok := fs[filename(p)]
if ok {
return fileInfo(p, b), nil
}
ents, _ := fs.ReadDir(p)
if len(ents) > 0 {
return dirInfo(p), nil
}
return nil, os.ErrNotExist
}
func (fs mapFS) Stat(p string) (os.FileInfo, error) {
return fs.Lstat(p)
}
// slashdir returns path.Dir(p), but special-cases paths not beginning
// with a slash to be in the root.
func slashdir(p string) string {
d := pathpkg.Dir(p)
if d == "." {
return "/"
}
if strings.HasPrefix(p, "/") {
return d
}
return "/" + d
}
func (fs mapFS) ReadDir(p string) ([]os.FileInfo, error) {
p = pathpkg.Clean(p)
var ents []string
fim := make(map[string]os.FileInfo) // base -> fi
for fn, b := range fs {
dir := slashdir(fn)
isFile := true
var lastBase string
for {
if dir == p {
base := lastBase
if isFile {
base = pathpkg.Base(fn)
}
if fim[base] == nil {
var fi os.FileInfo
if isFile {
fi = fileInfo(fn, b)
} else {
fi = dirInfo(base)
}
ents = append(ents, base)
fim[base] = fi
}
}
if dir == "/" {
break
} else {
isFile = false
lastBase = pathpkg.Base(dir)
dir = pathpkg.Dir(dir)
}
}
}
if len(ents) == 0 {
return nil, os.ErrNotExist
}
sort.Strings(ents)
var list []os.FileInfo
for _, dir := range ents {
list = append(list, fim[dir])
}
return list, nil
}
// mapFI is the map-based implementation of FileInfo.
type mapFI struct {
name string
size int
dir bool
}
func (fi mapFI) IsDir() bool { return fi.dir }
func (fi mapFI) ModTime() time.Time { return time.Time{} }
func (fi mapFI) Mode() os.FileMode {
if fi.IsDir() {
return 0755 | os.ModeDir
}
return 0444
}
func (fi mapFI) Name() string { return pathpkg.Base(fi.name) }
func (fi mapFI) Size() int64 { return int64(fi.size) }
func (fi mapFI) Sys() interface{} { return nil }
type nopCloser struct {
io.ReadSeeker
}
func (nc nopCloser) Close() error { return nil }