diff --git a/cmd/godoc/codewalk.go b/cmd/godoc/codewalk.go index c62e0be4..8b151b46 100644 --- a/cmd/godoc/codewalk.go +++ b/cmd/godoc/codewalk.go @@ -62,7 +62,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) { cw, err := loadCodewalk(abspath + ".xml") if err != nil { log.Print(err) - godoc.ServeError(w, r, relpath, err) + pres.ServeError(w, r, relpath, err) return } @@ -71,7 +71,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) { return } - godoc.ServePage(w, godoc.Page{ + pres.ServePage(w, godoc.Page{ Title: "Codewalk: " + cw.Title, Tabtitle: cw.Title, 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) if err != nil { log.Print(err) - godoc.ServeError(w, r, relpath, err) + pres.ServeError(w, r, relpath, err) return } 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", 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) if err != nil { log.Print(err) - godoc.ServeError(w, r, f, err) + pres.ServeError(w, r, f, err) return } lo, _ := strconv.Atoi(r.FormValue("lo")) diff --git a/cmd/godoc/godoc.go b/cmd/godoc/godoc.go index ce6377b0..fa550553 100644 --- a/cmd/godoc/godoc.go +++ b/cmd/godoc/godoc.go @@ -9,16 +9,12 @@ import ( "flag" "fmt" htmlpkg "html" - "log" "net/http" "net/url" - pathpkg "path" - "regexp" "runtime" - "strings" "text/template" @@ -55,8 +51,7 @@ var ( // file system roots // TODO(gri) consider the invariant that goroot always end in '/' - goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory") - testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)") + goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory") // layout control _ = flagInt(&godoc.TabWidth, "tabwidth", 4, "tab width") @@ -67,8 +62,8 @@ var ( _ = flagBool(&godoc.DeclLinks, "links", true, "link identifiers to their declarations") // search index - _ = flagBool(&godoc.IndexEnabled, "index", false, "enable search index") - _ = flagString(&godoc.IndexFiles, "index_files", "", "glob pattern specifying index files;"+ + indexEnabled = flag.Bool("index", false, "enable search index") + indexFiles = flag.String("index_files", "", "glob pattern specifying index files;"+ "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") _ = 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") ) +var pres *godoc.Presentation + func registerPublicHandlers(mux *http.ServeMux) { godoc.CmdHandler.RegisterWithMux(mux) godoc.PkgHandler.RegisterWithMux(mux) @@ -88,16 +85,6 @@ func registerPublicHandlers(mux *http.ServeMux) { 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 @@ -176,12 +163,12 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit src, err := vfs.ReadFile(godoc.FS, abspath) if err != nil { log.Printf("ReadFile: %s", err) - godoc.ServeError(w, r, relpath, err) + pres.ServeError(w, r, relpath, err) return } if r.FormValue("m") == "text" { - godoc.ServeText(w, src) + pres.ServeText(w, src) return } @@ -191,7 +178,7 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit buf.WriteString("") fmt.Fprintf(&buf, `

View as plain text

`, htmlpkg.EscapeString(relpath)) - godoc.ServePage(w, godoc.Page{ + pres.ServePage(w, godoc.Page{ Title: title + " " + relpath, Tabtitle: relpath, Body: buf.Bytes(), @@ -205,11 +192,11 @@ func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath str list, err := godoc.FS.ReadDir(abspath) if err != nil { - godoc.ServeError(w, r, relpath, err) + pres.ServeError(w, r, relpath, err) return } - godoc.ServePage(w, godoc.Page{ + pres.ServePage(w, godoc.Page{ Title: "Directory " + relpath, Tabtitle: relpath, 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) return } - godoc.ServeHTMLDoc(w, r, abspath, relpath) + pres.ServeHTMLDoc(w, r, abspath, relpath) return case ".go": @@ -252,7 +239,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) { dir, err := godoc.FS.Lstat(abspath) if err != nil { log.Print(err) - godoc.ServeError(w, r, relpath, err) + pres.ServeError(w, r, relpath, err) return } @@ -261,7 +248,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) { return } 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 } serveDirectory(w, r, abspath, relpath) @@ -362,7 +349,7 @@ func lookup(query string) (result SearchResult) { } // is the result accurate? - if godoc.IndexEnabled { + if pres.Corpus.IndexEnabled { if _, ts := godoc.FSModified.Get(); timestamp.Before(ts) { // The index is older than the latest file system change under godoc's observation. result.Alert = "Indexing in progress: result may be inaccurate" @@ -379,7 +366,7 @@ func search(w http.ResponseWriter, r *http.Request) { result := lookup(query) if godoc.GetPageInfoMode(r)&godoc.NoHTML != 0 { - godoc.ServeText(w, applyTemplate(godoc.SearchText, "searchText", result)) + pres.ServeText(w, applyTemplate(godoc.SearchText, "searchText", result)) return } @@ -390,7 +377,7 @@ func search(w http.ResponseWriter, r *http.Request) { title = fmt.Sprintf(`No results found for query %q`, query) } - godoc.ServePage(w, godoc.Page{ + pres.ServePage(w, godoc.Page{ Title: title, Tabtitle: query, Query: query, diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go index fa6dda36..22be2df4 100644 --- a/cmd/godoc/main.go +++ b/cmd/godoc/main.go @@ -158,9 +158,8 @@ func main() { usage() } - if godoc.TabWidth < 0 { - log.Fatalf("negative tabwidth %d", godoc.TabWidth) - } + fs := vfs.NameSpace{} + godoc.FS = fs // temp hack // Determine file system to use. // 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. if *zipfile == "" { // use file system of underlying OS - godoc.FS.Bind("/", vfs.OS(*goroot), "/", vfs.BindReplace) + fs.Bind("/", vfs.OS(*goroot), "/", vfs.BindReplace) if *templateDir != "" { - godoc.FS.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore) + fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore) } } else { // use file system specified via .zip file (path separator must be '/') @@ -179,16 +178,23 @@ func main() { log.Fatalf("%s: %s\n", *zipfile, err) } 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. 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() - godoc.InitHandlers(godoc.FS) + + corpus := godoc.NewCorpus(fs) + corpus.IndexEnabled = *indexEnabled + corpus.IndexFiles = *indexFiles + + pres = godoc.NewPresentation(corpus) + // ... + godoc.InitHandlers(pres) if *writeIndex { // Write search index and exit. @@ -198,7 +204,6 @@ func main() { log.Println("initialize file systems") *verbose = true // want to see what happens - initFSTree() godoc.IndexThrottle = 1.0 godoc.UpdateIndex() @@ -221,8 +226,7 @@ func main() { // Print content that would be served at the URL *urlFlag. if *urlFlag != "" { registerPublicHandlers(http.DefaultServeMux) - initFSTree() - godoc.UpdateMetadata() + // Try up to 10 fetches, following redirects. urlstr := *urlFlag for i := 0; i < 10; i++ { @@ -268,30 +272,21 @@ func main() { log.Printf("goroot = %s", *goroot) log.Printf("tabwidth = %d", godoc.TabWidth) switch { - case !godoc.IndexEnabled: + case !*indexEnabled: log.Print("search index disabled") case godoc.MaxResults > 0: log.Printf("full text index enabled (maxresults = %d)", godoc.MaxResults) default: log.Print("identifier search index enabled") } - godoc.FS.Fprint(os.Stderr) + fs.Fprint(os.Stderr) handler = loggingHandler(handler) } 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. - if godoc.IndexEnabled { + if *indexEnabled { go godoc.RunIndexer() } @@ -335,18 +330,18 @@ func main() { var forceCmd bool var abspath, relpath string if filepath.IsAbs(path) { - godoc.FS.Bind(target, vfs.OS(path), "/", vfs.BindReplace) + fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace) abspath = target } else if build.IsLocalImport(path) { cwd, _ := os.Getwd() // ignore errors path = filepath.Join(cwd, path) - godoc.FS.Bind(target, vfs.OS(path), "/", vfs.BindReplace) + fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace) abspath = target } else if strings.HasPrefix(path, cmdPrefix) { path = strings.TrimPrefix(path, cmdPrefix) forceCmd = true } 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 relpath = bp.ImportPath } else { diff --git a/godoc/corpus.go b/godoc/corpus.go new file mode 100644 index 00000000..87d33bd9 --- /dev/null +++ b/godoc/corpus.go @@ -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 +} diff --git a/godoc/dirtrees.go b/godoc/dirtrees.go index ce423d9d..edf36b82 100644 --- a/godoc/dirtrees.go +++ b/godoc/dirtrees.go @@ -50,6 +50,7 @@ func isPkgDir(fi os.FileInfo) bool { } type treeBuilder struct { + c *Corpus 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 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 // (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. - d, err := FS.Stat(root) + d, err := c.fs.Stat(root) // If we fail here, report detailed error messages; otherwise // is is hard to see why a directory tree was not built. switch { @@ -177,7 +178,7 @@ func NewDirectory(root string, maxDepth int) *Directory { if maxDepth < 0 { maxDepth = 1e6 // "infinity" } - b := treeBuilder{maxDepth} + b := treeBuilder{c, maxDepth} // the file set provided is only for local parsing, no position // information escapes and thus we don't need to save the set return b.newDirTree(token.NewFileSet(), root, d.Name(), 0) diff --git a/godoc/godoc.go b/godoc/godoc.go index b1438ef2..e400f6de 100644 --- a/godoc/godoc.go +++ b/godoc/godoc.go @@ -38,6 +38,7 @@ import ( // 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 // system, which helps keep things simple. +// TODO(bradfitz): delete this global var FS = vfs.NameSpace{} // Old flags @@ -54,8 +55,6 @@ var ( // TODO(bradfitz,adg): delete this flag ShowPlayground = false - IndexEnabled = false - ShowTimestamps = false Verbose = false diff --git a/godoc/index.go b/godoc/index.go index b0b23ec3..d7c79203 100644 --- a/godoc/index.go +++ b/godoc/index.go @@ -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 // under godoc's observation change so that the indexer is kicked on. -func InvalidateIndex() { - FSModified.Set(nil) - refreshMetadata() +func (c *Corpus) invalidateIndex() { + c.fsModified.Set(nil) + c.refreshMetadata() } // indexUpToDate() returns true if the search index is not older diff --git a/godoc/meta.go b/godoc/meta.go index 13daf1d4..86f25e62 100644 --- a/godoc/meta.go +++ b/godoc/meta.go @@ -58,11 +58,11 @@ func extractMetadata(b []byte) (meta Metadata, tail []byte, err error) { // UpdateMetadata scans $GOROOT/doc for HTML files, reads their metadata, // and updates the DocMetadata map. -func UpdateMetadata() { +func (c *Corpus) updateMetadata() { metadata := make(map[string]*Metadata) var scan func(string) // scan is recursive scan = func(dir string) { - fis, err := FS.ReadDir(dir) + fis, err := c.fs.ReadDir(dir) if err != nil { log.Println("updateMetadata:", err) return @@ -77,7 +77,7 @@ func UpdateMetadata() { continue } // Extract metadata from the file. - b, err := vfs.ReadFile(FS, name) + b, err := vfs.ReadFile(c.fs, name) if err != nil { log.Printf("updateMetadata %s: %v", name, err) continue @@ -123,27 +123,22 @@ func MetadataFor(relpath string) *Metadata { 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 // progress the metadata will be refreshed again afterward. // -func refreshMetadata() { +func (c *Corpus) refreshMetadata() { select { - case refreshMetadataSignal <- true: + case c.refreshMetadataSignal <- true: default: } } // RefreshMetadataLoop runs forever, updating DocMetadata when the underlying // file system changes. It should be launched in a goroutine. -func RefreshMetadataLoop() { +func (c *Corpus) refreshMetadataLoop() { for { - <-refreshMetadataSignal - UpdateMetadata() + <-c.refreshMetadataSignal + c.updateMetadata() time.Sleep(10 * time.Second) // at most once every 10 seconds } } diff --git a/godoc/page.go b/godoc/page.go index 7157ef42..f8ee60ef 100644 --- a/godoc/page.go +++ b/godoc/page.go @@ -37,11 +37,11 @@ var ( SearchDescXML *template.Template ) -func ServePage(w http.ResponseWriter, page Page) { +func (p *Presentation) ServePage(w http.ResponseWriter, page Page) { if page.Tabtitle == "" { page.Tabtitle = page.Title } - page.SearchBox = IndexEnabled + page.SearchBox = p.Corpus.IndexEnabled page.Playground = ShowPlayground page.Version = runtime.Version() 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) - ServePage(w, Page{ + p.ServePage(w, Page{ Title: "File " + relpath, Subtitle: relpath, Body: applyTemplate(ErrorHTML, "errorHTML", err), // err may contain an absolute path! diff --git a/godoc/pres.go b/godoc/pres.go new file mode 100644 index 00000000..a002b3a0 --- /dev/null +++ b/godoc/pres.go @@ -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("") +} diff --git a/godoc/server.go b/godoc/server.go index baaadfe2..c4793ed7 100644 --- a/godoc/server.go +++ b/godoc/server.go @@ -42,16 +42,19 @@ var ( DocMetadata util.RWValue // mapping from paths to *Metadata ) -func InitHandlers(fs vfs.FileSystem) { - FileServer = http.FileServer(httpfs.New(fs)) - CmdHandler = Server{"/cmd/", "/src/cmd"} - PkgHandler = Server{"/pkg/", "/src/pkg"} +func InitHandlers(p *Presentation) { + c := p.Corpus + FileServer = http.FileServer(httpfs.New(c.fs)) + CmdHandler = Server{p, c, "/cmd/", "/src/cmd"} + PkgHandler = Server{p, c, "/pkg/", "/src/pkg"} } // Server is a godoc server. type Server struct { - pattern string // url pattern; e.g. "/pkg/" - fsRoot string // file system root to which the pattern is mapped + p *Presentation + 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 } @@ -178,7 +181,7 @@ func (h *Server) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageIn // command-line mode); compute one level for this page // note: cannot use path filter here because in general // it doesn't contain the FSTree path - dir = NewDirectory(abspath, 1) + dir = h.c.newDirectory(abspath, 1) timestamp = time.Now() } 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) if info.Err != nil { log.Print(info.Err) - ServeError(w, r, relpath, info.Err) + h.p.ServeError(w, r, relpath, info.Err) return } if mode&NoHTML != 0 { - ServeText(w, applyTemplate(PackageText, "packageText", info)) + h.p.ServeText(w, applyTemplate(PackageText, "packageText", info)) return } @@ -243,7 +246,7 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { tabtitle = "Commands" } - ServePage(w, Page{ + h.p.ServePage(w, Page{ Title: title, Tabtitle: tabtitle, Subtitle: subtitle, @@ -431,16 +434,16 @@ func redirectFile(w http.ResponseWriter, r *http.Request) (redirected bool) { return } -func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) { - src, err := vfs.ReadFile(FS, abspath) +func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) { + src, err := vfs.ReadFile(p.Corpus.fs, abspath) if err != nil { log.Printf("ReadFile: %s", err) - ServeError(w, r, relpath, err) + p.ServeError(w, r, relpath, err) return } if r.FormValue("m") == "text" { - ServeText(w, src) + p.ServeText(w, src) return } @@ -450,37 +453,37 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit buf.WriteString("") fmt.Fprintf(&buf, `

View as plain text

`, htmlpkg.EscapeString(relpath)) - ServePage(w, Page{ + p.ServePage(w, Page{ Title: title + " " + relpath, Tabtitle: relpath, 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) { return } list, err := FS.ReadDir(abspath) if err != nil { - ServeError(w, r, relpath, err) + p.ServeError(w, r, relpath, err) return } - ServePage(w, Page{ + p.ServePage(w, Page{ Title: "Directory " + relpath, Tabtitle: relpath, 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 src, err := vfs.ReadFile(FS, abspath) if err != nil { log.Printf("ReadFile: %s", err) - ServeError(w, r, relpath, err) + p.ServeError(w, r, relpath, err) 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)) if err != nil { log.Printf("parsing template %s: %v", relpath, err) - ServeError(w, r, relpath, err) + p.ServeError(w, r, relpath, err) return } var buf bytes.Buffer if err := tmpl.Execute(&buf, nil); err != nil { log.Printf("executing template %s: %v", relpath, err) - ServeError(w, r, relpath, err) + p.ServeError(w, r, relpath, err) return } src = buf.Bytes() @@ -521,14 +524,14 @@ func ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin src = buf.Bytes() } - ServePage(w, Page{ + p.ServePage(w, Page{ Title: meta.Title, Subtitle: meta.Subtitle, Body: src, }) } -func serveFile(w http.ResponseWriter, r *http.Request) { +func (p *Presentation) serveFile(w http.ResponseWriter, r *http.Request) { relpath := r.URL.Path // 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) return } - ServeHTMLDoc(w, r, abspath, relpath) + p.ServeHTMLDoc(w, r, abspath, relpath) return case ".go": - serveTextFile(w, r, abspath, relpath, "Source file") + p.serveTextFile(w, r, abspath, relpath, "Source file") return } dir, err := FS.Lstat(abspath) if err != nil { log.Print(err) - ServeError(w, r, relpath, err) + p.ServeError(w, r, relpath, err) return } @@ -573,10 +576,10 @@ func serveFile(w http.ResponseWriter, r *http.Request) { return } if index := pathpkg.Join(abspath, "index.html"); util.IsTextFile(FS, index) { - ServeHTMLDoc(w, r, index, index) + p.ServeHTMLDoc(w, r, index, index) return } - serveDirectory(w, r, abspath, relpath) + p.serveDirectory(w, r, abspath, relpath) return } @@ -584,7 +587,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) { if redirectFile(w, r) { return } - serveTextFile(w, r, abspath, relpath, "Text file") + p.serveTextFile(w, r, abspath, relpath, "Text file") 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.Write(text) }