From 705bb7ffce9bdf77c77d4dc22b950d90a93f4474 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 19 Jul 2013 10:27:53 +1000 Subject: [PATCH] godoc: remove the last of the global variables, unexport Server The exported Server becomes handlerServer, and part of Presentation now. Presentation is also now an http.Handler with its own internal mux (a detail, which might go away). main.go becomes ever simpler. R=golang-dev, adg CC=golang-dev https://golang.org/cl/11505043 --- cmd/godoc/main.go | 21 ++++++++---------- godoc/corpus.go | 3 +++ godoc/godoc.go | 7 ++---- godoc/index.go | 4 ++-- godoc/linkify.go | 2 +- godoc/pres.go | 54 +++++++++++++++++++++++++++++++++++++++++++++-- godoc/search.go | 2 +- godoc/server.go | 46 ++++++++++++---------------------------- 8 files changed, 83 insertions(+), 56 deletions(-) diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go index 521b496d..148b36d2 100644 --- a/cmd/godoc/main.go +++ b/cmd/godoc/main.go @@ -110,14 +110,12 @@ func registerPublicHandlers(mux *http.ServeMux) { if pres == nil { panic("nil Presentation") } - godoc.CmdHandler.RegisterWithMux(mux) - godoc.PkgHandler.RegisterWithMux(mux) mux.HandleFunc("/doc/codewalk/", codewalk) - mux.Handle("/doc/play/", godoc.FileServer) + mux.Handle("/doc/play/", pres.FileServer()) mux.HandleFunc("/search", pres.HandleSearch) - mux.Handle("/robots.txt", godoc.FileServer) + mux.Handle("/robots.txt", pres.FileServer()) mux.HandleFunc("/opensearch.xml", serveSearchDesc) - mux.HandleFunc("/", pres.ServeFile) + mux.Handle("/", pres) } // ---------------------------------------------------------------------------- @@ -298,6 +296,7 @@ func main() { } corpus := godoc.NewCorpus(fs) + corpus.Verbose = *verbose corpus.IndexEnabled = *indexEnabled corpus.IndexFiles = *indexFiles if *writeIndex { @@ -319,8 +318,6 @@ func main() { readTemplates(pres) - godoc.InitHandlers(pres) - if *writeIndex { // Write search index and exit. if *indexFiles == "" { @@ -429,14 +426,14 @@ func main() { abspath = target relpath = bp.ImportPath } else { - abspath = pathpkg.Join(godoc.PkgHandler.FSRoot(), path) + abspath = pathpkg.Join(pres.PkgFSRoot(), path) } if relpath == "" { relpath = abspath } var mode godoc.PageInfoMode - if relpath == godoc.BuiltinPkgPath { + if relpath == "builtin" { // the fake built-in package contains unexported identifiers mode = godoc.NoFiltering } @@ -451,15 +448,15 @@ func main() { // first, try as package unless forced as command var info *godoc.PageInfo if !forceCmd { - info = godoc.PkgHandler.GetPageInfo(abspath, relpath, mode) + info = pres.GetPkgPageInfo(abspath, relpath, mode) } // second, try as command unless the path is absolute // (the go command invokes godoc w/ absolute paths; don't override) var cinfo *godoc.PageInfo if !filepath.IsAbs(path) { - abspath = pathpkg.Join(godoc.CmdHandler.FSRoot(), path) - cinfo = godoc.CmdHandler.GetPageInfo(abspath, relpath, mode) + abspath = pathpkg.Join(pres.CmdFSRoot(), path) + cinfo = pres.GetCmdPageInfo(abspath, relpath, mode) } // determine what to use diff --git a/godoc/corpus.go b/godoc/corpus.go index fb889445..af9eaee3 100644 --- a/godoc/corpus.go +++ b/godoc/corpus.go @@ -21,6 +21,9 @@ import ( type Corpus struct { fs vfs.FileSystem + // Verbose logging. + Verbose bool + // IndexEnabled controls whether indexing is enabled. IndexEnabled bool diff --git a/godoc/godoc.go b/godoc/godoc.go index ee55355c..0e0bf713 100644 --- a/godoc/godoc.go +++ b/godoc/godoc.go @@ -29,12 +29,9 @@ import ( "unicode/utf8" ) -// Verbose controls logging verbosity. -var Verbose = false - // Fake relative package path for built-ins. Documentation for all globals // (not just exported ones) will be shown for packages in this directory. -const BuiltinPkgPath = "builtin" +const builtinPkgPath = "builtin" // FuncMap defines template functions used in godoc templates. // @@ -232,7 +229,7 @@ func pkgLinkFunc(path string) string { // because of the irregular mapping under goroot // we need to correct certain relative paths relpath = strings.TrimPrefix(relpath, "src/pkg/") - return PkgHandler.pattern[1:] + relpath // remove trailing '/' for relative URL + return "pkg/" + relpath // remove trailing '/' for relative URL } // n must be an ast.Node or a *doc.Note diff --git a/godoc/index.go b/godoc/index.go index 3040a358..5611489f 100644 --- a/godoc/index.go +++ b/godoc/index.go @@ -1090,14 +1090,14 @@ func (c *Corpus) readIndex(filenames string) error { } func (c *Corpus) UpdateIndex() { - if Verbose { + if c.Verbose { log.Printf("updating index...") } start := time.Now() index := NewIndex(c, c.fsDirnames(), c.MaxResults > 0, c.IndexThrottle) stop := time.Now() c.searchIndex.Set(index) - if Verbose { + if c.Verbose { secs := stop.Sub(start).Seconds() stats := index.Stats() log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)", diff --git a/godoc/linkify.go b/godoc/linkify.go index ea6cbcfd..0a8fb474 100644 --- a/godoc/linkify.go +++ b/godoc/linkify.go @@ -94,7 +94,7 @@ func linksFor(node ast.Node) (list []link) { switch m { case identUse: if n.Obj == nil && predeclared[n.Name] { - info.path = BuiltinPkgPath + info.path = builtinPkgPath } info.name = n.Name case identDef: diff --git a/godoc/pres.go b/godoc/pres.go index c97aa961..3a8b99a3 100644 --- a/godoc/pres.go +++ b/godoc/pres.go @@ -5,15 +5,23 @@ package godoc import ( + "net/http" "regexp" "sync" "text/template" + + "code.google.com/p/go.tools/godoc/vfs/httpfs" ) // Presentation generates output from a corpus. type Presentation struct { Corpus *Corpus + mux *http.ServeMux + fileServer http.Handler + cmdHandler handlerServer + pkgHandler handlerServer + DirlistHTML, ErrorHTML, ExampleHTML, @@ -36,6 +44,11 @@ type Presentation struct { // notes to render in the output. NotesRx *regexp.Regexp + // AdjustPageInfoMode optionally specifies a function to + // modify the PageInfoMode of a request. The default chosen + // value is provided. + AdjustPageInfoMode func(req *http.Request, mode PageInfoMode) PageInfoMode + initFuncMapOnce sync.Once funcMap template.FuncMap templateFuncs template.FuncMap @@ -46,10 +59,47 @@ func NewPresentation(c *Corpus) *Presentation { if c == nil { panic("nil Corpus") } - return &Presentation{ - Corpus: c, + p := &Presentation{ + Corpus: c, + mux: http.NewServeMux(), + fileServer: http.FileServer(httpfs.New(c.fs)), + TabWidth: 4, ShowExamples: true, DeclLinks: true, } + p.cmdHandler = handlerServer{p, c, "/cmd/", "/src/cmd"} + p.pkgHandler = handlerServer{p, c, "/pkg/", "/src/pkg"} + p.cmdHandler.registerWithMux(p.mux) + p.pkgHandler.registerWithMux(p.mux) + p.mux.HandleFunc("/", p.ServeFile) + return p +} + +func (p *Presentation) FileServer() http.Handler { + return p.fileServer +} + +func (p *Presentation) ServeHTTP(w http.ResponseWriter, r *http.Request) { + p.mux.ServeHTTP(w, r) +} + +func (p *Presentation) PkgFSRoot() string { + return p.pkgHandler.fsRoot +} + +func (p *Presentation) CmdFSRoot() string { + return p.cmdHandler.fsRoot +} + +// TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now, +// but this doesn't feel right. +func (p *Presentation) GetPkgPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo { + return p.pkgHandler.GetPageInfo(abspath, relpath, mode) +} + +// TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now, +// but this doesn't feel right. +func (p *Presentation) GetCmdPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo { + return p.cmdHandler.GetPageInfo(abspath, relpath, mode) } diff --git a/godoc/search.go b/godoc/search.go index 8d5b4e3a..a50de5f5 100644 --- a/godoc/search.go +++ b/godoc/search.go @@ -78,7 +78,7 @@ func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) { query := strings.TrimSpace(r.FormValue("q")) result := p.Corpus.Lookup(query) - if GetPageInfoMode(r)&NoHTML != 0 { + if p.GetPageInfoMode(r)&NoHTML != 0 { p.ServeText(w, applyTemplate(p.SearchText, "searchText", result)) return } diff --git a/godoc/server.go b/godoc/server.go index 91b39600..b3b05d80 100644 --- a/godoc/server.go +++ b/godoc/server.go @@ -25,35 +25,18 @@ import ( "code.google.com/p/go.tools/godoc/util" "code.google.com/p/go.tools/godoc/vfs" - "code.google.com/p/go.tools/godoc/vfs/httpfs" ) -// TODO(bradfitz,adg): these are moved from godoc.go globals. -// Clean this up. -var ( - FileServer http.Handler // default file server - CmdHandler Server - PkgHandler Server -) - -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 { +// handlerServer is a migration from an old godoc http Handler type. +// This should probably merge into something else. +type handlerServer struct { 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 } - -func (s *Server) RegisterWithMux(mux *http.ServeMux) { +func (s *handlerServer) registerWithMux(mux *http.ServeMux) { mux.Handle(s.pattern, s) } @@ -65,7 +48,7 @@ func (s *Server) RegisterWithMux(mux *http.ServeMux) { // directories, PageInfo.Dirs is nil. If an error occurred, PageInfo.Err is // set to the respective error but the error is not logged. // -func (h *Server) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo { +func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo { info := &PageInfo{Dirname: abspath} // Restrict to the package files that would be used when building @@ -194,15 +177,15 @@ func (h *Server) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageIn return info } -func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { if redirect(w, r) { return } relpath := pathpkg.Clean(r.URL.Path[len(h.pattern):]) abspath := pathpkg.Join(h.fsRoot, relpath) - mode := GetPageInfoMode(r) - if relpath == BuiltinPkgPath { + mode := h.p.GetPageInfoMode(r) + if relpath == builtinPkgPath { mode = NoFiltering } info := h.GetPageInfo(abspath, relpath, mode) @@ -279,19 +262,16 @@ var modeNames = map[string]PageInfoMode{ // GetPageInfoMode computes the PageInfoMode flags by analyzing the request // URL form value "m". It is value is a comma-separated list of mode names // as defined by modeNames (e.g.: m=src,text). -func GetPageInfoMode(r *http.Request) PageInfoMode { +func (p *Presentation) GetPageInfoMode(r *http.Request) PageInfoMode { var mode PageInfoMode for _, k := range strings.Split(r.FormValue("m"), ",") { if m, found := modeNames[strings.TrimSpace(k)]; found { mode |= m } } - return AdjustPageInfoMode(r, mode) -} - -// AdjustPageInfoMode allows specialized versions of godoc to adjust -// PageInfoMode by overriding this variable. -var AdjustPageInfoMode = func(_ *http.Request, mode PageInfoMode) PageInfoMode { + if p.AdjustPageInfoMode != nil { + mode = p.AdjustPageInfoMode(r, mode) + } return mode } @@ -584,7 +564,7 @@ func (p *Presentation) serveFile(w http.ResponseWriter, r *http.Request) { return } - FileServer.ServeHTTP(w, r) + p.fileServer.ServeHTTP(w, r) } func (p *Presentation) serveSearchDesc(w http.ResponseWriter, r *http.Request) {