mirror of
https://github.com/golang/go
synced 2024-11-22 01:04:40 -07:00
Steps towards more flexible godoc:
The Mapping object implements a flexible mapping of relative to absolute paths and vice versa. R=rsc CC=golang-dev https://golang.org/cl/206067
This commit is contained in:
parent
494bcc80e4
commit
a91fa9d52e
176
src/cmd/godoc/mapping.go
Normal file
176
src/cmd/godoc/mapping.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file implements the Mapping data structure.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
pathutil "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// A Mapping object maps relative paths (e.g. from URLs)
|
||||||
|
// to absolute paths (of the file system) and vice versa.
|
||||||
|
//
|
||||||
|
// A Mapping object consists of a list of individual mappings
|
||||||
|
// of the form: prefix -> path which are interpreted as follows:
|
||||||
|
// A relative path of the form prefix/tail is to be mapped to
|
||||||
|
// the absolute path/tail, if that absolute path exists in the file
|
||||||
|
// system. Given a Mapping object, a relative path is mapped to an
|
||||||
|
// absolute path by trying each of the individual mappings in order,
|
||||||
|
// until a valid mapping is found. For instance, for the mapping:
|
||||||
|
//
|
||||||
|
// user -> /home/user
|
||||||
|
// public -> /home/user/public
|
||||||
|
// public -> /home/build/public
|
||||||
|
//
|
||||||
|
// the relative paths below are mapped to absolute paths as follows:
|
||||||
|
//
|
||||||
|
// user/foo -> /home/user/foo
|
||||||
|
// public/net/rpc/file1.go -> /home/user/public/net/rpc/file1.go
|
||||||
|
//
|
||||||
|
// If there is no /home/user/public/net/rpc/file2.go, the next public
|
||||||
|
// mapping entry is used to map the relative path to:
|
||||||
|
//
|
||||||
|
// public/net/rpc/file2.go -> /home/build/public/net/rpc/file2.go
|
||||||
|
//
|
||||||
|
// (assuming that file exists).
|
||||||
|
//
|
||||||
|
type Mapping struct {
|
||||||
|
list []mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type mapping struct {
|
||||||
|
prefix, path string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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:
|
||||||
|
//
|
||||||
|
// dirname/localname
|
||||||
|
//
|
||||||
|
// a mapping
|
||||||
|
//
|
||||||
|
// localname -> path
|
||||||
|
//
|
||||||
|
// is added to the Mapping object, in the order of occurrence.
|
||||||
|
// For instance, the argument:
|
||||||
|
//
|
||||||
|
// /home/user:/home/build/public
|
||||||
|
//
|
||||||
|
// leads to the following mapping:
|
||||||
|
//
|
||||||
|
// user -> /home/user
|
||||||
|
// public -> /home/build/public
|
||||||
|
//
|
||||||
|
func (m *Mapping) Init(paths string) {
|
||||||
|
cwd, _ := os.Getwd() // ignore errors
|
||||||
|
|
||||||
|
pathlist := strings.Split(paths, ":", 0)
|
||||||
|
|
||||||
|
list := make([]mapping, len(pathlist))
|
||||||
|
n := 0 // number of mappings
|
||||||
|
|
||||||
|
for _, path := range pathlist {
|
||||||
|
if len(path) == 0 {
|
||||||
|
// ignore empty paths (don't assume ".")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// len(path) > 0: normalize path
|
||||||
|
if path[0] != '/' {
|
||||||
|
path = pathutil.Join(cwd, path)
|
||||||
|
} else {
|
||||||
|
path = pathutil.Clean(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if mapping exists already
|
||||||
|
var i int
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
if path == list[i].path {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add mapping if it is new
|
||||||
|
if i >= n {
|
||||||
|
_, prefix := pathutil.Split(path)
|
||||||
|
list[i] = mapping{prefix, path}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.list = list[0:n]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// IsEmpty returns true if there are no mappings specified.
|
||||||
|
func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }
|
||||||
|
|
||||||
|
|
||||||
|
// Fprint prints the mapping.
|
||||||
|
func (m *Mapping) Fprint(w io.Writer) {
|
||||||
|
for _, e := range m.list {
|
||||||
|
fmt.Fprintf(w, "\t%s -> %s\n", e.prefix, e.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func split(path string) (head, tail string) {
|
||||||
|
i := strings.Index(path, "/")
|
||||||
|
if i > 0 {
|
||||||
|
// 0 < i < len(path)
|
||||||
|
return path[0:i], path[i+1:]
|
||||||
|
}
|
||||||
|
return "", path
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
func (m *Mapping) ToAbsolute(path string) string {
|
||||||
|
for _, e := range m.list {
|
||||||
|
if strings.HasPrefix(path, e.path) {
|
||||||
|
// /absolute/prefix/foo -> prefix/foo
|
||||||
|
return pathutil.Join(e.prefix, path[len(e.path):]) // Join will remove a trailing '/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "" // no match
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
func (m *Mapping) ToRelative(path string) string {
|
||||||
|
prefix, tail := split(path)
|
||||||
|
for _, e := range m.list {
|
||||||
|
switch {
|
||||||
|
case e.prefix == prefix:
|
||||||
|
// use tail
|
||||||
|
case e.prefix == "":
|
||||||
|
tail = path
|
||||||
|
default:
|
||||||
|
continue // no match
|
||||||
|
}
|
||||||
|
abspath := pathutil.Join(e.path, tail)
|
||||||
|
if _, err := os.Stat(abspath); err == nil {
|
||||||
|
return abspath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "" // no match
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user