1
0
mirror of https://github.com/golang/go synced 2024-10-01 11:38:34 -06:00
go/godoc/vfs/mapfs/mapfs.go
Agniva De Sarker 16d1af8d88 godoc: group package home page list by root
This CL groups the package list into two groups - standard library(GOROOT),
and third-party code(GOPATH).

It also wraps the list with a collapsible div header used in the package
documentation page. This makes the entire page easy to view and manage, and also
makes it consistent with the rest of the pages.

To implement this, a new function was added to the filesystem interface
which returns the root type of the filesystem. In most cases, it is either GOROOT
or GOPATH. There are other kinds of filesystems which are not used in the home page,
so additional values have been added to satisfy the interface.

A side effect of this is that the html template code has become a bit spaghetti-like
with if conditions all over. This is because the same template is used to render
a package directory as well as the package home page. A better way is to use
two separate templates for the different tasks. This cleans out a lot of the
if conditions and make for a much cleaner code. This has been taken care in CL 101295.

Fixes golang/go#3305
Fixes golang/go#15020

Change-Id: I876357dc76280a7df2ed08d7c6bc53d9a41e69ab
Reviewed-on: https://go-review.googlesource.com/95835
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2018-04-10 16:41:40 +00:00

160 lines
3.4 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 "golang.org/x/tools/godoc/vfs/mapfs"
import (
"io"
"os"
pathpkg "path"
"sort"
"strings"
"time"
"golang.org/x/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" }
// RootType directly returns vfs.RootTypeAsset because
// mapFs is only used to return static assets and not for
// resolving Go files.
func (fs mapFS) RootType(p string) vfs.RootType {
return vfs.RootTypeAsset
}
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 }