mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
godoc/redirect: support loading hg->git change map from a file
This isn't exposed through the godoc binary, as it will only be used by the Google-specific deployment of godoc. Change-Id: Id5808f3adcb7eb36a7ccd6e4960ce3f01179fe51 Reviewed-on: https://go-review.googlesource.com/1567 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
88d370fb93
commit
55402a2b46
138
godoc/redirect/hash.go
Normal file
138
godoc/redirect/hash.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// Copyright 2014 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 provides a compact encoding of
|
||||||
|
// a map of Mercurial hashes to Git hashes.
|
||||||
|
|
||||||
|
package redirect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// hashMap is a map of Mercurial hashes to Git hashes.
|
||||||
|
type hashMap struct {
|
||||||
|
file *os.File
|
||||||
|
entries int
|
||||||
|
}
|
||||||
|
|
||||||
|
// newHashMap takes a file handle that contains a map of Mercurial to Git
|
||||||
|
// hashes. The file should be a sequence of pairs of little-endian encoded
|
||||||
|
// uint32s, representing a hgHash and a gitHash respectively.
|
||||||
|
// The sequence must be sorted by hgHash.
|
||||||
|
// The file must remain open for as long as the returned hashMap is used.
|
||||||
|
func newHashMap(f *os.File) (*hashMap, error) {
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &hashMap{file: f, entries: int(fi.Size() / 8)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup finds an hgHash in the map that matches the given prefix, and returns
|
||||||
|
// its corresponding gitHash. The prefix must be at least 8 characters long.
|
||||||
|
func (m *hashMap) Lookup(s string) gitHash {
|
||||||
|
if m == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
hg, err := hgHashFromString(s)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var git gitHash
|
||||||
|
b := make([]byte, 8)
|
||||||
|
sort.Search(m.entries, func(i int) bool {
|
||||||
|
n, err := m.file.ReadAt(b, int64(i*8))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if n != 8 {
|
||||||
|
panic(io.ErrUnexpectedEOF)
|
||||||
|
}
|
||||||
|
v := hgHash(binary.LittleEndian.Uint32(b[:4]))
|
||||||
|
if v == hg {
|
||||||
|
git = gitHash(binary.LittleEndian.Uint32(b[4:]))
|
||||||
|
}
|
||||||
|
return v >= hg
|
||||||
|
})
|
||||||
|
return git
|
||||||
|
}
|
||||||
|
|
||||||
|
// hgHash represents the lower (leftmost) 32 bits of a Mercurial hash.
|
||||||
|
type hgHash uint32
|
||||||
|
|
||||||
|
func (h hgHash) String() string {
|
||||||
|
return intToHash(int64(h))
|
||||||
|
}
|
||||||
|
|
||||||
|
func hgHashFromString(s string) (hgHash, error) {
|
||||||
|
if len(s) < 8 {
|
||||||
|
return 0, fmt.Errorf("string too small: len(s) = %d", len(s))
|
||||||
|
}
|
||||||
|
hash := s[:8]
|
||||||
|
i, err := strconv.ParseInt(hash, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return hgHash(i), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// gitHash represents the leftmost 28 bits of a Git hash in its upper 28 bits,
|
||||||
|
// and it encodes hash's repository in the lower 4 bits.
|
||||||
|
type gitHash uint32
|
||||||
|
|
||||||
|
func (h gitHash) Hash() string {
|
||||||
|
return intToHash(int64(h))[:7]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h gitHash) Repo() string {
|
||||||
|
return repo(h & 0xF).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func intToHash(i int64) string {
|
||||||
|
s := strconv.FormatInt(i, 16)
|
||||||
|
if len(s) < 8 {
|
||||||
|
s = strings.Repeat("0", 8-len(s)) + s
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// repo represents a Go Git repository.
|
||||||
|
type repo byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
repoGo repo = iota
|
||||||
|
repoBlog
|
||||||
|
repoCrypto
|
||||||
|
repoExp
|
||||||
|
repoImage
|
||||||
|
repoMobile
|
||||||
|
repoNet
|
||||||
|
repoSys
|
||||||
|
repoTalks
|
||||||
|
repoText
|
||||||
|
repoTools
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r repo) String() string {
|
||||||
|
return map[repo]string{
|
||||||
|
repoGo: "go",
|
||||||
|
repoBlog: "blog",
|
||||||
|
repoCrypto: "crypto",
|
||||||
|
repoExp: "exp",
|
||||||
|
repoImage: "image",
|
||||||
|
repoMobile: "mobile",
|
||||||
|
repoNet: "net",
|
||||||
|
repoSys: "sys",
|
||||||
|
repoTalks: "talks",
|
||||||
|
repoText: "text",
|
||||||
|
repoTools: "tools",
|
||||||
|
}[r]
|
||||||
|
}
|
@ -8,7 +8,9 @@
|
|||||||
package redirect // import "golang.org/x/tools/godoc/redirect"
|
package redirect // import "golang.org/x/tools/godoc/redirect"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -33,6 +35,7 @@ func Register(mux *http.ServeMux) {
|
|||||||
// NB: /src/pkg (sans trailing slash) is the index of packages.
|
// NB: /src/pkg (sans trailing slash) is the index of packages.
|
||||||
mux.HandleFunc("/src/pkg/", srcPkgHandler)
|
mux.HandleFunc("/src/pkg/", srcPkgHandler)
|
||||||
mux.HandleFunc("/cl/", clHandler)
|
mux.HandleFunc("/cl/", clHandler)
|
||||||
|
mux.HandleFunc("/change/", changeHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
|
func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
|
||||||
@ -128,11 +131,6 @@ var redirects = map[string]string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var prefixHelpers = map[string]string{
|
var prefixHelpers = map[string]string{
|
||||||
// TODO(adg): add redirects from known hg hashes to the git equivalents
|
|
||||||
// and switch this to point to "https://go.googlesource.com/go/+/".
|
|
||||||
// (We can only change this once we know all the new git hashes.)
|
|
||||||
"change": "https://code.google.com/p/go/source/detail?r=",
|
|
||||||
|
|
||||||
"issue": "https://github.com/golang/go/issues/",
|
"issue": "https://github.com/golang/go/issues/",
|
||||||
"play": "http://play.golang.org/",
|
"play": "http://play.golang.org/",
|
||||||
"talks": "http://talks.golang.org/",
|
"talks": "http://talks.golang.org/",
|
||||||
@ -193,3 +191,39 @@ func clHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
http.Redirect(w, r, target, http.StatusFound)
|
http.Redirect(w, r, target, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var changeMap *hashMap
|
||||||
|
|
||||||
|
// LoadChangeMap loads the specified map of Mercurial to Git revisions,
|
||||||
|
// which is used by the /change/ handler to intelligently map old hg
|
||||||
|
// revisions to their new git equivalents.
|
||||||
|
// It should be called before calling Register.
|
||||||
|
// The file should remain open as long as the process is running.
|
||||||
|
// See the implementation of this package for details.
|
||||||
|
func LoadChangeMap(filename string) error {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m, err := newHashMap(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
changeMap = m
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
const prefix = "/change/"
|
||||||
|
if p := r.URL.Path; p == prefix {
|
||||||
|
// redirect /prefix/ to /prefix
|
||||||
|
http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hash := r.URL.Path[len(prefix):]
|
||||||
|
target := "https://go.googlesource.com/go/+/" + hash
|
||||||
|
if git := changeMap.Lookup(hash); git > 0 {
|
||||||
|
target = fmt.Sprintf("https://go.googlesource.com/%v/+/%v", git.Repo(), git.Hash())
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, target, http.StatusFound)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user