diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go index 521b496d1b..148b36d2c2 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 fb8894456d..af9eaee33b 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 ee55355ccf..0e0bf713c7 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 3040a3589c..5611489f40 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 ea6cbcfd66..0a8fb474ec 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 c97aa96155..3a8b99a3c1 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 8d5b4e3a68..a50de5f5ce 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 91b39600c6..b3b05d8051 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) {