diff options
| author | Russ Cox <rsc@golang.org> | 2021-02-26 01:53:00 -0500 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2021-06-14 17:41:38 +0000 |
| commit | 5ee419f2eadb4e9213f52ffc1f6fea62bb55fbb7 (patch) | |
| tree | 16a235ec5ef361c53b1ca58034adc77a119882a9 | |
| parent | 4b5486d0e5c44f3e96aea9d5d8a00185872c416f (diff) | |
| download | go-x-website-5ee419f2eadb4e9213f52ffc1f6fea62bb55fbb7.tar.xz | |
all: remove toFS usage
The toFS calls were a stop-gap to convert from old code that wasn't
strict about path forms to the io/fs routines that are more strict.
Arrange to pass io/fs-compatible paths everywhere and remove toFS.
Change-Id: Id69c0f23074ebd3a6dfef2255b2f8185ad1d1249
Reviewed-on: https://go-review.googlesource.com/c/website/+/317659
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
| -rw-r--r-- | _content/lib/godoc/package.html | 2 | ||||
| -rw-r--r-- | cmd/golangorg/codewalk.go | 25 | ||||
| -rw-r--r-- | cmd/golangorg/handlers.go | 9 | ||||
| -rw-r--r-- | cmd/golangorg/main.go | 2 | ||||
| -rw-r--r-- | internal/pkgdoc/dir.go | 45 | ||||
| -rw-r--r-- | internal/pkgdoc/dir_test.go | 4 | ||||
| -rw-r--r-- | internal/pkgdoc/doc.go | 29 | ||||
| -rw-r--r-- | internal/pkgdoc/doc_test.go | 4 | ||||
| -rw-r--r-- | internal/web/docfuncs.go | 24 | ||||
| -rw-r--r-- | internal/web/file.go | 52 | ||||
| -rw-r--r-- | internal/web/pkgdoc.go | 5 | ||||
| -rw-r--r-- | internal/web/site.go | 38 |
12 files changed, 101 insertions, 138 deletions
diff --git a/_content/lib/godoc/package.html b/_content/lib/godoc/package.html index 3d6e8ba9..7efdea11 100644 --- a/_content/lib/godoc/package.html +++ b/_content/lib/godoc/package.html @@ -95,7 +95,7 @@ <p> <span style="font-size:90%"> {{range .}} - <a href="/src/{{.}}">{{basename .}}</a> + <a href="/{{.}}">{{basename .}}</a> {{end}} </span> </p> diff --git a/cmd/golangorg/codewalk.go b/cmd/golangorg/codewalk.go index 52deb299..d3e5cbd1 100644 --- a/cmd/golangorg/codewalk.go +++ b/cmd/golangorg/codewalk.go @@ -25,6 +25,7 @@ import ( "log" "net/http" "os" + "path" pathpkg "path" "regexp" "sort" @@ -37,8 +38,7 @@ import ( // Handler for /doc/codewalk/ and below. func codewalk(w http.ResponseWriter, r *http.Request) { - relpath := r.URL.Path[len("/doc/codewalk/"):] - abspath := r.URL.Path + relpath := path.Clean(r.URL.Path[1:]) r.ParseForm() if f := r.FormValue("fileprint"); f != "" { @@ -47,9 +47,9 @@ func codewalk(w http.ResponseWriter, r *http.Request) { } // If directory exists, serve list of code walks. - dir, err := fs.Stat(fsys, toFS(abspath)) + dir, err := fs.Stat(fsys, relpath) if err == nil && dir.IsDir() { - codewalkDir(w, r, relpath, abspath) + codewalkDir(w, r, relpath) return } @@ -62,8 +62,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) { // Otherwise append .xml and hope to find // a codewalk description, but before trim // the trailing /. - abspath = strings.TrimRight(abspath, "/") - cw, err := loadCodewalk(abspath + ".xml") + cw, err := loadCodewalk(relpath + ".xml") if err != nil { log.Print(err) site.ServeError(w, r, err) @@ -140,7 +139,7 @@ func (st *Codestep) String() string { // loadCodewalk reads a codewalk from the named XML file. func loadCodewalk(filename string) (*Codewalk, error) { - f, err := fsys.Open(toFS(filename)) + f, err := fsys.Open(filename) if err != nil { return nil, err } @@ -161,7 +160,7 @@ func loadCodewalk(filename string) (*Codewalk, error) { i = len(st.Src) } filename := st.Src[0:i] - data, err := fs.ReadFile(fsys, toFS(filename)) + data, err := fs.ReadFile(fsys, filename) if err != nil { st.Err = err continue @@ -202,13 +201,13 @@ func loadCodewalk(filename string) (*Codewalk, error) { // codewalkDir serves the codewalk directory listing. // It scans the directory for subdirectories or files named *.xml // and prepares a table. -func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) { +func codewalkDir(w http.ResponseWriter, r *http.Request, relpath string) { type elem struct { Name string Title string } - dir, err := fs.ReadDir(fsys, toFS(abspath)) + dir, err := fs.ReadDir(fsys, relpath) if err != nil { log.Print(err) site.ServeError(w, r, err) @@ -220,7 +219,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string if fi.IsDir() { v = append(v, &elem{name + "/", ""}) } else if strings.HasSuffix(name, ".xml") { - cw, err := loadCodewalk(abspath + "/" + name) + cw, err := loadCodewalk(relpath + "/" + name) if err != nil { continue } @@ -242,8 +241,8 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string // of the codewalk pages. It is a separate iframe and does not get // the usual godoc HTML wrapper. func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) { - abspath := f - data, err := fs.ReadFile(fsys, toFS(abspath)) + relpath := strings.Trim(path.Clean(f), "/") + data, err := fs.ReadFile(fsys, relpath) if err != nil { log.Print(err) site.ServeError(w, r, err) diff --git a/cmd/golangorg/handlers.go b/cmd/golangorg/handlers.go index 1ea84789..ee2cb77f 100644 --- a/cmd/golangorg/handlers.go +++ b/cmd/golangorg/handlers.go @@ -12,7 +12,6 @@ import ( "go/format" "io/fs" "net/http" - pathpkg "path" "strings" "golang.org/x/website/internal/env" @@ -25,14 +24,6 @@ var ( fsys fs.FS ) -// toFS returns the io/fs name for path (no leading slash). -func toFS(path string) string { - if path == "/" { - return "." - } - return pathpkg.Clean(strings.TrimPrefix(path, "/")) -} - // hostEnforcerHandler redirects requests to "http://foo.golang.org/bar" // to "https://golang.org/bar". // It permits requests to the host "godoc-test.golang.org" for testing and diff --git a/cmd/golangorg/main.go b/cmd/golangorg/main.go index 7e832d53..37d9d8b6 100644 --- a/cmd/golangorg/main.go +++ b/cmd/golangorg/main.go @@ -137,7 +137,7 @@ func (fsys unionFS) ReadDir(name string) ([]fs.DirEntry, error) { var seen map[string]bool // seen[name] is true if name is listed in all; lazily initialized var errOut error for _, sub := range fsys { - list, err := fs.ReadDir(sub, toFS(name)) + list, err := fs.ReadDir(sub, name) if err != nil { errOut = err } diff --git a/internal/pkgdoc/dir.go b/internal/pkgdoc/dir.go index e8b2c618..fe995e2f 100644 --- a/internal/pkgdoc/dir.go +++ b/internal/pkgdoc/dir.go @@ -22,14 +22,6 @@ import ( "strings" ) -// toFS returns the io/fs name for path (no leading slash). -func toFS(name string) string { - if name == "/" { - return "." - } - return path.Clean(strings.TrimPrefix(name, "/")) -} - type Dir struct { Path string // directory path HasPkg bool // true if the directory contains at least one package @@ -65,17 +57,15 @@ func (dir *Dir) Lookup(name string) *Dir { if name == dir.Path { return dir } - dirPathLen := len(dir.Path) - if dir.Path == "/" { - dirPathLen = 0 // so path[dirPathLen] is a slash - } - if !strings.HasPrefix(name, dir.Path) || name[dirPathLen] != '/' { - println("NO", name, dir.Path) - return nil + if dir.Path != "." { + if !strings.HasPrefix(name, dir.Path) || name[len(dir.Path)] != '/' { + return nil + } + name = name[len(dir.Path)+1:] } d := dir Walk: - for i := dirPathLen + 1; i <= len(name); i++ { + for i := 0; i <= len(name); i++ { if i == len(name) || name[i] == '/' { // Find next child along path. for _, sub := range d.Dirs { @@ -84,7 +74,6 @@ Walk: continue Walk } } - println("LOST", name[:i]) return nil } } @@ -126,16 +115,16 @@ func (dir *Dir) List(filter func(string) bool) *DirList { return &DirList{list} } -func newDir(fsys fs.FS, fset *token.FileSet, abspath string) *Dir { +func newDir(fsys fs.FS, fset *token.FileSet, dirpath string) *Dir { var synopses [3]string // prioritized package documentation (0 == highest priority) hasPkgFiles := false haveSummary := false - list, err := fs.ReadDir(fsys, toFS(abspath)) + list, err := fs.ReadDir(fsys, dirpath) if err != nil { // TODO: propagate more. See golang.org/issue/14252. - log.Printf("newDirTree reading %s: %v", abspath, err) + log.Printf("newDirTree reading %s: %v", dirpath, err) } // determine number of subdirectories and if there are package files @@ -143,7 +132,7 @@ func newDir(fsys fs.FS, fset *token.FileSet, abspath string) *Dir { var dirs []*Dir for _, d := range list { - filename := path.Join(abspath, d.Name()) + filename := path.Join(dirpath, d.Name()) switch { case isPkgDir(d): dir := newDir(fsys, fset, filename) @@ -168,7 +157,7 @@ func newDir(fsys fs.FS, fset *token.FileSet, abspath string) *Dir { // prioritize documentation i := -1 switch file.Name.Name { - case path.Base(abspath): + case path.Base(dirpath): i = 0 // normal case: directory name matches package name case "main": i = 1 // directory contains a main package @@ -211,7 +200,7 @@ func newDir(fsys fs.FS, fset *token.FileSet, abspath string) *Dir { } return &Dir{ - Path: abspath, + Path: dirpath, HasPkg: hasPkgFiles, Synopsis: synopsis, Dirs: dirs, @@ -247,7 +236,7 @@ func walkDirs(f func(d *Dir, depth int), d *Dir, depth int) { } func parseFile(fsys fs.FS, fset *token.FileSet, filename string, mode parser.Mode) (*ast.File, error) { - src, err := fs.ReadFile(fsys, toFS(filename)) + src, err := fs.ReadFile(fsys, filename) if err != nil { return nil, err } @@ -259,15 +248,15 @@ func parseFile(fsys fs.FS, fset *token.FileSet, filename string, mode parser.Mod return parser.ParseFile(fset, filename, src, mode) } -func parseFiles(fsys fs.FS, fset *token.FileSet, relpath string, abspath string, localnames []string) (map[string]*ast.File, error) { +func parseFiles(fsys fs.FS, fset *token.FileSet, dirname string, localnames []string) (map[string]*ast.File, error) { files := make(map[string]*ast.File) for _, f := range localnames { - absname := path.Join(abspath, f) - file, err := parseFile(fsys, fset, absname, parser.ParseComments) + filename := path.Join(dirname, f) + file, err := parseFile(fsys, fset, filename, parser.ParseComments) if err != nil { return nil, err } - files[path.Join(relpath, f)] = file + files[filename] = file } return files, nil diff --git a/internal/pkgdoc/dir_test.go b/internal/pkgdoc/dir_test.go index 94412746..db1c7821 100644 --- a/internal/pkgdoc/dir_test.go +++ b/internal/pkgdoc/dir_test.go @@ -17,7 +17,7 @@ import ( ) func TestNewDirTree(t *testing.T) { - dir := newDir(os.DirFS(runtime.GOROOT()), token.NewFileSet(), "/src") + dir := newDir(os.DirFS(runtime.GOROOT()), token.NewFileSet(), "src") processDir(t, dir) } @@ -62,6 +62,6 @@ func BenchmarkNewDirectory(b *testing.B) { b.ResetTimer() b.ReportAllocs() for tries := 0; tries < b.N; tries++ { - newDir(fs, token.NewFileSet(), "/src") + newDir(fs, token.NewFileSet(), "src") } } diff --git a/internal/pkgdoc/doc.go b/internal/pkgdoc/doc.go index 02e7b5b3..218228ea 100644 --- a/internal/pkgdoc/doc.go +++ b/internal/pkgdoc/doc.go @@ -32,9 +32,9 @@ type Docs struct { } func NewDocs(fsys fs.FS) *Docs { - src := newDir(fsys, token.NewFileSet(), "/src") + src := newDir(fsys, token.NewFileSet(), "src") root := &Dir{ - Path: "/", + Path: ".", Dirs: []*Dir{src}, } return &Docs{ @@ -112,14 +112,15 @@ func ParseMode(text string) Mode { return mode } -// Doc returns the Page for a package directory abspath. +// Doc returns the Page for a package directory dir. // Package documentation (Page.PDoc) is extracted from the AST. // If there is no corresponding package in the // directory, Page.PDoc is nil. If there are no sub- // directories, Page.Dirs is nil. If an error occurred, PageInfo.Err is // set to the respective error but the error is not logged. -func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page { - info := &Page{Dirname: abspath, Mode: mode} +func Doc(d *Docs, dir string, mode Mode, goos, goarch string) *Page { + dir = path.Clean(dir) + info := &Page{Dirname: dir, Mode: mode} // Restrict to the package files that would be used when building // the package on this system. This makes sure that if there are @@ -130,11 +131,11 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page ctxt := build.Default ctxt.IsAbsPath = path.IsAbs ctxt.IsDir = func(path string) bool { - fi, err := fs.Stat(d.fs, toFS(filepath.ToSlash(path))) + fi, err := fs.Stat(d.fs, filepath.ToSlash(path)) return err == nil && fi.IsDir() } ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) { - f, err := fs.ReadDir(d.fs, toFS(filepath.ToSlash(dir))) + f, err := fs.ReadDir(d.fs, filepath.ToSlash(dir)) filtered := make([]os.FileInfo, 0, len(f)) for _, i := range f { if mode&ModeAll != 0 || i.Name() != "internal" { @@ -147,7 +148,7 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page return filtered, err } ctxt.OpenFile = func(name string) (r io.ReadCloser, err error) { - data, err := fs.ReadFile(d.fs, toFS(filepath.ToSlash(name))) + data, err := fs.ReadFile(d.fs, filepath.ToSlash(name)) if err != nil { return nil, err } @@ -159,7 +160,7 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page // linux/amd64 means the wasm syscall/js package was blank. // And you can't run godoc on js/wasm anyway, so host defaults // don't make sense here. - if goos == "" && goarch == "" && relpath == "syscall/js" { + if goos == "" && goarch == "" && dir == "syscall/js" { goos, goarch = "js", "wasm" } if goos != "" { @@ -169,7 +170,7 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page ctxt.GOARCH = goarch } - pkginfo, err := ctxt.ImportDir(abspath, 0) + pkginfo, err := ctxt.ImportDir(dir, 0) // continue if there are no Go source files; we still want the directory info if _, nogo := err.(*build.NoGoError); err != nil && !nogo { info.Err = err @@ -193,7 +194,7 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page if len(pkgfiles) > 0 { // build package AST fset := token.NewFileSet() - files, err := parseFiles(d.fs, fset, relpath, abspath, pkgfiles) + files, err := parseFiles(d.fs, fset, dir, pkgfiles) if err != nil { info.Err = err return info @@ -213,7 +214,7 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page if mode&ModeMethods != 0 { m |= doc.AllMethods } - info.PDoc = doc.New(pkg, path.Clean(relpath), m) // no trailing '/' in importpath + info.PDoc = doc.New(pkg, strings.TrimPrefix(dir, "src/"), m) if mode&ModeBuiltin != 0 { for _, t := range info.PDoc.Types { info.PDoc.Consts = append(info.PDoc.Consts, t.Consts...) @@ -230,7 +231,7 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page // collect examples testfiles := append(pkginfo.TestGoFiles, pkginfo.XTestGoFiles...) - files, err = parseFiles(d.fs, fset, relpath, abspath, testfiles) + files, err = parseFiles(d.fs, fset, dir, testfiles) if err != nil { log.Println("parsing examples:", err) } @@ -238,7 +239,7 @@ func Doc(d *Docs, abspath, relpath string, mode Mode, goos, goarch string) *Page info.Bugs = info.PDoc.Notes["BUG"] } - info.Dirs = d.root.Lookup(abspath).List(func(path string) bool { return d.includePath(path, mode) }) + info.Dirs = d.root.Lookup(dir).List(func(path string) bool { return d.includePath(path, mode) }) info.DirFlat = mode&ModeFlat != 0 return info diff --git a/internal/pkgdoc/doc_test.go b/internal/pkgdoc/doc_test.go index c82d042e..1ac4f0a3 100644 --- a/internal/pkgdoc/doc_test.go +++ b/internal/pkgdoc/doc_test.go @@ -25,7 +25,7 @@ func TestIgnoredGoFiles(t *testing.T) { package main`)}, } d := NewDocs(fs) - pInfo := Doc(d, "/src/"+packagePath, packagePath, ModeAll, "linux", "amd64") + pInfo := Doc(d, "src/"+packagePath, ModeAll, "linux", "amd64") if pInfo.PDoc == nil { t.Error("pInfo.PDoc = nil; want non-nil.") @@ -58,7 +58,7 @@ func F() } d := NewDocs(fs) - pInfo := Doc(d, "/src/"+packagePath, packagePath, 0, "linux", "amd64") + pInfo := Doc(d, "src/"+packagePath, 0, "linux", "amd64") if got, want := pInfo.PDoc.Funcs[0].Doc, "F doc //line 1 should appear\nline 2 should appear\n"; got != want { t.Errorf("pInfo.PDoc.Funcs[0].Doc = %q; want %q", got, want) } diff --git a/internal/web/docfuncs.go b/internal/web/docfuncs.go index a11190f8..1f7850eb 100644 --- a/internal/web/docfuncs.go +++ b/internal/web/docfuncs.go @@ -13,6 +13,7 @@ import ( "html/template" "io/fs" "log" + "path" "regexp" "strings" @@ -34,7 +35,12 @@ func (s *Site) code(file string, arg ...interface{}) (_ template.HTML, err error } }() - text := s.contents(file) + file = path.Clean(strings.TrimPrefix(file, "/")) + btext, err := fs.ReadFile(s.fs, file) + if err != nil { + return "", err + } + text := string(btext) var command string switch len(arg) { case 0: @@ -64,16 +70,6 @@ func (s *Site) code(file string, arg ...interface{}) (_ template.HTML, err error // Functions in this file panic on error, but the panic is recovered // to an error by 'code'. -// contents reads and returns the content of the named file -// (from the virtual file system, so for example /doc refers to $GOROOT/doc). -func (s *Site) contents(name string) string { - file, err := fs.ReadFile(s.fs, toFS(name)) - if err != nil { - log.Panic(err) - } - return string(file) -} - // stringFor returns a textual representation of the arg, formatted according to its nature. func stringFor(arg interface{}) string { switch arg := arg.(type) { @@ -92,7 +88,7 @@ func stringFor(arg interface{}) string { // oneLine returns the single line generated by a two-argument code invocation. func (s *Site) oneLine(file, text string, arg interface{}) string { - lines := strings.SplitAfter(s.contents(file), "\n") + lines := strings.SplitAfter(text, "\n") line, pattern, isInt := parseArg(arg, file, len(lines)) if isInt { return lines[line-1] @@ -102,7 +98,7 @@ func (s *Site) oneLine(file, text string, arg interface{}) string { // multipleLines returns the text generated by a three-argument code invocation. func (s *Site) multipleLines(file, text string, arg1, arg2 interface{}) string { - lines := strings.SplitAfter(s.contents(file), "\n") + lines := strings.SplitAfter(text, "\n") line1, pattern1, isInt1 := parseArg(arg1, file, len(lines)) line2, pattern2, isInt2 := parseArg(arg2, file, len(lines)) if !isInt1 { @@ -111,7 +107,7 @@ func (s *Site) multipleLines(file, text string, arg1, arg2 interface{}) string { if !isInt2 { line2 = match(file, line1, lines, pattern2) } else if line2 < line1 { - log.Panicf("lines out of order for %q: %d %d", text, line1, line2) + log.Panicf("lines out of order for %q: %d %d", file, line1, line2) } for k := line1 - 1; k < line2; k++ { if strings.HasSuffix(lines[k], "OMIT\n") { diff --git a/internal/web/file.go b/internal/web/file.go index f2ff605f..c82ff854 100644 --- a/internal/web/file.go +++ b/internal/web/file.go @@ -34,25 +34,23 @@ type fileJSON struct { Redirect string // if set, redirect to other URL } -var join = path.Join - -// open returns the file for a given absolute path or nil if none exists. -func open(fsys fs.FS, path string) *file { +// open returns the *file for a given relative path or nil if none exists. +func open(fsys fs.FS, relpath string) *file { // Strip trailing .html or .md or /; it all names the same page. - if strings.HasSuffix(path, ".html") { - path = strings.TrimSuffix(path, ".html") - } else if strings.HasSuffix(path, ".md") { - path = strings.TrimSuffix(path, ".md") - } else if path != "/" && strings.HasSuffix(path, "/") { - path = strings.TrimSuffix(path, "/") + if strings.HasSuffix(relpath, ".html") { + relpath = strings.TrimSuffix(relpath, ".html") + } else if strings.HasSuffix(relpath, ".md") { + relpath = strings.TrimSuffix(relpath, ".md") + } else if strings.HasSuffix(relpath, "/") { + relpath = strings.TrimSuffix(relpath, "/") } - files := []string{path + ".html", path + ".md", join(path, "index.html"), join(path, "index.md")} + files := []string{relpath + ".html", relpath + ".md", path.Join(relpath, "index.html"), path.Join(relpath, "index.md")} var filePath string var b []byte var err error for _, filePath = range files { - b, err = fs.ReadFile(fsys, toFS(filePath)) + b, err = fs.ReadFile(fsys, filePath) if err == nil { break } @@ -60,14 +58,14 @@ func open(fsys fs.FS, path string) *file { // Special case for memory model and spec, which live // in the main Go repo's doc directory and therefore have not - // been renamed to their serving paths. + // been renamed to their serving relpaths. // We wait until the ReadFiles above have failed so that the // code works if these are ever moved to /ref/spec and /ref/mem. - if err != nil && path == "/ref/spec" { - return open(fsys, "/doc/go_spec") + if err != nil && relpath == "ref/spec" { + return open(fsys, "doc/go_spec") } - if err != nil && path == "/ref/mem" { - return open(fsys, "/doc/go_mem") + if err != nil && relpath == "ref/mem" { + return open(fsys, "doc/go_mem") } if err != nil { @@ -75,21 +73,21 @@ func open(fsys fs.FS, path string) *file { } // Special case for memory model and spec, continued. - switch path { - case "/doc/go_spec": - path = "/ref/spec" - case "/doc/go_mem": - path = "/ref/mem" + switch relpath { + case "doc/go_spec": + relpath = "ref/spec" + case "doc/go_mem": + relpath = "ref/mem" } - // If we read an index.md or index.html, the canonical path is without the index.md/index.html suffix. - if strings.HasSuffix(filePath, "/index.md") || strings.HasSuffix(filePath, "/index.html") { - path = filePath[:strings.LastIndex(filePath, "/")+1] + // If we read an index.md or index.html, the canonical relpath is without the index.md/index.html suffix. + if name := path.Base(filePath); name == "index.html" || name == "index.md" { + relpath, _ = path.Split(filePath) } js, body, err := parseFile(b) if err != nil { - log.Printf("extractMetadata %s: %v", path, err) + log.Printf("extractMetadata %s: %v", relpath, err) return nil } @@ -97,7 +95,7 @@ func open(fsys fs.FS, path string) *file { Title: js.Title, Subtitle: js.Subtitle, Template: js.Template, - Path: path, + Path: "/" + relpath, FilePath: filePath, Body: body, } diff --git a/internal/web/pkgdoc.go b/internal/web/pkgdoc.go index c0b5e916..32949f44 100644 --- a/internal/web/pkgdoc.go +++ b/internal/web/pkgdoc.go @@ -31,7 +31,6 @@ func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { relpath := path.Clean(strings.TrimPrefix(r.URL.Path, "/pkg")) relpath = strings.TrimPrefix(relpath, "/") - abspath := path.Join("/src", relpath) mode := pkgdoc.ParseMode(r.FormValue("m")) if relpath == "builtin" { // The fake built-in package contains unexported identifiers, @@ -39,7 +38,7 @@ func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { // since it's not helpful for this fake package (see issue 6645). mode |= pkgdoc.ModeAll | pkgdoc.ModeBuiltin } - info := pkgdoc.Doc(h.d, abspath, relpath, mode, r.FormValue("GOOS"), r.FormValue("GOARCH")) + info := pkgdoc.Doc(h.d, "src/"+relpath, mode, r.FormValue("GOOS"), r.FormValue("GOARCH")) if info.Err != nil { log.Print(info.Err) h.p.ServeError(w, r, info.Err) @@ -76,7 +75,7 @@ func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { } name := "package.html" - if info.Dirname == "/src" { + if info.Dirname == "src" { name = "packageroot.html" } h.p.ServePage(w, r, Page{ diff --git a/internal/web/site.go b/internal/web/site.go index 57567144..1ad8948c 100644 --- a/internal/web/site.go +++ b/internal/web/site.go @@ -28,14 +28,6 @@ import ( "golang.org/x/website/internal/texthtml" ) -// toFS returns the io/fs name for path (no leading slash). -func toFS(name string) string { - if name == "/" { - return "." - } - return path.Clean(strings.TrimPrefix(name, "/")) -} - // Site is a website served from a file system. type Site struct { fs fs.FS @@ -204,7 +196,8 @@ func (s *Site) serveFile(w http.ResponseWriter, r *http.Request) { // Check to see if we need to redirect or serve another file. abspath := r.URL.Path - if f := open(s.fs, abspath); f != nil { + relpath := path.Clean(strings.TrimPrefix(abspath, "/")) + if f := open(s.fs, relpath); f != nil { if f.Path != abspath { // Redirect to canonical path. http.Redirect(w, r, f.Path, http.StatusMovedPermanently) @@ -215,16 +208,14 @@ func (s *Site) serveFile(w http.ResponseWriter, r *http.Request) { return } - relpath := abspath[1:] // strip leading slash - - dir, err := fs.Stat(s.fs, toFS(abspath)) + dir, err := fs.Stat(s.fs, relpath) if err != nil { // Check for spurious trailing slash. if strings.HasSuffix(abspath, "/") { - trimmed := abspath[:len(abspath)-1] - if _, err := fs.Stat(s.fs, toFS(trimmed)); err == nil || + trimmed := relpath[:len(relpath)-1] + if _, err := fs.Stat(s.fs, trimmed); err == nil || open(s.fs, trimmed) != nil { - http.Redirect(w, r, trimmed, http.StatusMovedPermanently) + http.Redirect(w, r, "/"+trimmed, http.StatusMovedPermanently) return } } @@ -232,20 +223,19 @@ func (s *Site) serveFile(w http.ResponseWriter, r *http.Request) { return } - fsPath := toFS(abspath) if dir != nil && dir.IsDir() { if maybeRedirect(w, r) { return } - s.serveDir(w, r, abspath, relpath) + s.serveDir(w, r, relpath) return } - if isTextFile(s.fs, fsPath) { + if isTextFile(s.fs, relpath) { if maybeRedirectFile(w, r) { return } - s.serveText(w, r, abspath, relpath) + s.serveText(w, r, relpath) return } @@ -337,12 +327,12 @@ func (s *Site) serveHTML(w http.ResponseWriter, r *http.Request, f *file) { s.ServePage(w, r, page) } -func (s *Site) serveDir(w http.ResponseWriter, r *http.Request, abspath, relpath string) { +func (s *Site) serveDir(w http.ResponseWriter, r *http.Request, relpath string) { if maybeRedirect(w, r) { return } - list, err := fs.ReadDir(s.fs, toFS(abspath)) + list, err := fs.ReadDir(s.fs, relpath) if err != nil { s.ServeError(w, r, err) return @@ -365,8 +355,8 @@ func (s *Site) serveDir(w http.ResponseWriter, r *http.Request, abspath, relpath }) } -func (s *Site) serveText(w http.ResponseWriter, r *http.Request, abspath, relpath string) { - src, err := fs.ReadFile(s.fs, toFS(abspath)) +func (s *Site) serveText(w http.ResponseWriter, r *http.Request, relpath string) { + src, err := fs.ReadFile(s.fs, relpath) if err != nil { log.Printf("ReadFile: %s", err) s.ServeError(w, r, err) @@ -379,7 +369,7 @@ func (s *Site) serveText(w http.ResponseWriter, r *http.Request, abspath, relpat } cfg := texthtml.Config{ - GoComments: path.Ext(abspath) == ".go", + GoComments: path.Ext(relpath) == ".go", Highlight: r.FormValue("h"), Selection: rangeSelection(r.FormValue("s")), Line: 1, |
