github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/_vendor/src/golang.org/x/tools/cmd/godoc/main.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // godoc: Go Documentation Server 6 7 // Web server tree: 8 // 9 // http://godoc/ main landing page 10 // http://godoc/doc/ serve from $GOROOT/doc - spec, mem, etc. 11 // http://godoc/src/ serve files from $GOROOT/src; .go gets pretty-printed 12 // http://godoc/cmd/ serve documentation about commands 13 // http://godoc/pkg/ serve documentation about packages 14 // (idea is if you say import "compress/zlib", you go to 15 // http://godoc/pkg/compress/zlib) 16 // 17 // Command-line interface: 18 // 19 // godoc packagepath [name ...] 20 // 21 // godoc compress/zlib 22 // - prints doc for package compress/zlib 23 // godoc crypto/block Cipher NewCMAC 24 // - prints doc for Cipher and NewCMAC in package crypto/block 25 26 // +build !appengine 27 28 package main 29 30 import ( 31 "archive/zip" 32 _ "expvar" // to serve /debug/vars 33 "flag" 34 "fmt" 35 "go/build" 36 "log" 37 "net/http" 38 "net/http/httptest" 39 _ "net/http/pprof" // to serve /debug/pprof/* 40 "net/url" 41 "os" 42 "path/filepath" 43 "regexp" 44 "runtime" 45 "strings" 46 47 "golang.org/x/tools/godoc" 48 "golang.org/x/tools/godoc/analysis" 49 "golang.org/x/tools/godoc/static" 50 "golang.org/x/tools/godoc/vfs" 51 "golang.org/x/tools/godoc/vfs/gatefs" 52 "golang.org/x/tools/godoc/vfs/mapfs" 53 "golang.org/x/tools/godoc/vfs/zipfs" 54 ) 55 56 const defaultAddr = ":6060" // default webserver address 57 58 var ( 59 // file system to serve 60 // (with e.g.: zip -r go.zip $GOROOT -i \*.go -i \*.html -i \*.css -i \*.js -i \*.txt -i \*.c -i \*.h -i \*.s -i \*.png -i \*.jpg -i \*.sh -i favicon.ico) 61 zipfile = flag.String("zip", "", "zip file providing the file system to serve; disabled if empty") 62 63 // file-based index 64 writeIndex = flag.Bool("write_index", false, "write index to a file; the file name must be specified with -index_files") 65 66 analysisFlag = flag.String("analysis", "", `comma-separated list of analyses to perform (supported: type, pointer). See http://golang.org/lib/godoc/analysis/help.html`) 67 68 // network 69 httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')") 70 serverAddr = flag.String("server", "", "webserver address for command line searches") 71 72 // layout control 73 html = flag.Bool("html", false, "print HTML in command-line mode") 74 srcMode = flag.Bool("src", false, "print (exported) source in command-line mode") 75 allMode = flag.Bool("all", false, "include unexported identifiers in command-line mode") 76 urlFlag = flag.String("url", "", "print HTML for named URL") 77 78 // command-line searches 79 query = flag.Bool("q", false, "arguments are considered search queries") 80 81 verbose = flag.Bool("v", false, "verbose mode") 82 83 // file system roots 84 // TODO(gri) consider the invariant that goroot always end in '/' 85 goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory") 86 87 // layout control 88 tabWidth = flag.Int("tabwidth", 4, "tab width") 89 showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings") 90 templateDir = flag.String("templates", "", "load templates/JS/CSS from disk in this directory") 91 showPlayground = flag.Bool("play", false, "enable playground in web interface") 92 showExamples = flag.Bool("ex", false, "show examples in command line mode") 93 declLinks = flag.Bool("links", true, "link identifiers to their declarations") 94 95 // search index 96 indexEnabled = flag.Bool("index", false, "enable search index") 97 indexFiles = flag.String("index_files", "", "glob pattern specifying index files; if not empty, the index is read from these files in sorted order") 98 indexInterval = flag.Duration("index_interval", 0, "interval of indexing; 0 for default (5m), negative to only index once at startup") 99 maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown") 100 indexThrottle = flag.Float64("index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle") 101 102 // source code notes 103 notesRx = flag.String("notes", "BUG", "regular expression matching note markers to show") 104 ) 105 106 func usage() { 107 fmt.Fprintf(os.Stderr, 108 "usage: godoc package [name ...]\n"+ 109 " godoc -http="+defaultAddr+"\n") 110 flag.PrintDefaults() 111 os.Exit(2) 112 } 113 114 func loggingHandler(h http.Handler) http.Handler { 115 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 116 log.Printf("%s\t%s", req.RemoteAddr, req.URL) 117 h.ServeHTTP(w, req) 118 }) 119 } 120 121 func handleURLFlag() { 122 // Try up to 10 fetches, following redirects. 123 urlstr := *urlFlag 124 for i := 0; i < 10; i++ { 125 // Prepare request. 126 u, err := url.Parse(urlstr) 127 if err != nil { 128 log.Fatal(err) 129 } 130 req := &http.Request{ 131 URL: u, 132 } 133 134 // Invoke default HTTP handler to serve request 135 // to our buffering httpWriter. 136 w := httptest.NewRecorder() 137 http.DefaultServeMux.ServeHTTP(w, req) 138 139 // Return data, error, or follow redirect. 140 switch w.Code { 141 case 200: // ok 142 os.Stdout.Write(w.Body.Bytes()) 143 return 144 case 301, 302, 303, 307: // redirect 145 redirect := w.HeaderMap.Get("Location") 146 if redirect == "" { 147 log.Fatalf("HTTP %d without Location header", w.Code) 148 } 149 urlstr = redirect 150 default: 151 log.Fatalf("HTTP error %d", w.Code) 152 } 153 } 154 log.Fatalf("too many redirects") 155 } 156 157 func initCorpus(corpus *godoc.Corpus) { 158 err := corpus.Init() 159 if err != nil { 160 log.Fatal(err) 161 } 162 } 163 164 func main() { 165 flag.Usage = usage 166 flag.Parse() 167 168 if certInit != nil { 169 certInit() 170 } 171 172 playEnabled = *showPlayground 173 174 // Check usage: server and no args. 175 if (*httpAddr != "" || *urlFlag != "") && (flag.NArg() > 0) { 176 fmt.Fprintln(os.Stderr, "can't use -http with args.") 177 usage() 178 } 179 180 // Check usage: command line args or index creation mode. 181 if (*httpAddr != "" || *urlFlag != "") != (flag.NArg() == 0) && !*writeIndex { 182 fmt.Fprintln(os.Stderr, "missing args.") 183 usage() 184 } 185 186 var fsGate chan bool 187 fsGate = make(chan bool, 20) 188 189 // Determine file system to use. 190 if *zipfile == "" { 191 // use file system of underlying OS 192 rootfs := gatefs.New(vfs.OS(*goroot), fsGate) 193 fs.Bind("/", rootfs, "/", vfs.BindReplace) 194 } else { 195 // use file system specified via .zip file (path separator must be '/') 196 rc, err := zip.OpenReader(*zipfile) 197 if err != nil { 198 log.Fatalf("%s: %s\n", *zipfile, err) 199 } 200 defer rc.Close() // be nice (e.g., -writeIndex mode) 201 fs.Bind("/", zipfs.New(rc, *zipfile), *goroot, vfs.BindReplace) 202 } 203 if *templateDir != "" { 204 fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore) 205 } else { 206 fs.Bind("/lib/godoc", mapfs.New(static.Files), "/", vfs.BindReplace) 207 } 208 209 // Bind $GOPATH trees into Go root. 210 for _, p := range filepath.SplitList(build.Default.GOPATH) { 211 fs.Bind("/src", gatefs.New(vfs.OS(p), fsGate), "/src", vfs.BindAfter) 212 } 213 214 httpMode := *httpAddr != "" 215 216 var typeAnalysis, pointerAnalysis bool 217 if *analysisFlag != "" { 218 for _, a := range strings.Split(*analysisFlag, ",") { 219 switch a { 220 case "type": 221 typeAnalysis = true 222 case "pointer": 223 pointerAnalysis = true 224 default: 225 log.Fatalf("unknown analysis: %s", a) 226 } 227 } 228 } 229 230 corpus := godoc.NewCorpus(fs) 231 corpus.Verbose = *verbose 232 corpus.MaxResults = *maxResults 233 corpus.IndexEnabled = *indexEnabled && httpMode 234 if *maxResults == 0 { 235 corpus.IndexFullText = false 236 } 237 corpus.IndexFiles = *indexFiles 238 corpus.IndexDirectory = indexDirectoryDefault 239 corpus.IndexThrottle = *indexThrottle 240 corpus.IndexInterval = *indexInterval 241 if *writeIndex { 242 corpus.IndexThrottle = 1.0 243 corpus.IndexEnabled = true 244 } 245 if *writeIndex || httpMode || *urlFlag != "" { 246 if httpMode { 247 go initCorpus(corpus) 248 } else { 249 initCorpus(corpus) 250 } 251 } 252 253 pres = godoc.NewPresentation(corpus) 254 pres.TabWidth = *tabWidth 255 pres.ShowTimestamps = *showTimestamps 256 pres.ShowPlayground = *showPlayground 257 pres.ShowExamples = *showExamples 258 pres.DeclLinks = *declLinks 259 pres.SrcMode = *srcMode 260 pres.HTMLMode = *html 261 pres.AllMode = *allMode 262 if *notesRx != "" { 263 pres.NotesRx = regexp.MustCompile(*notesRx) 264 } 265 266 readTemplates(pres, httpMode || *urlFlag != "") 267 registerHandlers(pres) 268 269 if *writeIndex { 270 // Write search index and exit. 271 if *indexFiles == "" { 272 log.Fatal("no index file specified") 273 } 274 275 log.Println("initialize file systems") 276 *verbose = true // want to see what happens 277 278 corpus.UpdateIndex() 279 280 log.Println("writing index file", *indexFiles) 281 f, err := os.Create(*indexFiles) 282 if err != nil { 283 log.Fatal(err) 284 } 285 index, _ := corpus.CurrentIndex() 286 _, err = index.WriteTo(f) 287 if err != nil { 288 log.Fatal(err) 289 } 290 291 log.Println("done") 292 return 293 } 294 295 // Print content that would be served at the URL *urlFlag. 296 if *urlFlag != "" { 297 handleURLFlag() 298 return 299 } 300 301 if httpMode { 302 // HTTP server mode. 303 var handler http.Handler = http.DefaultServeMux 304 if *verbose { 305 log.Printf("Go Documentation Server") 306 log.Printf("version = %s", runtime.Version()) 307 log.Printf("address = %s", *httpAddr) 308 log.Printf("goroot = %s", *goroot) 309 log.Printf("tabwidth = %d", *tabWidth) 310 switch { 311 case !*indexEnabled: 312 log.Print("search index disabled") 313 case *maxResults > 0: 314 log.Printf("full text index enabled (maxresults = %d)", *maxResults) 315 default: 316 log.Print("identifier search index enabled") 317 } 318 fs.Fprint(os.Stderr) 319 handler = loggingHandler(handler) 320 } 321 322 // Initialize search index. 323 if *indexEnabled { 324 go corpus.RunIndexer() 325 } 326 327 // Start type/pointer analysis. 328 if typeAnalysis || pointerAnalysis { 329 go analysis.Run(pointerAnalysis, &corpus.Analysis) 330 } 331 332 if runHTTPS != nil { 333 go func() { 334 if err := runHTTPS(handler); err != nil { 335 log.Fatalf("ListenAndServe TLS: %v", err) 336 } 337 }() 338 } 339 340 // Start http server. 341 if *verbose { 342 log.Println("starting HTTP server") 343 } 344 if wrapHTTPMux != nil { 345 handler = wrapHTTPMux(handler) 346 } 347 if err := http.ListenAndServe(*httpAddr, handler); err != nil { 348 log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) 349 } 350 351 return 352 } 353 354 if *query { 355 handleRemoteSearch() 356 return 357 } 358 359 if err := godoc.CommandLine(os.Stdout, fs, pres, flag.Args()); err != nil { 360 log.Print(err) 361 } 362 } 363 364 // Hooks that are set non-nil in autocert.go if the "autocert" build tag 365 // is used. 366 var ( 367 certInit func() 368 runHTTPS func(http.Handler) error 369 wrapHTTPMux func(http.Handler) http.Handler 370 )