diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-04-20 15:44:41 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-04-20 15:44:41 +0200 |
commit | 50104cc32a498f7517a51c8dc93106c51c7a54b4 (patch) | |
tree | 47af80be259cc7c45d0eaec7d42e61fa38c8e4fb /src/cmd/godoc | |
parent | c072558b90f1bbedc2022b0f30c8b1ac4712538e (diff) | |
download | golang-50104cc32a498f7517a51c8dc93106c51c7a54b4.tar.gz |
Imported Upstream version 2011.03.07.1upstream/2011.03.07.1
Diffstat (limited to 'src/cmd/godoc')
-rw-r--r-- | src/cmd/godoc/dirtrees.go | 29 | ||||
-rw-r--r-- | src/cmd/godoc/godoc.go | 82 | ||||
-rw-r--r-- | src/cmd/godoc/index.go | 8 | ||||
-rw-r--r-- | src/cmd/godoc/main.go | 10 | ||||
-rw-r--r-- | src/cmd/godoc/mapping.go | 47 | ||||
-rw-r--r-- | src/cmd/godoc/utils.go | 12 |
6 files changed, 108 insertions, 80 deletions
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go index edb4a169d..3ad7c8cfc 100644 --- a/src/cmd/godoc/dirtrees.go +++ b/src/cmd/godoc/dirtrees.go @@ -12,8 +12,9 @@ import ( "go/parser" "go/token" "io/ioutil" + "log" "os" - pathutil "path" + "path/filepath" "strings" "unicode" ) @@ -31,7 +32,7 @@ type Directory struct { func isGoFile(f *os.FileInfo) bool { return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && // ignore .files - pathutil.Ext(f.Name) == ".go" + filepath.Ext(f.Name) == ".go" } @@ -100,7 +101,13 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i return &Directory{depth, path, name, "", nil} } - list, _ := ioutil.ReadDir(path) // ignore errors + list, err := ioutil.ReadDir(path) + if err != nil { + // newDirTree is called with a path that should be a package + // directory; errors here should not happen, but if they do, + // we want to know about them + log.Printf("ioutil.ReadDir(%s): %s", path, err) + } // determine number of subdirectories and if there are package files ndirs := 0 @@ -116,7 +123,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i // though the directory doesn't contain any real package files - was bug) if synopses[0] == "" { // no "optimal" package synopsis yet; continue to collect synopses - file, err := parser.ParseFile(fset, pathutil.Join(path, d.Name), nil, + file, err := parser.ParseFile(fset, filepath.Join(path, d.Name), nil, parser.ParseComments|parser.PackageClauseOnly) if err == nil { hasPkgFiles = true @@ -149,7 +156,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i i := 0 for _, d := range list { if isPkgDir(d) { - dd := b.newDirTree(fset, pathutil.Join(path, d.Name), d.Name, depth+1) + dd := b.newDirTree(fset, filepath.Join(path, d.Name), d.Name, depth+1) if dd != nil { dirs[i] = dd i++ @@ -188,8 +195,16 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i // (i.e., in this case the tree may contain directories w/o any package files). // func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory { - d, err := os.Lstat(root) - if err != nil || !isPkgDir(d) { + // The root could be a symbolic link so use os.Stat not os.Lstat. + d, err := os.Stat(root) + // If we fail here, report detailed error messages; otherwise + // is is hard to see why a directory tree was not built. + switch { + case err != nil: + log.Printf("newDirectory(%s): %s", root, err) + return nil + case !isPkgDir(d): + log.Printf("newDirectory(%s): not a package directory", root) return nil } if maxDepth < 0 { diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go index c91dc33db..9dce5edf9 100644 --- a/src/cmd/godoc/godoc.go +++ b/src/cmd/godoc/godoc.go @@ -18,7 +18,8 @@ import ( "io/ioutil" "log" "os" - pathutil "path" + "path" + "path/filepath" "regexp" "runtime" "sort" @@ -81,8 +82,8 @@ var ( func initHandlers() { fsMap.Init(*pkgPath) fileServer = http.FileServer(*goroot, "") - cmdHandler = httpHandler{"/cmd/", pathutil.Join(*goroot, "src/cmd"), false} - pkgHandler = httpHandler{"/pkg/", pathutil.Join(*goroot, "src/pkg"), true} + cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false} + pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true} } @@ -91,12 +92,13 @@ func registerPublicHandlers(mux *http.ServeMux) { mux.Handle(pkgHandler.pattern, &pkgHandler) mux.HandleFunc("/doc/codewalk/", codewalk) mux.HandleFunc("/search", search) + mux.Handle("/robots.txt", fileServer) mux.HandleFunc("/", serveFile) } func initFSTree() { - fsTree.set(newDirectory(pathutil.Join(*goroot, *testDir), nil, -1)) + fsTree.set(newDirectory(filepath.Join(*goroot, *testDir), nil, -1)) invalidateIndex() } @@ -147,8 +149,13 @@ func readDirList(filename string) ([]string, os.Error) { } // create a sorted list of valid directory names filter := func(path string) bool { - d, err := os.Lstat(path) - return err == nil && isPkgDir(d) + d, e := os.Lstat(path) + if e != nil && err == nil { + // remember first error and return it from readDirList + // so we have at least some information if things go bad + err = e + } + return e == nil && isPkgDir(d) } list := canonicalizePaths(strings.Split(string(contents), "\n", -1), filter) // for each parent path, remove all it's children q @@ -160,7 +167,7 @@ func readDirList(filename string) ([]string, os.Error) { i++ } } - return list[0:i], nil + return list[0:i], err } @@ -207,9 +214,10 @@ func initDirTrees() { if *filter != "" { list, err := readDirList(*filter) if err != nil { - log.Printf("%s", err) - } else if len(list) == 0 { - log.Printf("no directory paths in file %s", *filter) + log.Printf("readDirList(%s): %s", *filter, err) + } + if *verbose || len(list) == 0 { + log.Printf("found %d directory paths in file %s", len(list), *filter) } setPathFilter(list) } @@ -239,27 +247,30 @@ func initDirTrees() { // ---------------------------------------------------------------------------- // Path mapping -func absolutePath(path, defaultRoot string) string { - abspath := fsMap.ToAbsolute(path) +// Absolute paths are file system paths (backslash-separated on Windows), +// but relative paths are always slash-separated. + +func absolutePath(relpath, defaultRoot string) string { + abspath := fsMap.ToAbsolute(relpath) if abspath == "" { // no user-defined mapping found; use default mapping - abspath = pathutil.Join(defaultRoot, path) + abspath = filepath.Join(defaultRoot, filepath.FromSlash(relpath)) } return abspath } -func relativePath(path string) string { - relpath := fsMap.ToRelative(path) +func relativeURL(abspath string) string { + relpath := fsMap.ToRelative(abspath) if relpath == "" { - // prefix must end in '/' + // prefix must end in a path separator prefix := *goroot - if len(prefix) > 0 && prefix[len(prefix)-1] != '/' { - prefix += "/" + if len(prefix) > 0 && prefix[len(prefix)-1] != filepath.Separator { + prefix += string(filepath.Separator) } - if strings.HasPrefix(path, prefix) { + if strings.HasPrefix(abspath, prefix) { // no user-defined mapping found; use default mapping - relpath = path[len(prefix):] + relpath = filepath.ToSlash(abspath[len(prefix):]) } } // Only if path is an invalid absolute path is relpath == "" @@ -474,7 +485,7 @@ func urlFmt(w io.Writer, format string, x ...interface{}) { } // map path - relpath := relativePath(path) + relpath := relativeURL(path) // convert to relative URLs so that they can also // be used as relative file names in .txt templates @@ -591,7 +602,7 @@ func dirslashFmt(w io.Writer, format string, x ...interface{}) { // Template formatter for "localname" format. func localnameFmt(w io.Writer, format string, x ...interface{}) { - _, localname := pathutil.Split(x[0].(string)) + _, localname := filepath.Split(x[0].(string)) template.HTMLEscape(w, []byte(localname)) } @@ -623,7 +634,7 @@ var fmap = template.FormatterMap{ func readTemplate(name string) *template.Template { - path := pathutil.Join(*goroot, "lib/godoc/"+name) + path := filepath.Join(*goroot, "lib", "godoc", name) data, err := ioutil.ReadFile(path) if err != nil { log.Fatalf("ReadFile %s: %v", path, err) @@ -760,14 +771,13 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte { func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) { - if canonical := pathutil.Clean(r.URL.Path) + "/"; r.URL.Path != canonical { + if canonical := path.Clean(r.URL.Path) + "/"; r.URL.Path != canonical { http.Redirect(w, r, canonical, http.StatusMovedPermanently) redirected = true } return } - func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) { src, err := ioutil.ReadFile(abspath) if err != nil { @@ -778,7 +788,7 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit var buf bytes.Buffer buf.WriteString("<pre>") - FormatText(&buf, src, 1, pathutil.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s"))) + FormatText(&buf, src, 1, filepath.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s"))) buf.WriteString("</pre>") servePage(w, title+" "+relpath, "", "", buf.Bytes()) @@ -815,7 +825,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) { // pick off special cases and hand the rest to the standard file server switch r.URL.Path { case "/": - serveHTMLDoc(w, r, pathutil.Join(*goroot, "doc/root.html"), "doc/root.html") + serveHTMLDoc(w, r, filepath.Join(*goroot, "doc", "root.html"), "doc/root.html") return case "/doc/root.html": @@ -824,9 +834,9 @@ func serveFile(w http.ResponseWriter, r *http.Request) { return } - switch pathutil.Ext(abspath) { + switch path.Ext(relpath) { case ".html": - if strings.HasSuffix(abspath, "/index.html") { + if strings.HasSuffix(relpath, "/index.html") { // We'll show index.html for the directory. // Use the dir/ version as canonical instead of dir/index.html. http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently) @@ -851,8 +861,8 @@ func serveFile(w http.ResponseWriter, r *http.Request) { if redirect(w, r) { return } - if index := abspath + "/index.html"; isTextFile(index) { - serveHTMLDoc(w, r, index, relativePath(index)) + if index := filepath.Join(abspath, "index.html"); isTextFile(index) { + serveHTMLDoc(w, r, index, relativeURL(index)) return } serveDirectory(w, r, abspath, relpath) @@ -948,13 +958,13 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf // the package with dirname, and the 3rd choice is a package // that is not called "main" if there is exactly one such // package. Otherwise, don't select a package. - dirpath, dirname := pathutil.Split(abspath) + dirpath, dirname := filepath.Split(abspath) // If the dirname is "go" we might be in a sub-directory for // .go files - use the outer directory name instead for better // results. if dirname == "go" { - _, dirname = pathutil.Split(pathutil.Clean(dirpath)) + _, dirname = filepath.Split(filepath.Clean(dirpath)) } var choice3 *ast.Package @@ -995,7 +1005,7 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf ast.PackageExports(pkg) } if mode&genDoc != 0 { - pdoc = doc.NewPackageDoc(pkg, pathutil.Clean(relpath)) // no trailing '/' in importpath + pdoc = doc.NewPackageDoc(pkg, path.Clean(relpath)) // no trailing '/' in importpath } else { past = ast.MergePackageFiles(pkg, ast.FilterUnassociatedComments) } @@ -1081,13 +1091,13 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { title = "Package " + info.PDoc.PackageName case info.PDoc.PackageName == fakePkgName: // assume that the directory name is the command name - _, pkgname := pathutil.Split(pathutil.Clean(relpath)) + _, pkgname := path.Split(path.Clean(relpath)) title = "Command " + pkgname default: title = "Command " + info.PDoc.PackageName } default: - title = "Directory " + relativePath(info.Dirname) + title = "Directory " + relativeURL(info.Dirname) if *showTimestamps { subtitle = "Last update: " + time.SecondsToLocalTime(info.DirTime).String() } diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go index 56f31f5cf..5af4d15cb 100644 --- a/src/cmd/godoc/index.go +++ b/src/cmd/godoc/index.go @@ -47,7 +47,7 @@ import ( "index/suffixarray" "io/ioutil" "os" - "path" + "path/filepath" "regexp" "sort" "strings" @@ -718,7 +718,7 @@ var whitelisted = map[string]bool{ // of "permitted" files for indexing. The filename must // be the directory-local name of the file. func isWhitelisted(filename string) bool { - key := path.Ext(filename) + key := filepath.Ext(filename) if key == "" { // file has no extension - use entire filename key = filename @@ -732,7 +732,7 @@ func (x *Indexer) visitFile(dirname string, f *os.FileInfo, fulltextIndex bool) return } - filename := path.Join(dirname, f.Name) + filename := filepath.Join(dirname, f.Name) goFile := false switch { @@ -757,7 +757,7 @@ func (x *Indexer) visitFile(dirname string, f *os.FileInfo, fulltextIndex bool) if fast != nil { // we've got a Go file to index x.current = file - dir, _ := path.Split(filename) + dir, _ := filepath.Split(filename) pak := Pak{dir, fast.Name.Name} x.file = &File{filename, pak} ast.Walk(x, fast) diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go index ea1e3c42e..1ebb80279 100644 --- a/src/cmd/godoc/main.go +++ b/src/cmd/godoc/main.go @@ -36,7 +36,7 @@ import ( "io" "log" "os" - pathutil "path" + "path/filepath" "regexp" "runtime" "strings" @@ -314,14 +314,14 @@ func main() { if len(path) > 0 && path[0] == '.' { // assume cwd; don't assume -goroot cwd, _ := os.Getwd() // ignore errors - path = pathutil.Join(cwd, path) + path = filepath.Join(cwd, path) } relpath := path abspath := path - if !pathutil.IsAbs(path) { + if !filepath.IsAbs(path) { abspath = absolutePath(path, pkgHandler.fsRoot) } else { - relpath = relativePath(path) + relpath = relativeURL(path) } var mode PageInfoMode @@ -339,7 +339,7 @@ func main() { if info.IsEmpty() { // try again, this time assume it's a command - if !pathutil.IsAbs(path) { + if !filepath.IsAbs(path) { abspath = absolutePath(path, cmdHandler.fsRoot) } cmdInfo := cmdHandler.getPageInfo(abspath, relpath, "", mode) diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go index 1d87bbc76..6ae9032e4 100644 --- a/src/cmd/godoc/mapping.go +++ b/src/cmd/godoc/mapping.go @@ -10,7 +10,8 @@ import ( "fmt" "io" "os" - pathutil "path" + "path" + "path/filepath" "sort" "strings" ) @@ -59,10 +60,10 @@ type mapping struct { } -// Init initializes the Mapping from a list of ':'-separated -// paths. Empty paths are ignored; relative paths are assumed -// to be relative to the current working directory and converted -// to absolute paths. For each path of the form: +// Init initializes the Mapping from a list of paths separated by +// filepath.ListSeparator. Empty paths are ignored; relative paths +// are assumed to be relative to the current working directory and +// converted to absolute paths. For each path of the form: // // dirname/localname // @@ -71,7 +72,7 @@ type mapping struct { // localname -> path // // is added to the Mapping object, in the order of occurrence. -// For instance, the argument: +// For instance, under Unix, the argument: // // /home/user:/home/build/public // @@ -81,12 +82,12 @@ type mapping struct { // public -> /home/build/public // func (m *Mapping) Init(paths string) { - pathlist := canonicalizePaths(strings.Split(paths, ":", -1), nil) + pathlist := canonicalizePaths(filepath.SplitList(paths), nil) list := make([]mapping, len(pathlist)) // create mapping list for i, path := range pathlist { - _, prefix := pathutil.Split(path) + _, prefix := filepath.Split(path) list[i] = mapping{prefix, path, new(RWValue)} } @@ -147,7 +148,7 @@ func (m *Mapping) Fprint(w io.Writer) { func splitFirst(path string) (head, tail string) { - i := strings.Index(path, "/") + i := strings.Index(path, string(filepath.Separator)) if i > 0 { // 0 < i < len(path) return path[0:i], path[i+1:] @@ -156,22 +157,23 @@ func splitFirst(path string) (head, tail string) { } -// ToAbsolute maps a relative path to an absolute path using the Mapping -// specified by the receiver. If the path cannot be mapped, the empty -// string is returned. +// ToAbsolute maps a slash-separated relative path to an absolute filesystem +// path using the Mapping specified by the receiver. If the path cannot +// be mapped, the empty string is returned. // -func (m *Mapping) ToAbsolute(path string) string { - prefix, tail := splitFirst(path) +func (m *Mapping) ToAbsolute(spath string) string { + fpath := filepath.FromSlash(spath) + prefix, tail := splitFirst(fpath) for _, e := range m.list { switch { case e.prefix == prefix: // use tail case e.prefix == "": - tail = path + tail = fpath default: continue // no match } - abspath := pathutil.Join(e.path, tail) + abspath := filepath.Join(e.path, tail) if _, err := os.Stat(abspath); err == nil { return abspath } @@ -181,15 +183,16 @@ func (m *Mapping) ToAbsolute(path string) string { } -// ToRelative maps an absolute path to a relative path using the Mapping -// specified by the receiver. If the path cannot be mapped, the empty -// string is returned. +// ToRelative maps an absolute filesystem path to a relative slash-separated +// path using the Mapping specified by the receiver. If the path cannot +// be mapped, the empty string is returned. // -func (m *Mapping) ToRelative(path string) string { +func (m *Mapping) ToRelative(fpath string) string { for _, e := range m.list { - if strings.HasPrefix(path, e.path) { + if strings.HasPrefix(fpath, e.path) { + spath := filepath.ToSlash(fpath) // /absolute/prefix/foo -> prefix/foo - return pathutil.Join(e.prefix, path[len(e.path):]) // Join will remove a trailing '/' + return path.Join(e.prefix, spath[len(e.path):]) // Join will remove a trailing '/' } } return "" // no match diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go index cc028cc4d..9517aee7a 100644 --- a/src/cmd/godoc/utils.go +++ b/src/cmd/godoc/utils.go @@ -10,7 +10,7 @@ import ( "io" "io/ioutil" "os" - pathutil "path" + "path/filepath" "sort" "strings" "sync" @@ -60,10 +60,10 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string { continue // ignore empty paths (don't assume ".") } // len(path) > 0: normalize path - if pathutil.IsAbs(path) { - path = pathutil.Clean(path) + if filepath.IsAbs(path) { + path = filepath.Clean(path) } else { - path = pathutil.Join(cwd, path) + path = filepath.Join(cwd, path) } // we have a non-empty absolute path if filter != nil && !filter(path) { @@ -95,7 +95,7 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string { // atomically renames that file to the file named by filename. // func writeFileAtomically(filename string, data []byte) os.Error { - f, err := ioutil.TempFile(cwd, filename) + f, err := ioutil.TempFile(filepath.Split(filename)) if err != nil { return err } @@ -149,7 +149,7 @@ var textExt = map[string]bool{ // func isTextFile(filename string) bool { // if the extension is known, use it for decision making - if isText, found := textExt[pathutil.Ext(filename)]; found { + if isText, found := textExt[filepath.Ext(filename)]; found { return isText } |