cmd/godoc: bake templates and scripts into godoc binary

Add godoc/vfs/mapfs package for serving baked files.

Fixes golang/go#6010.

R=golang-dev, bradfitz, r, arnehormann, rsc
CC=golang-dev
https://golang.org/cl/12978043
This commit is contained in:
Andrew Gerrand 2013-08-16 11:44:27 +10:00
Родитель dfa65ded17
Коммит 562e4faeca
5 изменённых файлов: 2117 добавлений и 7 удалений

64
cmd/godoc/bake.go Normal file
Просмотреть файл

@ -0,0 +1,64 @@
// Copyright 2013 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.
// +build ignore
// Command bake takes a list of file names and writes a Go source file to
// standard output that declares a map of string constants containing the input files.
//
// For example, the command
// bake foo.html bar.txt
// produces a source file in package main that declares the variable bakedFiles
// that is a map with keys "foo.html" and "bar.txt" that contain the contents
// of foo.html and bar.txt.
package main
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"unicode/utf8"
)
func main() {
if err := bake(os.Args[1:]); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func bake(files []string) error {
w := bufio.NewWriter(os.Stdout)
fmt.Fprintf(w, "%v\n\npackage main\n\n", warning)
fmt.Fprintf(w, "var bakedFiles = map[string]string{\n")
for _, fn := range files {
b, err := ioutil.ReadFile(fn)
if err != nil {
return err
}
if !utf8.Valid(b) {
return fmt.Errorf("file %s is not valid UTF-8", fn)
}
fmt.Fprintf(w, "\t%q: `%s`,\n", filepath.Base(fn), sanitize(b))
}
fmt.Fprintln(w, "}")
return w.Flush()
}
// sanitize prepares a string as a raw string constant.
func sanitize(b []byte) []byte {
// Replace ` with `+"`"+`
b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)
// Replace BOM with `+"\xEF\xBB\xBF"+`
// (A BOM is valid UTF-8 but not permitted in Go source files.
// I wouldn't bother handling this, but for some insane reason
// jquery.js has a BOM somewhere in the middle.)
return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
}
const warning = "// DO NOT EDIT ** This file was generated with the bake tool ** DO NOT EDIT //"

9
cmd/godoc/bake.sh Executable file
Просмотреть файл

@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Copyright 2013 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.
set -e
go run bake.go template/* | gofmt > template.go

Просмотреть файл

@ -50,6 +50,7 @@ import (
"code.google.com/p/go.tools/godoc"
"code.google.com/p/go.tools/godoc/vfs"
"code.google.com/p/go.tools/godoc/vfs/mapfs"
"code.google.com/p/go.tools/godoc/vfs/zipfs"
)
@ -196,13 +197,7 @@ func main() {
if *templateDir != "" {
fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
} else {
// Read templates from go.tools repository; if not
// found there, fall back on $GOROOT/lib/godoc
// which will be present in binary distributions.
pkg, err := build.Import(templatePath, "", build.FindOnly)
if err == nil {
fs.Bind("/lib/godoc", vfs.OS(pkg.Dir), "/", vfs.BindReplace)
}
fs.Bind("/lib/godoc", mapfs.New(bakedFiles), "/", vfs.BindReplace)
}
} else {
// use file system specified via .zip file (path separator must be '/')

1961
cmd/godoc/template.go Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

81
godoc/vfs/mapfs/mapfs.go Normal file
Просмотреть файл

@ -0,0 +1,81 @@
// Copyright 2013 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.
// Package mapfs file provides an implementation of the FileSystem
// interface based on the contents of a map[string]string.
package mapfs
import (
"io"
"os"
"strings"
"time"
"code.google.com/p/go.tools/godoc/vfs"
)
func New(m map[string]string) vfs.FileSystem {
return mapFS(m)
}
// mapFS is the map based implementation of FileSystem
type mapFS map[string]string
func (fs mapFS) String() string { return "mapfs" }
func (fs mapFS) Close() error { return nil }
func filename(p string) string {
if len(p) > 0 && p[0] == '/' {
p = p[1:]
}
return p
}
func (fs mapFS) Open(p string) (vfs.ReadSeekCloser, error) {
b, ok := fs[filename(p)]
if !ok {
return nil, os.ErrNotExist
}
return nopCloser{strings.NewReader(b)}, nil
}
func (fs mapFS) Lstat(p string) (os.FileInfo, error) {
b, ok := fs[filename(p)]
if !ok {
return nil, os.ErrNotExist
}
return mapFI{name: p, size: int64(len(b))}, nil
}
func (fs mapFS) Stat(p string) (os.FileInfo, error) {
return fs.Lstat(p)
}
func (fs mapFS) ReadDir(p string) ([]os.FileInfo, error) {
var list []os.FileInfo
for fn, b := range fs {
list = append(list, mapFI{name: fn, size: int64(len(b))})
}
return list, nil
}
// mapFI is the map-based implementation of FileInfo.
type mapFI struct {
name string
size int64
}
func (fi mapFI) IsDir() bool { return false }
func (fi mapFI) ModTime() time.Time { return time.Time{} }
func (fi mapFI) Mode() os.FileMode { return 0444 }
func (fi mapFI) Name() string { return fi.name }
func (fi mapFI) Size() int64 { return fi.size }
func (fi mapFI) Sys() interface{} { return nil }
type nopCloser struct {
io.ReadSeeker
}
func (nc nopCloser) Close() error { return nil }