mirror of
https://github.com/golang/go
synced 2024-11-18 09:04:49 -07:00
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>
This commit is contained in:
parent
5dfd8930f2
commit
16d1af8d88
@ -16,6 +16,8 @@ import (
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
)
|
||||
|
||||
// Conventional name for directories containing test data.
|
||||
@ -24,12 +26,13 @@ import (
|
||||
const testdataDirName = "testdata"
|
||||
|
||||
type Directory struct {
|
||||
Depth int
|
||||
Path string // directory path; includes Name
|
||||
Name string // directory name
|
||||
HasPkg bool // true if the directory contains at least one package
|
||||
Synopsis string // package documentation, if any
|
||||
Dirs []*Directory // subdirectories
|
||||
Depth int
|
||||
Path string // directory path; includes Name
|
||||
Name string // directory name
|
||||
HasPkg bool // true if the directory contains at least one package
|
||||
Synopsis string // package documentation, if any
|
||||
FsRootType string // string representation of vfs.RootType
|
||||
Dirs []*Directory // subdirectories
|
||||
}
|
||||
|
||||
func isGoFile(fi os.FileInfo) bool {
|
||||
@ -195,12 +198,13 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
|
||||
}
|
||||
|
||||
return &Directory{
|
||||
Depth: depth,
|
||||
Path: path,
|
||||
Name: name,
|
||||
HasPkg: hasPkgFiles && show, // TODO(bradfitz): add proper Hide field?
|
||||
Synopsis: synopsis,
|
||||
Dirs: dirs,
|
||||
Depth: depth,
|
||||
Path: path,
|
||||
Name: name,
|
||||
HasPkg: hasPkgFiles && show, // TODO(bradfitz): add proper Hide field?
|
||||
Synopsis: synopsis,
|
||||
FsRootType: string(b.c.fs.RootType(path)),
|
||||
Dirs: dirs,
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,12 +302,13 @@ func (dir *Directory) lookup(path string) *Directory {
|
||||
// are useful for presenting an entry in an indented fashion.
|
||||
//
|
||||
type DirEntry struct {
|
||||
Depth int // >= 0
|
||||
Height int // = DirList.MaxHeight - Depth, > 0
|
||||
Path string // directory path; includes Name, relative to DirList root
|
||||
Name string // directory name
|
||||
HasPkg bool // true if the directory contains at least one package
|
||||
Synopsis string // package documentation, if any
|
||||
Depth int // >= 0
|
||||
Height int // = DirList.MaxHeight - Depth, > 0
|
||||
Path string // directory path; includes Name, relative to DirList root
|
||||
Name string // directory name
|
||||
HasPkg bool // true if the directory contains at least one package
|
||||
Synopsis string // package documentation, if any
|
||||
FsRootType string // string representation of vfs.RootType
|
||||
}
|
||||
|
||||
type DirList struct {
|
||||
@ -311,6 +316,17 @@ type DirList struct {
|
||||
List []DirEntry
|
||||
}
|
||||
|
||||
// hasThirdParty checks whether a list of directory entries has packages outside
|
||||
// the standard library or not.
|
||||
func hasThirdParty(list []DirEntry) bool {
|
||||
for _, entry := range list {
|
||||
if entry.FsRootType == string(vfs.RootTypeGoPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// listing creates a (linear) directory listing from a directory tree.
|
||||
// If skipRoot is set, the root directory itself is excluded from the list.
|
||||
// If filter is set, only the directory entries whose paths match the filter
|
||||
@ -359,6 +375,7 @@ func (root *Directory) listing(skipRoot bool, filter func(string) bool) *DirList
|
||||
p.Name = d.Name
|
||||
p.HasPkg = d.HasPkg
|
||||
p.Synopsis = d.Synopsis
|
||||
p.FsRootType = d.FsRootType
|
||||
list = append(list, p)
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,9 @@ func (p *Presentation) initFuncMap() {
|
||||
|
||||
// formatting of PageInfoMode query string
|
||||
"modeQueryString": modeQueryString,
|
||||
|
||||
// check whether to display third party section or not
|
||||
"hasThirdParty": hasThirdParty,
|
||||
}
|
||||
if p.URLForSrc != nil {
|
||||
p.funcMap["srcLink"] = p.URLForSrc
|
||||
|
@ -249,59 +249,124 @@
|
||||
<div id="manual-nav">
|
||||
<dl>
|
||||
<dt><a href="#stdlib">Standard library</a></dt>
|
||||
{{if hasThirdParty .List }}
|
||||
<dt><a href="#thirdparty">Third party</a></dt>
|
||||
{{end}}
|
||||
<dt><a href="#other">Other packages</a></dt>
|
||||
<dd><a href="#subrepo">Sub-repositories</a></dd>
|
||||
<dd><a href="#community">Community</a></dd>
|
||||
</dl>
|
||||
</div>
|
||||
<h2 id="stdlib">Standard library</h2>
|
||||
<img alt="" class="gopher" src="/doc/gopher/pkg.png"/>
|
||||
|
||||
<div id="stdlib" class="toggleVisible">
|
||||
<div class="collapsed">
|
||||
<h2 class="toggleButton" title="Click to show Standard library section">Standard library ▹</h2>
|
||||
</div>
|
||||
<div class="expanded">
|
||||
<h2 class="toggleButton" title="Click to hide Standard library section">Standard library ▾</h2>
|
||||
<img alt="" class="gopher" src="/doc/gopher/pkg.png"/>
|
||||
{{end}}
|
||||
<div class="pkg-dir">
|
||||
<table>
|
||||
<tr>
|
||||
<th class="pkg-name">Name</th>
|
||||
<th class="pkg-synopsis">Synopsis</th>
|
||||
</tr>
|
||||
|
||||
{{if not (or (eq $.Dirname "/src") (eq $.Dirname "/src/cmd") $.DirFlat)}}
|
||||
<tr>
|
||||
<td colspan="2"><a href="..">..</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
<div class="pkg-dir">
|
||||
<table>
|
||||
<tr>
|
||||
<th class="pkg-name">Name</th>
|
||||
<th class="pkg-synopsis">Synopsis</th>
|
||||
</tr>
|
||||
|
||||
{{if not (or (eq $.Dirname "/src") (eq $.Dirname "/src/cmd") $.DirFlat)}}
|
||||
<tr>
|
||||
<td colspan="2"><a href="..">..</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
{{range .List}}
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
{{if eq $.Dirname "/src"}}
|
||||
{{range .List}}
|
||||
<tr>
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
{{if eq .FsRootType "GOROOT"}}
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
{{end}}
|
||||
</tr>
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{range .List}}
|
||||
<tr>
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<tr>
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
{{if eq $.Dirname "/src"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if hasThirdParty .List }}
|
||||
<div id="thirdparty" class="toggleVisible">
|
||||
<div class="collapsed">
|
||||
<h2 class="toggleButton" title="Click to show Third party section">Third party ▹</h2>
|
||||
</div>
|
||||
<div class="expanded">
|
||||
<h2 class="toggleButton" title="Click to hide Third party section">Third party ▾</h2>
|
||||
<div class="pkg-dir">
|
||||
<table>
|
||||
<tr>
|
||||
<th class="pkg-name">Name</th>
|
||||
<th class="pkg-synopsis">Synopsis</th>
|
||||
</tr>
|
||||
|
||||
{{range .List}}
|
||||
<tr>
|
||||
{{if eq .FsRootType "GOPATH"}}
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
{{end}}
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if eq $.Dirname "/src"}}
|
||||
<h2 id="other">Other packages</h2>
|
||||
|
||||
<h3 id="subrepo">Sub-repositories</h3>
|
||||
<p>
|
||||
These packages are part of the Go Project but outside the main Go tree.
|
||||
|
@ -1869,59 +1869,124 @@ function cgAddChild(tree, ul, cgn) {
|
||||
<div id="manual-nav">
|
||||
<dl>
|
||||
<dt><a href="#stdlib">Standard library</a></dt>
|
||||
{{if hasThirdParty .List }}
|
||||
<dt><a href="#thirdparty">Third party</a></dt>
|
||||
{{end}}
|
||||
<dt><a href="#other">Other packages</a></dt>
|
||||
<dd><a href="#subrepo">Sub-repositories</a></dd>
|
||||
<dd><a href="#community">Community</a></dd>
|
||||
</dl>
|
||||
</div>
|
||||
<h2 id="stdlib">Standard library</h2>
|
||||
<img alt="" class="gopher" src="/doc/gopher/pkg.png"/>
|
||||
|
||||
<div id="stdlib" class="toggleVisible">
|
||||
<div class="collapsed">
|
||||
<h2 class="toggleButton" title="Click to show Standard library section">Standard library ▹</h2>
|
||||
</div>
|
||||
<div class="expanded">
|
||||
<h2 class="toggleButton" title="Click to hide Standard library section">Standard library ▾</h2>
|
||||
<img alt="" class="gopher" src="/doc/gopher/pkg.png"/>
|
||||
{{end}}
|
||||
<div class="pkg-dir">
|
||||
<table>
|
||||
<tr>
|
||||
<th class="pkg-name">Name</th>
|
||||
<th class="pkg-synopsis">Synopsis</th>
|
||||
</tr>
|
||||
|
||||
{{if not (or (eq $.Dirname "/src") (eq $.Dirname "/src/cmd") $.DirFlat)}}
|
||||
<tr>
|
||||
<td colspan="2"><a href="..">..</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
<div class="pkg-dir">
|
||||
<table>
|
||||
<tr>
|
||||
<th class="pkg-name">Name</th>
|
||||
<th class="pkg-synopsis">Synopsis</th>
|
||||
</tr>
|
||||
|
||||
{{if not (or (eq $.Dirname "/src") (eq $.Dirname "/src/cmd") $.DirFlat)}}
|
||||
<tr>
|
||||
<td colspan="2"><a href="..">..</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
{{range .List}}
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
{{if eq $.Dirname "/src"}}
|
||||
{{range .List}}
|
||||
<tr>
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
{{if eq .FsRootType "GOROOT"}}
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
{{end}}
|
||||
</tr>
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{range .List}}
|
||||
<tr>
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<tr>
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
{{if eq $.Dirname "/src"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if hasThirdParty .List }}
|
||||
<div id="thirdparty" class="toggleVisible">
|
||||
<div class="collapsed">
|
||||
<h2 class="toggleButton" title="Click to show Third party section">Third party ▹</h2>
|
||||
</div>
|
||||
<div class="expanded">
|
||||
<h2 class="toggleButton" title="Click to hide Third party section">Third party ▾</h2>
|
||||
<div class="pkg-dir">
|
||||
<table>
|
||||
<tr>
|
||||
<th class="pkg-name">Name</th>
|
||||
<th class="pkg-synopsis">Synopsis</th>
|
||||
</tr>
|
||||
|
||||
{{range .List}}
|
||||
<tr>
|
||||
{{if eq .FsRootType "GOPATH"}}
|
||||
{{if $.DirFlat}}
|
||||
{{if .HasPkg}}
|
||||
<td class="pkg-name">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
|
||||
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
|
||||
</td>
|
||||
{{end}}
|
||||
<td class="pkg-synopsis">
|
||||
{{html .Synopsis}}
|
||||
</td>
|
||||
{{end}}
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if eq $.Dirname "/src"}}
|
||||
<h2 id="other">Other packages</h2>
|
||||
|
||||
<h3 id="subrepo">Sub-repositories</h3>
|
||||
<p>
|
||||
These packages are part of the Go Project but outside the main Go tree.
|
||||
|
@ -57,6 +57,10 @@ func (e *emptyVFS) String() string {
|
||||
return "emptyVFS(/)"
|
||||
}
|
||||
|
||||
func (e *emptyVFS) RootType(path string) RootType {
|
||||
return RootTypeStandAlone
|
||||
}
|
||||
|
||||
// These functions below implement os.FileInfo for the single
|
||||
// empty emulated directory.
|
||||
|
||||
|
@ -37,6 +37,10 @@ func (fs gatefs) String() string {
|
||||
return fmt.Sprintf("gated(%s, %d)", fs.fs.String(), cap(fs.gate))
|
||||
}
|
||||
|
||||
func (fs gatefs) RootType(path string) vfs.RootType {
|
||||
return fs.fs.RootType(path)
|
||||
}
|
||||
|
||||
func (fs gatefs) Open(p string) (vfs.ReadSeekCloser, error) {
|
||||
fs.enter()
|
||||
defer fs.leave()
|
||||
|
39
godoc/vfs/gatefs/gatefs_test.go
Normal file
39
godoc/vfs/gatefs/gatefs_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2018 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 gatefs_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
"golang.org/x/tools/godoc/vfs/gatefs"
|
||||
)
|
||||
|
||||
func TestRootType(t *testing.T) {
|
||||
goPath := os.Getenv("GOPATH")
|
||||
var expectedType vfs.RootType
|
||||
if goPath == "" {
|
||||
expectedType = vfs.RootTypeStandAlone
|
||||
} else {
|
||||
expectedType = vfs.RootTypeGoPath
|
||||
}
|
||||
tests := []struct {
|
||||
path string
|
||||
fsType vfs.RootType
|
||||
}{
|
||||
{runtime.GOROOT(), vfs.RootTypeGoRoot},
|
||||
{goPath, expectedType},
|
||||
{"/tmp/", vfs.RootTypeStandAlone},
|
||||
}
|
||||
|
||||
for _, item := range tests {
|
||||
fs := gatefs.New(vfs.OS(item.path), make(chan bool, 1))
|
||||
if fs.RootType("path") != item.fsType {
|
||||
t.Errorf("unexpected fsType. Expected- %v, Got- %v", item.fsType, fs.RootType("path"))
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,13 @@ 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 {
|
||||
|
@ -381,6 +381,20 @@ func (ns NameSpace) ReadDir(path string) ([]os.FileInfo, error) {
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// RootType returns the RootType for the given path in the namespace.
|
||||
func (ns NameSpace) RootType(path string) RootType {
|
||||
// We resolve the given path to a list of mountedFS and then return
|
||||
// the root type for the filesystem which contains the path.
|
||||
for _, m := range ns.resolve(path) {
|
||||
_, err := m.fs.ReadDir(m.translate(path))
|
||||
// Found a match, return the filesystem's root type
|
||||
if err == nil {
|
||||
return m.fs.RootType(path)
|
||||
}
|
||||
}
|
||||
return RootTypeStandAlone
|
||||
}
|
||||
|
||||
// byName implements sort.Interface.
|
||||
type byName []os.FileInfo
|
||||
|
||||
|
@ -6,10 +6,12 @@ package vfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// OS returns an implementation of FileSystem reading from the
|
||||
@ -18,12 +20,44 @@ import (
|
||||
// passed to Open has no way to specify a drive letter. Using a root
|
||||
// lets code refer to OS(`c:\`), OS(`d:\`) and so on.
|
||||
func OS(root string) FileSystem {
|
||||
return osFS(root)
|
||||
var t RootType
|
||||
switch {
|
||||
case root == runtime.GOROOT():
|
||||
t = RootTypeGoRoot
|
||||
case isGoPath(root):
|
||||
t = RootTypeGoPath
|
||||
default:
|
||||
t = RootTypeStandAlone
|
||||
}
|
||||
return osFS{rootPath: root, rootType: t}
|
||||
}
|
||||
|
||||
type osFS string
|
||||
type osFS struct {
|
||||
rootPath string
|
||||
rootType RootType
|
||||
}
|
||||
|
||||
func (root osFS) String() string { return "os(" + string(root) + ")" }
|
||||
func isGoPath(path string) bool {
|
||||
for _, bp := range filepath.SplitList(build.Default.GOPATH) {
|
||||
for _, gp := range filepath.SplitList(path) {
|
||||
if bp == gp {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (root osFS) String() string { return "os(" + root.rootPath + ")" }
|
||||
|
||||
// RootType returns the root type for the filesystem.
|
||||
//
|
||||
// Note that we ignore the path argument because roottype is a property of
|
||||
// this filesystem. But for other filesystems, the roottype might need to be
|
||||
// dynamically deduced at call time.
|
||||
func (root osFS) RootType(path string) RootType {
|
||||
return root.rootType
|
||||
}
|
||||
|
||||
func (root osFS) resolve(path string) string {
|
||||
// Clean the path so that it cannot possibly begin with ../.
|
||||
@ -32,7 +66,7 @@ func (root osFS) resolve(path string) string {
|
||||
// with .. in it, but be safe anyway.
|
||||
path = pathpkg.Clean("/" + path)
|
||||
|
||||
return filepath.Join(string(root), path)
|
||||
return filepath.Join(root.rootPath, path)
|
||||
}
|
||||
|
||||
func (root osFS) Open(path string) (ReadSeekCloser, error) {
|
||||
|
38
godoc/vfs/os_test.go
Normal file
38
godoc/vfs/os_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2018 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 vfs_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
)
|
||||
|
||||
func TestRootType(t *testing.T) {
|
||||
goPath := os.Getenv("GOPATH")
|
||||
var expectedType vfs.RootType
|
||||
if goPath == "" {
|
||||
expectedType = vfs.RootTypeStandAlone
|
||||
} else {
|
||||
expectedType = vfs.RootTypeGoPath
|
||||
}
|
||||
tests := []struct {
|
||||
path string
|
||||
fsType vfs.RootType
|
||||
}{
|
||||
{runtime.GOROOT(), vfs.RootTypeGoRoot},
|
||||
{goPath, expectedType},
|
||||
{"/tmp/", vfs.RootTypeStandAlone},
|
||||
}
|
||||
|
||||
for _, item := range tests {
|
||||
fs := vfs.OS(item.path)
|
||||
if fs.RootType("path") != item.fsType {
|
||||
t.Errorf("unexpected fsType. Expected- %v, Got- %v", item.fsType, fs.RootType("path"))
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,18 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// RootType indicates the type of files contained within a directory.
|
||||
//
|
||||
// The two main types are a GOROOT or a GOPATH directory.
|
||||
type RootType string
|
||||
|
||||
const (
|
||||
RootTypeGoRoot RootType = "GOROOT"
|
||||
RootTypeGoPath RootType = "GOPATH"
|
||||
RootTypeStandAlone RootType = "StandAlone" // used by emptyvfs
|
||||
RootTypeAsset RootType = "Assets" // serves static assets using mapfs
|
||||
)
|
||||
|
||||
// The FileSystem interface specifies the methods godoc is using
|
||||
// to access the file system for which it serves documentation.
|
||||
type FileSystem interface {
|
||||
@ -19,6 +31,7 @@ type FileSystem interface {
|
||||
Lstat(path string) (os.FileInfo, error)
|
||||
Stat(path string) (os.FileInfo, error)
|
||||
ReadDir(path string) ([]os.FileInfo, error)
|
||||
RootType(path string) RootType
|
||||
String() string
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,12 @@ package zipfs // import "golang.org/x/tools/godoc/vfs/zipfs"
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -81,6 +84,28 @@ func (fs *zipFS) String() string {
|
||||
return "zip(" + fs.name + ")"
|
||||
}
|
||||
|
||||
func (fs *zipFS) RootType(abspath string) vfs.RootType {
|
||||
var t vfs.RootType
|
||||
switch {
|
||||
case abspath == runtime.GOROOT():
|
||||
t = vfs.RootTypeGoRoot
|
||||
case isGoPath(abspath):
|
||||
t = vfs.RootTypeGoPath
|
||||
default:
|
||||
t = vfs.RootTypeStandAlone
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func isGoPath(path string) bool {
|
||||
for _, p := range filepath.SplitList(build.Default.GOPATH) {
|
||||
if p == path {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (fs *zipFS) Close() error {
|
||||
fs.list = nil
|
||||
return fs.ReadCloser.Close()
|
||||
|
Loading…
Reference in New Issue
Block a user