godoc: add a Corpus and Presentation type
Start of moving globals into those types. R=golang-dev, adg CC=golang-dev https://golang.org/cl/11484043
This commit is contained in:
parent
3af65e49c2
commit
4fc6323385
|
|
@ -62,7 +62,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
|
||||||
cw, err := loadCodewalk(abspath + ".xml")
|
cw, err := loadCodewalk(abspath + ".xml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
godoc.ServeError(w, r, relpath, err)
|
pres.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,7 +71,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
godoc.ServePage(w, godoc.Page{
|
pres.ServePage(w, godoc.Page{
|
||||||
Title: "Codewalk: " + cw.Title,
|
Title: "Codewalk: " + cw.Title,
|
||||||
Tabtitle: cw.Title,
|
Tabtitle: cw.Title,
|
||||||
Body: applyTemplate(codewalkHTML, "codewalk", cw),
|
Body: applyTemplate(codewalkHTML, "codewalk", cw),
|
||||||
|
|
@ -188,7 +188,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
|
||||||
dir, err := godoc.FS.ReadDir(abspath)
|
dir, err := godoc.FS.ReadDir(abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
godoc.ServeError(w, r, relpath, err)
|
pres.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var v []interface{}
|
var v []interface{}
|
||||||
|
|
@ -205,7 +205,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
godoc.ServePage(w, godoc.Page{
|
pres.ServePage(w, godoc.Page{
|
||||||
Title: "Codewalks",
|
Title: "Codewalks",
|
||||||
Body: applyTemplate(codewalkdirHTML, "codewalkdir", v),
|
Body: applyTemplate(codewalkdirHTML, "codewalkdir", v),
|
||||||
})
|
})
|
||||||
|
|
@ -222,7 +222,7 @@ func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
|
||||||
data, err := vfs.ReadFile(godoc.FS, abspath)
|
data, err := vfs.ReadFile(godoc.FS, abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
godoc.ServeError(w, r, f, err)
|
pres.ServeError(w, r, f, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lo, _ := strconv.Atoi(r.FormValue("lo"))
|
lo, _ := strconv.Atoi(r.FormValue("lo"))
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,12 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
htmlpkg "html"
|
htmlpkg "html"
|
||||||
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
pathpkg "path"
|
pathpkg "path"
|
||||||
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
|
@ -55,8 +51,7 @@ var (
|
||||||
|
|
||||||
// file system roots
|
// file system roots
|
||||||
// TODO(gri) consider the invariant that goroot always end in '/'
|
// TODO(gri) consider the invariant that goroot always end in '/'
|
||||||
goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
|
goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
|
||||||
testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
|
|
||||||
|
|
||||||
// layout control
|
// layout control
|
||||||
_ = flagInt(&godoc.TabWidth, "tabwidth", 4, "tab width")
|
_ = flagInt(&godoc.TabWidth, "tabwidth", 4, "tab width")
|
||||||
|
|
@ -67,8 +62,8 @@ var (
|
||||||
_ = flagBool(&godoc.DeclLinks, "links", true, "link identifiers to their declarations")
|
_ = flagBool(&godoc.DeclLinks, "links", true, "link identifiers to their declarations")
|
||||||
|
|
||||||
// search index
|
// search index
|
||||||
_ = flagBool(&godoc.IndexEnabled, "index", false, "enable search index")
|
indexEnabled = flag.Bool("index", false, "enable search index")
|
||||||
_ = flagString(&godoc.IndexFiles, "index_files", "", "glob pattern specifying index files;"+
|
indexFiles = flag.String("index_files", "", "glob pattern specifying index files;"+
|
||||||
"if not empty, the index is read from these files in sorted order")
|
"if not empty, the index is read from these files in sorted order")
|
||||||
_ = flagInt(&godoc.MaxResults, "maxresults", 10000, "maximum number of full text search results shown")
|
_ = flagInt(&godoc.MaxResults, "maxresults", 10000, "maximum number of full text search results shown")
|
||||||
_ = flagFloat64(&godoc.IndexThrottle, "index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle")
|
_ = flagFloat64(&godoc.IndexThrottle, "index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle")
|
||||||
|
|
@ -77,6 +72,8 @@ var (
|
||||||
_ = flagString(&godoc.NotesRx, "notes", "BUG", "regular expression matching note markers to show")
|
_ = flagString(&godoc.NotesRx, "notes", "BUG", "regular expression matching note markers to show")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var pres *godoc.Presentation
|
||||||
|
|
||||||
func registerPublicHandlers(mux *http.ServeMux) {
|
func registerPublicHandlers(mux *http.ServeMux) {
|
||||||
godoc.CmdHandler.RegisterWithMux(mux)
|
godoc.CmdHandler.RegisterWithMux(mux)
|
||||||
godoc.PkgHandler.RegisterWithMux(mux)
|
godoc.PkgHandler.RegisterWithMux(mux)
|
||||||
|
|
@ -88,16 +85,6 @@ func registerPublicHandlers(mux *http.ServeMux) {
|
||||||
mux.HandleFunc("/", serveFile)
|
mux.HandleFunc("/", serveFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initFSTree() {
|
|
||||||
dir := godoc.NewDirectory(pathpkg.Join("/", *testDir), -1)
|
|
||||||
if dir == nil {
|
|
||||||
log.Println("Warning: FSTree is nil")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
godoc.FSTree.Set(dir)
|
|
||||||
godoc.InvalidateIndex()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Templates
|
// Templates
|
||||||
|
|
||||||
|
|
@ -176,12 +163,12 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit
|
||||||
src, err := vfs.ReadFile(godoc.FS, abspath)
|
src, err := vfs.ReadFile(godoc.FS, abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ReadFile: %s", err)
|
log.Printf("ReadFile: %s", err)
|
||||||
godoc.ServeError(w, r, relpath, err)
|
pres.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.FormValue("m") == "text" {
|
if r.FormValue("m") == "text" {
|
||||||
godoc.ServeText(w, src)
|
pres.ServeText(w, src)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,7 +178,7 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit
|
||||||
buf.WriteString("</pre>")
|
buf.WriteString("</pre>")
|
||||||
fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
|
fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
|
||||||
|
|
||||||
godoc.ServePage(w, godoc.Page{
|
pres.ServePage(w, godoc.Page{
|
||||||
Title: title + " " + relpath,
|
Title: title + " " + relpath,
|
||||||
Tabtitle: relpath,
|
Tabtitle: relpath,
|
||||||
Body: buf.Bytes(),
|
Body: buf.Bytes(),
|
||||||
|
|
@ -205,11 +192,11 @@ func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath str
|
||||||
|
|
||||||
list, err := godoc.FS.ReadDir(abspath)
|
list, err := godoc.FS.ReadDir(abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
godoc.ServeError(w, r, relpath, err)
|
pres.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
godoc.ServePage(w, godoc.Page{
|
pres.ServePage(w, godoc.Page{
|
||||||
Title: "Directory " + relpath,
|
Title: "Directory " + relpath,
|
||||||
Tabtitle: relpath,
|
Tabtitle: relpath,
|
||||||
Body: applyTemplate(godoc.DirlistHTML, "dirlistHTML", list),
|
Body: applyTemplate(godoc.DirlistHTML, "dirlistHTML", list),
|
||||||
|
|
@ -241,7 +228,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
|
http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
godoc.ServeHTMLDoc(w, r, abspath, relpath)
|
pres.ServeHTMLDoc(w, r, abspath, relpath)
|
||||||
return
|
return
|
||||||
|
|
||||||
case ".go":
|
case ".go":
|
||||||
|
|
@ -252,7 +239,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
dir, err := godoc.FS.Lstat(abspath)
|
dir, err := godoc.FS.Lstat(abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
godoc.ServeError(w, r, relpath, err)
|
pres.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,7 +248,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if index := pathpkg.Join(abspath, "index.html"); util.IsTextFile(godoc.FS, index) {
|
if index := pathpkg.Join(abspath, "index.html"); util.IsTextFile(godoc.FS, index) {
|
||||||
godoc.ServeHTMLDoc(w, r, index, index)
|
pres.ServeHTMLDoc(w, r, index, index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
serveDirectory(w, r, abspath, relpath)
|
serveDirectory(w, r, abspath, relpath)
|
||||||
|
|
@ -362,7 +349,7 @@ func lookup(query string) (result SearchResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// is the result accurate?
|
// is the result accurate?
|
||||||
if godoc.IndexEnabled {
|
if pres.Corpus.IndexEnabled {
|
||||||
if _, ts := godoc.FSModified.Get(); timestamp.Before(ts) {
|
if _, ts := godoc.FSModified.Get(); timestamp.Before(ts) {
|
||||||
// The index is older than the latest file system change under godoc's observation.
|
// The index is older than the latest file system change under godoc's observation.
|
||||||
result.Alert = "Indexing in progress: result may be inaccurate"
|
result.Alert = "Indexing in progress: result may be inaccurate"
|
||||||
|
|
@ -379,7 +366,7 @@ func search(w http.ResponseWriter, r *http.Request) {
|
||||||
result := lookup(query)
|
result := lookup(query)
|
||||||
|
|
||||||
if godoc.GetPageInfoMode(r)&godoc.NoHTML != 0 {
|
if godoc.GetPageInfoMode(r)&godoc.NoHTML != 0 {
|
||||||
godoc.ServeText(w, applyTemplate(godoc.SearchText, "searchText", result))
|
pres.ServeText(w, applyTemplate(godoc.SearchText, "searchText", result))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,7 +377,7 @@ func search(w http.ResponseWriter, r *http.Request) {
|
||||||
title = fmt.Sprintf(`No results found for query %q`, query)
|
title = fmt.Sprintf(`No results found for query %q`, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
godoc.ServePage(w, godoc.Page{
|
pres.ServePage(w, godoc.Page{
|
||||||
Title: title,
|
Title: title,
|
||||||
Tabtitle: query,
|
Tabtitle: query,
|
||||||
Query: query,
|
Query: query,
|
||||||
|
|
|
||||||
|
|
@ -158,9 +158,8 @@ func main() {
|
||||||
usage()
|
usage()
|
||||||
}
|
}
|
||||||
|
|
||||||
if godoc.TabWidth < 0 {
|
fs := vfs.NameSpace{}
|
||||||
log.Fatalf("negative tabwidth %d", godoc.TabWidth)
|
godoc.FS = fs // temp hack
|
||||||
}
|
|
||||||
|
|
||||||
// Determine file system to use.
|
// Determine file system to use.
|
||||||
// TODO(gri) - fs and fsHttp should really be the same. Try to unify.
|
// TODO(gri) - fs and fsHttp should really be the same. Try to unify.
|
||||||
|
|
@ -168,9 +167,9 @@ func main() {
|
||||||
// same is true for the http handlers in initHandlers.
|
// same is true for the http handlers in initHandlers.
|
||||||
if *zipfile == "" {
|
if *zipfile == "" {
|
||||||
// use file system of underlying OS
|
// use file system of underlying OS
|
||||||
godoc.FS.Bind("/", vfs.OS(*goroot), "/", vfs.BindReplace)
|
fs.Bind("/", vfs.OS(*goroot), "/", vfs.BindReplace)
|
||||||
if *templateDir != "" {
|
if *templateDir != "" {
|
||||||
godoc.FS.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
|
fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// use file system specified via .zip file (path separator must be '/')
|
// use file system specified via .zip file (path separator must be '/')
|
||||||
|
|
@ -179,16 +178,23 @@ func main() {
|
||||||
log.Fatalf("%s: %s\n", *zipfile, err)
|
log.Fatalf("%s: %s\n", *zipfile, err)
|
||||||
}
|
}
|
||||||
defer rc.Close() // be nice (e.g., -writeIndex mode)
|
defer rc.Close() // be nice (e.g., -writeIndex mode)
|
||||||
godoc.FS.Bind("/", zipvfs.New(rc, *zipfile), *goroot, vfs.BindReplace)
|
fs.Bind("/", zipvfs.New(rc, *zipfile), *goroot, vfs.BindReplace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind $GOPATH trees into Go root.
|
// Bind $GOPATH trees into Go root.
|
||||||
for _, p := range filepath.SplitList(build.Default.GOPATH) {
|
for _, p := range filepath.SplitList(build.Default.GOPATH) {
|
||||||
godoc.FS.Bind("/src/pkg", vfs.OS(p), "/src", vfs.BindAfter)
|
fs.Bind("/src/pkg", vfs.OS(p), "/src", vfs.BindAfter)
|
||||||
}
|
}
|
||||||
|
|
||||||
readTemplates()
|
readTemplates()
|
||||||
godoc.InitHandlers(godoc.FS)
|
|
||||||
|
corpus := godoc.NewCorpus(fs)
|
||||||
|
corpus.IndexEnabled = *indexEnabled
|
||||||
|
corpus.IndexFiles = *indexFiles
|
||||||
|
|
||||||
|
pres = godoc.NewPresentation(corpus)
|
||||||
|
// ...
|
||||||
|
godoc.InitHandlers(pres)
|
||||||
|
|
||||||
if *writeIndex {
|
if *writeIndex {
|
||||||
// Write search index and exit.
|
// Write search index and exit.
|
||||||
|
|
@ -198,7 +204,6 @@ func main() {
|
||||||
|
|
||||||
log.Println("initialize file systems")
|
log.Println("initialize file systems")
|
||||||
*verbose = true // want to see what happens
|
*verbose = true // want to see what happens
|
||||||
initFSTree()
|
|
||||||
|
|
||||||
godoc.IndexThrottle = 1.0
|
godoc.IndexThrottle = 1.0
|
||||||
godoc.UpdateIndex()
|
godoc.UpdateIndex()
|
||||||
|
|
@ -221,8 +226,7 @@ func main() {
|
||||||
// Print content that would be served at the URL *urlFlag.
|
// Print content that would be served at the URL *urlFlag.
|
||||||
if *urlFlag != "" {
|
if *urlFlag != "" {
|
||||||
registerPublicHandlers(http.DefaultServeMux)
|
registerPublicHandlers(http.DefaultServeMux)
|
||||||
initFSTree()
|
|
||||||
godoc.UpdateMetadata()
|
|
||||||
// Try up to 10 fetches, following redirects.
|
// Try up to 10 fetches, following redirects.
|
||||||
urlstr := *urlFlag
|
urlstr := *urlFlag
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
|
|
@ -268,30 +272,21 @@ func main() {
|
||||||
log.Printf("goroot = %s", *goroot)
|
log.Printf("goroot = %s", *goroot)
|
||||||
log.Printf("tabwidth = %d", godoc.TabWidth)
|
log.Printf("tabwidth = %d", godoc.TabWidth)
|
||||||
switch {
|
switch {
|
||||||
case !godoc.IndexEnabled:
|
case !*indexEnabled:
|
||||||
log.Print("search index disabled")
|
log.Print("search index disabled")
|
||||||
case godoc.MaxResults > 0:
|
case godoc.MaxResults > 0:
|
||||||
log.Printf("full text index enabled (maxresults = %d)", godoc.MaxResults)
|
log.Printf("full text index enabled (maxresults = %d)", godoc.MaxResults)
|
||||||
default:
|
default:
|
||||||
log.Print("identifier search index enabled")
|
log.Print("identifier search index enabled")
|
||||||
}
|
}
|
||||||
godoc.FS.Fprint(os.Stderr)
|
fs.Fprint(os.Stderr)
|
||||||
handler = loggingHandler(handler)
|
handler = loggingHandler(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
registerPublicHandlers(http.DefaultServeMux)
|
registerPublicHandlers(http.DefaultServeMux)
|
||||||
|
|
||||||
// Initialize default directory tree with corresponding timestamp.
|
|
||||||
// (Do it in a goroutine so that launch is quick.)
|
|
||||||
go initFSTree()
|
|
||||||
|
|
||||||
// Immediately update metadata.
|
|
||||||
godoc.UpdateMetadata()
|
|
||||||
// Periodically refresh metadata.
|
|
||||||
go godoc.RefreshMetadataLoop()
|
|
||||||
|
|
||||||
// Initialize search index.
|
// Initialize search index.
|
||||||
if godoc.IndexEnabled {
|
if *indexEnabled {
|
||||||
go godoc.RunIndexer()
|
go godoc.RunIndexer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -335,18 +330,18 @@ func main() {
|
||||||
var forceCmd bool
|
var forceCmd bool
|
||||||
var abspath, relpath string
|
var abspath, relpath string
|
||||||
if filepath.IsAbs(path) {
|
if filepath.IsAbs(path) {
|
||||||
godoc.FS.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||||
abspath = target
|
abspath = target
|
||||||
} else if build.IsLocalImport(path) {
|
} else if build.IsLocalImport(path) {
|
||||||
cwd, _ := os.Getwd() // ignore errors
|
cwd, _ := os.Getwd() // ignore errors
|
||||||
path = filepath.Join(cwd, path)
|
path = filepath.Join(cwd, path)
|
||||||
godoc.FS.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||||
abspath = target
|
abspath = target
|
||||||
} else if strings.HasPrefix(path, cmdPrefix) {
|
} else if strings.HasPrefix(path, cmdPrefix) {
|
||||||
path = strings.TrimPrefix(path, cmdPrefix)
|
path = strings.TrimPrefix(path, cmdPrefix)
|
||||||
forceCmd = true
|
forceCmd = true
|
||||||
} else if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
|
} else if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
|
||||||
godoc.FS.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace)
|
fs.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace)
|
||||||
abspath = target
|
abspath = target
|
||||||
relpath = bp.ImportPath
|
relpath = bp.ImportPath
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// 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 godoc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
pathpkg "path"
|
||||||
|
|
||||||
|
"code.google.com/p/go.tools/godoc/util"
|
||||||
|
"code.google.com/p/go.tools/godoc/vfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Corpus holds all the state related to serving and indexing a
|
||||||
|
// collection of Go code.
|
||||||
|
//
|
||||||
|
// Construct a new Corpus with NewCorpus, then modify options,
|
||||||
|
// then call its Init method.
|
||||||
|
type Corpus struct {
|
||||||
|
fs vfs.FileSystem
|
||||||
|
|
||||||
|
// IndexEnabled controls whether indexing is enabled.
|
||||||
|
IndexEnabled bool
|
||||||
|
|
||||||
|
// IndexFiles specifies a glob pattern specifying index files.
|
||||||
|
// If not empty, the index is read from these files in sorted
|
||||||
|
// order.
|
||||||
|
IndexFiles string
|
||||||
|
|
||||||
|
IndexThrottle float64
|
||||||
|
|
||||||
|
// MaxResults optionally specifies the maximum results for indexing.
|
||||||
|
// The default is 1000.
|
||||||
|
MaxResults int
|
||||||
|
|
||||||
|
testDir string // TODO(bradfitz,adg): migrate old godoc flag? looks unused.
|
||||||
|
|
||||||
|
// Send a value on this channel to trigger a metadata refresh.
|
||||||
|
// It is buffered so that if a signal is not lost if sent
|
||||||
|
// during a refresh.
|
||||||
|
refreshMetadataSignal chan bool
|
||||||
|
|
||||||
|
// file system information
|
||||||
|
fsTree util.RWValue // *Directory tree of packages, updated with each sync (but sync code is removed now)
|
||||||
|
fsModified util.RWValue // timestamp of last call to invalidateIndex
|
||||||
|
docMetadata util.RWValue // mapping from paths to *Metadata
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCorpus returns a new Corpus from a filesystem.
|
||||||
|
// Set any options on Corpus before calling the Corpus.Init method.
|
||||||
|
func NewCorpus(fs vfs.FileSystem) *Corpus {
|
||||||
|
c := &Corpus{
|
||||||
|
fs: fs,
|
||||||
|
refreshMetadataSignal: make(chan bool, 1),
|
||||||
|
|
||||||
|
MaxResults: 1000,
|
||||||
|
IndexEnabled: true,
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes Corpus, once options on Corpus are set.
|
||||||
|
// It must be called before any subsequent method calls.
|
||||||
|
func (c *Corpus) Init() error {
|
||||||
|
// TODO(bradfitz): do this in a goroutine because newDirectory might block for a long time?
|
||||||
|
// It used to be sometimes done in a goroutine before, at least in HTTP server mode.
|
||||||
|
if err := c.initFSTree(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.updateMetadata()
|
||||||
|
go c.refreshMetadataLoop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Corpus) initFSTree() error {
|
||||||
|
dir := c.newDirectory(pathpkg.Join("/", c.testDir), -1)
|
||||||
|
if dir == nil {
|
||||||
|
return errors.New("godoc: corpus fstree is nil")
|
||||||
|
}
|
||||||
|
c.fsTree.Set(dir)
|
||||||
|
c.invalidateIndex()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -50,6 +50,7 @@ func isPkgDir(fi os.FileInfo) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type treeBuilder struct {
|
type treeBuilder struct {
|
||||||
|
c *Corpus
|
||||||
maxDepth int
|
maxDepth int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +70,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list, _ := FS.ReadDir(path)
|
list, _ := b.c.fs.ReadDir(path)
|
||||||
|
|
||||||
// determine number of subdirectories and if there are package files
|
// determine number of subdirectories and if there are package files
|
||||||
ndirs := 0
|
ndirs := 0
|
||||||
|
|
@ -161,9 +162,9 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
|
||||||
// are assumed to contain package files even if their contents are not known
|
// are assumed to contain package files even if their contents are not known
|
||||||
// (i.e., in this case the tree may contain directories w/o any package files).
|
// (i.e., in this case the tree may contain directories w/o any package files).
|
||||||
//
|
//
|
||||||
func NewDirectory(root string, maxDepth int) *Directory {
|
func (c *Corpus) newDirectory(root string, maxDepth int) *Directory {
|
||||||
// The root could be a symbolic link so use Stat not Lstat.
|
// The root could be a symbolic link so use Stat not Lstat.
|
||||||
d, err := FS.Stat(root)
|
d, err := c.fs.Stat(root)
|
||||||
// If we fail here, report detailed error messages; otherwise
|
// If we fail here, report detailed error messages; otherwise
|
||||||
// is is hard to see why a directory tree was not built.
|
// is is hard to see why a directory tree was not built.
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -177,7 +178,7 @@ func NewDirectory(root string, maxDepth int) *Directory {
|
||||||
if maxDepth < 0 {
|
if maxDepth < 0 {
|
||||||
maxDepth = 1e6 // "infinity"
|
maxDepth = 1e6 // "infinity"
|
||||||
}
|
}
|
||||||
b := treeBuilder{maxDepth}
|
b := treeBuilder{c, maxDepth}
|
||||||
// the file set provided is only for local parsing, no position
|
// the file set provided is only for local parsing, no position
|
||||||
// information escapes and thus we don't need to save the set
|
// information escapes and thus we don't need to save the set
|
||||||
return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
|
return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import (
|
||||||
// holds the source tree, and so on. This means that the URLs served by
|
// holds the source tree, and so on. This means that the URLs served by
|
||||||
// the godoc server are the same as the paths in the virtual file
|
// the godoc server are the same as the paths in the virtual file
|
||||||
// system, which helps keep things simple.
|
// system, which helps keep things simple.
|
||||||
|
// TODO(bradfitz): delete this global
|
||||||
var FS = vfs.NameSpace{}
|
var FS = vfs.NameSpace{}
|
||||||
|
|
||||||
// Old flags
|
// Old flags
|
||||||
|
|
@ -54,8 +55,6 @@ var (
|
||||||
// TODO(bradfitz,adg): delete this flag
|
// TODO(bradfitz,adg): delete this flag
|
||||||
ShowPlayground = false
|
ShowPlayground = false
|
||||||
|
|
||||||
IndexEnabled = false
|
|
||||||
|
|
||||||
ShowTimestamps = false
|
ShowTimestamps = false
|
||||||
|
|
||||||
Verbose = false
|
Verbose = false
|
||||||
|
|
|
||||||
|
|
@ -1038,9 +1038,9 @@ func (x *Index) LookupRegexp(r *regexp.Regexp, n int) (found int, result []FileL
|
||||||
|
|
||||||
// InvalidateIndex should be called whenever any of the file systems
|
// InvalidateIndex should be called whenever any of the file systems
|
||||||
// under godoc's observation change so that the indexer is kicked on.
|
// under godoc's observation change so that the indexer is kicked on.
|
||||||
func InvalidateIndex() {
|
func (c *Corpus) invalidateIndex() {
|
||||||
FSModified.Set(nil)
|
c.fsModified.Set(nil)
|
||||||
refreshMetadata()
|
c.refreshMetadata()
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexUpToDate() returns true if the search index is not older
|
// indexUpToDate() returns true if the search index is not older
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,11 @@ func extractMetadata(b []byte) (meta Metadata, tail []byte, err error) {
|
||||||
|
|
||||||
// UpdateMetadata scans $GOROOT/doc for HTML files, reads their metadata,
|
// UpdateMetadata scans $GOROOT/doc for HTML files, reads their metadata,
|
||||||
// and updates the DocMetadata map.
|
// and updates the DocMetadata map.
|
||||||
func UpdateMetadata() {
|
func (c *Corpus) updateMetadata() {
|
||||||
metadata := make(map[string]*Metadata)
|
metadata := make(map[string]*Metadata)
|
||||||
var scan func(string) // scan is recursive
|
var scan func(string) // scan is recursive
|
||||||
scan = func(dir string) {
|
scan = func(dir string) {
|
||||||
fis, err := FS.ReadDir(dir)
|
fis, err := c.fs.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("updateMetadata:", err)
|
log.Println("updateMetadata:", err)
|
||||||
return
|
return
|
||||||
|
|
@ -77,7 +77,7 @@ func UpdateMetadata() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Extract metadata from the file.
|
// Extract metadata from the file.
|
||||||
b, err := vfs.ReadFile(FS, name)
|
b, err := vfs.ReadFile(c.fs, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("updateMetadata %s: %v", name, err)
|
log.Printf("updateMetadata %s: %v", name, err)
|
||||||
continue
|
continue
|
||||||
|
|
@ -123,27 +123,22 @@ func MetadataFor(relpath string) *Metadata {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a value on this channel to trigger a metadata refresh.
|
|
||||||
// It is buffered so that if a signal is not lost if sent during a refresh.
|
|
||||||
//
|
|
||||||
var refreshMetadataSignal = make(chan bool, 1)
|
|
||||||
|
|
||||||
// refreshMetadata sends a signal to update DocMetadata. If a refresh is in
|
// refreshMetadata sends a signal to update DocMetadata. If a refresh is in
|
||||||
// progress the metadata will be refreshed again afterward.
|
// progress the metadata will be refreshed again afterward.
|
||||||
//
|
//
|
||||||
func refreshMetadata() {
|
func (c *Corpus) refreshMetadata() {
|
||||||
select {
|
select {
|
||||||
case refreshMetadataSignal <- true:
|
case c.refreshMetadataSignal <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshMetadataLoop runs forever, updating DocMetadata when the underlying
|
// RefreshMetadataLoop runs forever, updating DocMetadata when the underlying
|
||||||
// file system changes. It should be launched in a goroutine.
|
// file system changes. It should be launched in a goroutine.
|
||||||
func RefreshMetadataLoop() {
|
func (c *Corpus) refreshMetadataLoop() {
|
||||||
for {
|
for {
|
||||||
<-refreshMetadataSignal
|
<-c.refreshMetadataSignal
|
||||||
UpdateMetadata()
|
c.updateMetadata()
|
||||||
time.Sleep(10 * time.Second) // at most once every 10 seconds
|
time.Sleep(10 * time.Second) // at most once every 10 seconds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,11 @@ var (
|
||||||
SearchDescXML *template.Template
|
SearchDescXML *template.Template
|
||||||
)
|
)
|
||||||
|
|
||||||
func ServePage(w http.ResponseWriter, page Page) {
|
func (p *Presentation) ServePage(w http.ResponseWriter, page Page) {
|
||||||
if page.Tabtitle == "" {
|
if page.Tabtitle == "" {
|
||||||
page.Tabtitle = page.Title
|
page.Tabtitle = page.Title
|
||||||
}
|
}
|
||||||
page.SearchBox = IndexEnabled
|
page.SearchBox = p.Corpus.IndexEnabled
|
||||||
page.Playground = ShowPlayground
|
page.Playground = ShowPlayground
|
||||||
page.Version = runtime.Version()
|
page.Version = runtime.Version()
|
||||||
if err := GodocHTML.Execute(w, page); err != nil && err != http.ErrBodyNotAllowed {
|
if err := GodocHTML.Execute(w, page); err != nil && err != http.ErrBodyNotAllowed {
|
||||||
|
|
@ -51,9 +51,9 @@ func ServePage(w http.ResponseWriter, page Page) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServeError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
|
func (p *Presentation) ServeError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
ServePage(w, Page{
|
p.ServePage(w, Page{
|
||||||
Title: "File " + relpath,
|
Title: "File " + relpath,
|
||||||
Subtitle: relpath,
|
Subtitle: relpath,
|
||||||
Body: applyTemplate(ErrorHTML, "errorHTML", err), // err may contain an absolute path!
|
Body: applyTemplate(ErrorHTML, "errorHTML", err), // err may contain an absolute path!
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// 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 godoc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Presentation generates output from a corpus.
|
||||||
|
type Presentation struct {
|
||||||
|
Corpus *Corpus
|
||||||
|
|
||||||
|
// TabWidth optionally specifies the tab width.
|
||||||
|
TabWidth int
|
||||||
|
|
||||||
|
ShowTimestamps bool
|
||||||
|
ShowPlayground bool
|
||||||
|
ShowExamples bool
|
||||||
|
DeclLinks bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPresentation returns a new Presentation from a corpus.
|
||||||
|
func NewPresentation(c *Corpus) *Presentation {
|
||||||
|
if c == nil {
|
||||||
|
panic("nil Corpus")
|
||||||
|
}
|
||||||
|
return &Presentation{
|
||||||
|
Corpus: c,
|
||||||
|
TabWidth: 4,
|
||||||
|
ShowExamples: true,
|
||||||
|
DeclLinks: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Presentation) FuncMap() template.FuncMap {
|
||||||
|
panic("")
|
||||||
|
}
|
||||||
|
|
@ -42,16 +42,19 @@ var (
|
||||||
DocMetadata util.RWValue // mapping from paths to *Metadata
|
DocMetadata util.RWValue // mapping from paths to *Metadata
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitHandlers(fs vfs.FileSystem) {
|
func InitHandlers(p *Presentation) {
|
||||||
FileServer = http.FileServer(httpfs.New(fs))
|
c := p.Corpus
|
||||||
CmdHandler = Server{"/cmd/", "/src/cmd"}
|
FileServer = http.FileServer(httpfs.New(c.fs))
|
||||||
PkgHandler = Server{"/pkg/", "/src/pkg"}
|
CmdHandler = Server{p, c, "/cmd/", "/src/cmd"}
|
||||||
|
PkgHandler = Server{p, c, "/pkg/", "/src/pkg"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server is a godoc server.
|
// Server is a godoc server.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
pattern string // url pattern; e.g. "/pkg/"
|
p *Presentation
|
||||||
fsRoot string // file system root to which the pattern is mapped
|
c *Corpus // copy of p.Corpus
|
||||||
|
pattern string // url pattern; e.g. "/pkg/"
|
||||||
|
fsRoot string // file system root to which the pattern is mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) FSRoot() string { return s.fsRoot }
|
func (s *Server) FSRoot() string { return s.fsRoot }
|
||||||
|
|
@ -178,7 +181,7 @@ func (h *Server) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageIn
|
||||||
// command-line mode); compute one level for this page
|
// command-line mode); compute one level for this page
|
||||||
// note: cannot use path filter here because in general
|
// note: cannot use path filter here because in general
|
||||||
// it doesn't contain the FSTree path
|
// it doesn't contain the FSTree path
|
||||||
dir = NewDirectory(abspath, 1)
|
dir = h.c.newDirectory(abspath, 1)
|
||||||
timestamp = time.Now()
|
timestamp = time.Now()
|
||||||
}
|
}
|
||||||
info.Dirs = dir.listing(true)
|
info.Dirs = dir.listing(true)
|
||||||
|
|
@ -202,12 +205,12 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
info := h.GetPageInfo(abspath, relpath, mode)
|
info := h.GetPageInfo(abspath, relpath, mode)
|
||||||
if info.Err != nil {
|
if info.Err != nil {
|
||||||
log.Print(info.Err)
|
log.Print(info.Err)
|
||||||
ServeError(w, r, relpath, info.Err)
|
h.p.ServeError(w, r, relpath, info.Err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&NoHTML != 0 {
|
if mode&NoHTML != 0 {
|
||||||
ServeText(w, applyTemplate(PackageText, "packageText", info))
|
h.p.ServeText(w, applyTemplate(PackageText, "packageText", info))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,7 +246,7 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
tabtitle = "Commands"
|
tabtitle = "Commands"
|
||||||
}
|
}
|
||||||
|
|
||||||
ServePage(w, Page{
|
h.p.ServePage(w, Page{
|
||||||
Title: title,
|
Title: title,
|
||||||
Tabtitle: tabtitle,
|
Tabtitle: tabtitle,
|
||||||
Subtitle: subtitle,
|
Subtitle: subtitle,
|
||||||
|
|
@ -431,16 +434,16 @@ func redirectFile(w http.ResponseWriter, r *http.Request) (redirected bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
|
func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
|
||||||
src, err := vfs.ReadFile(FS, abspath)
|
src, err := vfs.ReadFile(p.Corpus.fs, abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ReadFile: %s", err)
|
log.Printf("ReadFile: %s", err)
|
||||||
ServeError(w, r, relpath, err)
|
p.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.FormValue("m") == "text" {
|
if r.FormValue("m") == "text" {
|
||||||
ServeText(w, src)
|
p.ServeText(w, src)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,37 +453,37 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit
|
||||||
buf.WriteString("</pre>")
|
buf.WriteString("</pre>")
|
||||||
fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
|
fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
|
||||||
|
|
||||||
ServePage(w, Page{
|
p.ServePage(w, Page{
|
||||||
Title: title + " " + relpath,
|
Title: title + " " + relpath,
|
||||||
Tabtitle: relpath,
|
Tabtitle: relpath,
|
||||||
Body: buf.Bytes(),
|
Body: buf.Bytes(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
|
func (p *Presentation) serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
|
||||||
if redirect(w, r) {
|
if redirect(w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := FS.ReadDir(abspath)
|
list, err := FS.ReadDir(abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ServeError(w, r, relpath, err)
|
p.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ServePage(w, Page{
|
p.ServePage(w, Page{
|
||||||
Title: "Directory " + relpath,
|
Title: "Directory " + relpath,
|
||||||
Tabtitle: relpath,
|
Tabtitle: relpath,
|
||||||
Body: applyTemplate(DirlistHTML, "dirlistHTML", list),
|
Body: applyTemplate(DirlistHTML, "dirlistHTML", list),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
|
func (p *Presentation) ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
|
||||||
// get HTML body contents
|
// get HTML body contents
|
||||||
src, err := vfs.ReadFile(FS, abspath)
|
src, err := vfs.ReadFile(FS, abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ReadFile: %s", err)
|
log.Printf("ReadFile: %s", err)
|
||||||
ServeError(w, r, relpath, err)
|
p.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,13 +505,13 @@ func ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
|
||||||
tmpl, err := template.New("main").Funcs(TemplateFuncs).Parse(string(src))
|
tmpl, err := template.New("main").Funcs(TemplateFuncs).Parse(string(src))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("parsing template %s: %v", relpath, err)
|
log.Printf("parsing template %s: %v", relpath, err)
|
||||||
ServeError(w, r, relpath, err)
|
p.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := tmpl.Execute(&buf, nil); err != nil {
|
if err := tmpl.Execute(&buf, nil); err != nil {
|
||||||
log.Printf("executing template %s: %v", relpath, err)
|
log.Printf("executing template %s: %v", relpath, err)
|
||||||
ServeError(w, r, relpath, err)
|
p.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
src = buf.Bytes()
|
src = buf.Bytes()
|
||||||
|
|
@ -521,14 +524,14 @@ func ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
|
||||||
src = buf.Bytes()
|
src = buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
ServePage(w, Page{
|
p.ServePage(w, Page{
|
||||||
Title: meta.Title,
|
Title: meta.Title,
|
||||||
Subtitle: meta.Subtitle,
|
Subtitle: meta.Subtitle,
|
||||||
Body: src,
|
Body: src,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveFile(w http.ResponseWriter, r *http.Request) {
|
func (p *Presentation) serveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
relpath := r.URL.Path
|
relpath := r.URL.Path
|
||||||
|
|
||||||
// Check to see if we need to redirect or serve another file.
|
// Check to see if we need to redirect or serve another file.
|
||||||
|
|
@ -553,18 +556,18 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
|
http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ServeHTMLDoc(w, r, abspath, relpath)
|
p.ServeHTMLDoc(w, r, abspath, relpath)
|
||||||
return
|
return
|
||||||
|
|
||||||
case ".go":
|
case ".go":
|
||||||
serveTextFile(w, r, abspath, relpath, "Source file")
|
p.serveTextFile(w, r, abspath, relpath, "Source file")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, err := FS.Lstat(abspath)
|
dir, err := FS.Lstat(abspath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
ServeError(w, r, relpath, err)
|
p.ServeError(w, r, relpath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -573,10 +576,10 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if index := pathpkg.Join(abspath, "index.html"); util.IsTextFile(FS, index) {
|
if index := pathpkg.Join(abspath, "index.html"); util.IsTextFile(FS, index) {
|
||||||
ServeHTMLDoc(w, r, index, index)
|
p.ServeHTMLDoc(w, r, index, index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
serveDirectory(w, r, abspath, relpath)
|
p.serveDirectory(w, r, abspath, relpath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,7 +587,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
if redirectFile(w, r) {
|
if redirectFile(w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
serveTextFile(w, r, abspath, relpath, "Text file")
|
p.serveTextFile(w, r, abspath, relpath, "Text file")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -603,7 +606,7 @@ func serveSearchDesc(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServeText(w http.ResponseWriter, text []byte) {
|
func (p *Presentation) ServeText(w http.ResponseWriter, text []byte) {
|
||||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
w.Write(text)
|
w.Write(text)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue