mirror of https://github.com/golang/go.git
- install gofmt in src/cmd/gofmt
- remove some left-over files R=rsc DELTA=1465 (281 added, 1181 deleted, 3 changed) OCL=30350 CL=30353
This commit is contained in:
parent
1ac2cfc720
commit
d8e4446d12
|
|
@ -0,0 +1,27 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.$(GOARCH)
|
||||||
|
|
||||||
|
TARG=gofmt
|
||||||
|
OFILES=\
|
||||||
|
gofmt.$O\
|
||||||
|
|
||||||
|
$(TARG): $(OFILES)
|
||||||
|
$(LD) -o $(TARG) $(OFILES)
|
||||||
|
|
||||||
|
test: $(TARG)
|
||||||
|
./test.sh
|
||||||
|
|
||||||
|
smoketest: $(TARG)
|
||||||
|
./test.sh $(GOROOT)/src/pkg/go/parser/parser.go
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OFILES) $(TARG)
|
||||||
|
|
||||||
|
install: $(TARG)
|
||||||
|
cp $(TARG) $(HOME)/bin/$(TARG)
|
||||||
|
|
||||||
|
%.$O: %.go
|
||||||
|
$(GC) $<
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
# Copyright 2009 The Go Authors. All rights reserved.
|
#!/bin/bash
|
||||||
|
# Copyright 2009 The Go Authors. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style
|
# Use of this source code is governed by a BSD-style
|
||||||
# license that can be found in the LICENSE file.
|
# license that can be found in the LICENSE file.
|
||||||
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
. $GOROOT/src/Make.$GOARCH
|
. $GOROOT/src/Make.$GOARCH
|
||||||
if [ -z "$O" ]; then
|
if [ -z "$O" ]; then
|
||||||
echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
|
echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
|
||||||
|
|
@ -18,7 +18,7 @@ rm -f $HOME/bin/quietgcc
|
||||||
cp quietgcc.bash $HOME/bin/quietgcc
|
cp quietgcc.bash $HOME/bin/quietgcc
|
||||||
chmod +x $HOME/bin/quietgcc
|
chmod +x $HOME/bin/quietgcc
|
||||||
|
|
||||||
for i in lib9 libbio libmach_amd64 libregexp cmd pkg cmd/gobuild cmd/godoc
|
for i in lib9 libbio libmach_amd64 libregexp cmd pkg cmd/gobuild cmd/godoc cmd/gofmt
|
||||||
do (
|
do (
|
||||||
echo; echo; echo %%%% making $i %%%%; echo
|
echo; echo; echo %%%% making $i %%%%; echo
|
||||||
cd $i
|
cd $i
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,10 @@ time make
|
||||||
GOMAXPROCS=10 make test
|
GOMAXPROCS=10 make test
|
||||||
) || exit $?
|
) || exit $?
|
||||||
|
|
||||||
(xcd ../usr/gri/pretty
|
(xcd cmd/gofmt
|
||||||
make clean
|
make clean
|
||||||
time make
|
time make
|
||||||
make smoketest
|
time make smoketest
|
||||||
# TODO: this belongs elsewhere
|
|
||||||
cp godoc $HOME/bin
|
|
||||||
) || exit $?
|
) || exit $?
|
||||||
|
|
||||||
(xcd ../doc/progs
|
(xcd ../doc/progs
|
||||||
|
|
|
||||||
|
|
@ -1,707 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
// godoc: Go Documentation Server
|
|
||||||
|
|
||||||
// Web server tree:
|
|
||||||
//
|
|
||||||
// http://godoc/ main landing page
|
|
||||||
// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, tutorial, etc.
|
|
||||||
// http://godoc/src/ serve files from $GOROOT/src; .go gets pretty-printed
|
|
||||||
// http://godoc/cmd/ serve documentation about commands (TODO)
|
|
||||||
// http://godoc/pkg/ serve documentation about packages
|
|
||||||
// (idea is if you say import "compress/zlib", you go to
|
|
||||||
// http://godoc/pkg/compress/zlib)
|
|
||||||
//
|
|
||||||
// Command-line interface:
|
|
||||||
//
|
|
||||||
// godoc packagepath [name ...]
|
|
||||||
//
|
|
||||||
// godoc compress/zlib
|
|
||||||
// - prints doc for package proto
|
|
||||||
// godoc compress/zlib Cipher NewCMAC
|
|
||||||
// - prints doc for Cipher and NewCMAC in package crypto/block
|
|
||||||
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/vector";
|
|
||||||
"flag";
|
|
||||||
"fmt";
|
|
||||||
"go/ast";
|
|
||||||
"go/doc";
|
|
||||||
"go/parser";
|
|
||||||
"go/printer";
|
|
||||||
"go/token";
|
|
||||||
"http";
|
|
||||||
"io";
|
|
||||||
"log";
|
|
||||||
"net";
|
|
||||||
"os";
|
|
||||||
pathutil "path";
|
|
||||||
"sort";
|
|
||||||
"strings";
|
|
||||||
"sync";
|
|
||||||
"syscall";
|
|
||||||
"tabwriter";
|
|
||||||
"template";
|
|
||||||
"time";
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
const Pkg = "/pkg/" // name for auto-generated package documentation tree
|
|
||||||
|
|
||||||
|
|
||||||
type timeStamp struct {
|
|
||||||
mutex sync.RWMutex;
|
|
||||||
seconds int64;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (ts *timeStamp) set() {
|
|
||||||
ts.mutex.Lock();
|
|
||||||
ts.seconds = time.Seconds();
|
|
||||||
ts.mutex.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (ts *timeStamp) get() int64 {
|
|
||||||
ts.mutex.RLock();
|
|
||||||
defer ts.mutex.RUnlock();
|
|
||||||
return ts.seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var (
|
|
||||||
verbose = flag.Bool("v", false, "verbose mode");
|
|
||||||
|
|
||||||
// file system roots
|
|
||||||
goroot string;
|
|
||||||
pkgroot = flag.String("pkgroot", "src/pkg", "root package source directory (if unrooted, relative to goroot)");
|
|
||||||
tmplroot = flag.String("tmplroot", "usr/gri/pretty", "root template directory (if unrooted, relative to goroot)");
|
|
||||||
|
|
||||||
// periodic sync
|
|
||||||
syncCmd = flag.String("sync", "", "sync command; disabled if empty");
|
|
||||||
syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0");
|
|
||||||
syncTime timeStamp; // time of last p4 sync
|
|
||||||
|
|
||||||
// layout control
|
|
||||||
tabwidth = flag.Int("tabwidth", 4, "tab width");
|
|
||||||
html = flag.Bool("html", false, "print HTML in command-line mode");
|
|
||||||
|
|
||||||
// server control
|
|
||||||
httpaddr = flag.String("http", "", "HTTP service address (e.g., ':6060')");
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err os.Error;
|
|
||||||
goroot, err = os.Getenv("GOROOT");
|
|
||||||
if err != nil {
|
|
||||||
goroot = "/home/r/go-release/go";
|
|
||||||
}
|
|
||||||
flag.StringVar(&goroot, "goroot", goroot, "Go root directory");
|
|
||||||
syncTime.set(); // have a reasonable initial value
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Support
|
|
||||||
|
|
||||||
func isDir(name string) bool {
|
|
||||||
d, err := os.Stat(name);
|
|
||||||
return err == nil && d.IsDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func isGoFile(dir *os.Dir) bool {
|
|
||||||
return dir.IsRegular() && pathutil.Ext(dir.Name) == ".go";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func isPkgDir(dir *os.Dir) bool {
|
|
||||||
return dir.IsDirectory() && dir.Name != "_obj";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func makeTabwriter(writer io.Writer) *tabwriter.Writer {
|
|
||||||
return tabwriter.NewWriter(writer, *tabwidth, 1, byte(' '), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Parsing
|
|
||||||
|
|
||||||
// A single error in the parsed file.
|
|
||||||
type parseError struct {
|
|
||||||
src []byte; // source before error
|
|
||||||
line int; // line number of error
|
|
||||||
msg string; // error message
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// All the errors in the parsed file, plus surrounding source code.
|
|
||||||
// Each error has a slice giving the source text preceding it
|
|
||||||
// (starting where the last error occurred). The final element in list[]
|
|
||||||
// has msg = "", to give the remainder of the source code.
|
|
||||||
// This data structure is handed to the templates parseerror.txt and parseerror.html.
|
|
||||||
//
|
|
||||||
type parseErrors struct {
|
|
||||||
filename string; // path to file
|
|
||||||
list []parseError; // the errors
|
|
||||||
src []byte; // the file's entire source code
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Parses a file (path) and returns the corresponding AST and
|
|
||||||
// a sorted list (by file position) of errors, if any.
|
|
||||||
//
|
|
||||||
func parse(path string, mode uint) (*ast.Program, *parseErrors) {
|
|
||||||
src, err := io.ReadFile(path);
|
|
||||||
if err != nil {
|
|
||||||
log.Stderrf("ReadFile %s: %v", path, err);
|
|
||||||
errs := []parseError{parseError{nil, 0, err.String()}};
|
|
||||||
return nil, &parseErrors{path, errs, nil};
|
|
||||||
}
|
|
||||||
|
|
||||||
prog, err := parser.Parse(src, mode);
|
|
||||||
if err != nil {
|
|
||||||
// sort and convert error list
|
|
||||||
if errors, ok := err.(parser.ErrorList); ok {
|
|
||||||
sort.Sort(errors);
|
|
||||||
errs := make([]parseError, len(errors) + 1); // +1 for final fragment of source
|
|
||||||
offs := 0;
|
|
||||||
for i, r := range errors {
|
|
||||||
// Should always be true, but check for robustness.
|
|
||||||
if 0 <= r.Pos.Offset && r.Pos.Offset <= len(src) {
|
|
||||||
errs[i].src = src[offs : r.Pos.Offset];
|
|
||||||
offs = r.Pos.Offset;
|
|
||||||
}
|
|
||||||
errs[i].line = r.Pos.Line;
|
|
||||||
errs[i].msg = r.Msg;
|
|
||||||
}
|
|
||||||
errs[len(errors)].src = src[offs : len(src)];
|
|
||||||
return nil, &parseErrors{path, errs, src};
|
|
||||||
} else {
|
|
||||||
// TODO should have some default handling here to be more robust
|
|
||||||
panic("unreachable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return prog, nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Templates
|
|
||||||
|
|
||||||
// Return text for an AST node.
|
|
||||||
func nodeText(node interface{}, mode uint) []byte {
|
|
||||||
var buf io.ByteBuffer;
|
|
||||||
tw := makeTabwriter(&buf);
|
|
||||||
printer.Fprint(tw, node, mode);
|
|
||||||
tw.Flush();
|
|
||||||
return buf.Data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Convert x, whatever it is, to text form.
|
|
||||||
func toText(x interface{}) []byte {
|
|
||||||
type String interface { String() string }
|
|
||||||
|
|
||||||
switch v := x.(type) {
|
|
||||||
case []byte:
|
|
||||||
return v;
|
|
||||||
case string:
|
|
||||||
return io.StringBytes(v);
|
|
||||||
case String:
|
|
||||||
return io.StringBytes(v.String());
|
|
||||||
case ast.Decl:
|
|
||||||
return nodeText(v, printer.ExportsOnly);
|
|
||||||
case ast.Expr:
|
|
||||||
return nodeText(v, printer.ExportsOnly);
|
|
||||||
}
|
|
||||||
var buf io.ByteBuffer;
|
|
||||||
fmt.Fprint(&buf, x);
|
|
||||||
return buf.Data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Template formatter for "html" format.
|
|
||||||
func htmlFmt(w io.Writer, x interface{}, format string) {
|
|
||||||
template.HtmlEscape(w, toText(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Template formatter for "html-comment" format.
|
|
||||||
func htmlCommentFmt(w io.Writer, x interface{}, format string) {
|
|
||||||
doc.ToHtml(w, toText(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Template formatter for "" (default) format.
|
|
||||||
func textFmt(w io.Writer, x interface{}, format string) {
|
|
||||||
w.Write(toText(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var fmap = template.FormatterMap{
|
|
||||||
"": textFmt,
|
|
||||||
"html": htmlFmt,
|
|
||||||
"html-comment": htmlCommentFmt,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func readTemplate(name string) *template.Template {
|
|
||||||
path := pathutil.Join(*tmplroot, name);
|
|
||||||
data, err := io.ReadFile(path);
|
|
||||||
if err != nil {
|
|
||||||
log.Exitf("ReadFile %s: %v", path, err);
|
|
||||||
}
|
|
||||||
t, err1 := template.Parse(string(data), fmap);
|
|
||||||
if err1 != nil {
|
|
||||||
log.Exitf("%s: %v", name, err);
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var godocHtml *template.Template
|
|
||||||
var packageHtml *template.Template
|
|
||||||
var packageText *template.Template
|
|
||||||
var parseerrorHtml *template.Template;
|
|
||||||
var parseerrorText *template.Template;
|
|
||||||
|
|
||||||
func readTemplates() {
|
|
||||||
// have to delay until after flags processing,
|
|
||||||
// so that main has chdir'ed to goroot.
|
|
||||||
godocHtml = readTemplate("godoc.html");
|
|
||||||
packageHtml = readTemplate("package.html");
|
|
||||||
packageText = readTemplate("package.txt");
|
|
||||||
parseerrorHtml = readTemplate("parseerror.html");
|
|
||||||
parseerrorText = readTemplate("parseerror.txt");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Generic HTML wrapper
|
|
||||||
|
|
||||||
func servePage(c *http.Conn, title, content interface{}) {
|
|
||||||
type Data struct {
|
|
||||||
title interface{};
|
|
||||||
header interface{};
|
|
||||||
timestamp string;
|
|
||||||
content interface{};
|
|
||||||
}
|
|
||||||
|
|
||||||
var d Data;
|
|
||||||
d.title = title;
|
|
||||||
d.header = title;
|
|
||||||
d.timestamp = time.SecondsToLocalTime(syncTime.get()).String();
|
|
||||||
d.content = content;
|
|
||||||
godocHtml.Execute(&d, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func serveText(c *http.Conn, text []byte) {
|
|
||||||
c.SetHeader("content-type", "text/plain; charset=utf-8");
|
|
||||||
c.Write(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Files
|
|
||||||
|
|
||||||
func serveParseErrors(c *http.Conn, errors *parseErrors) {
|
|
||||||
// format errors
|
|
||||||
var buf io.ByteBuffer;
|
|
||||||
parseerrorHtml.Execute(errors, &buf);
|
|
||||||
servePage(c, errors.filename + " - Parse Errors", buf.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func serveGoSource(c *http.Conn, name string) {
|
|
||||||
prog, errors := parse(name, parser.ParseComments);
|
|
||||||
if errors != nil {
|
|
||||||
serveParseErrors(c, errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf io.ByteBuffer;
|
|
||||||
fmt.Fprintln(&buf, "<pre>");
|
|
||||||
template.HtmlEscape(&buf, nodeText(prog, printer.DocComments));
|
|
||||||
fmt.Fprintln(&buf, "</pre>");
|
|
||||||
|
|
||||||
servePage(c, name + " - Go source", buf.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var fileServer = http.FileServer(".", "");
|
|
||||||
|
|
||||||
func serveFile(c *http.Conn, req *http.Request) {
|
|
||||||
// pick off special cases and hand the rest to the standard file server
|
|
||||||
switch {
|
|
||||||
case req.Url.Path == "/":
|
|
||||||
// serve landing page.
|
|
||||||
// TODO: hide page from ordinary file serving.
|
|
||||||
// writing doc/index.html will take care of that.
|
|
||||||
http.ServeFile(c, req, "doc/root.html");
|
|
||||||
|
|
||||||
case req.Url.Path == "/doc/root.html":
|
|
||||||
// hide landing page from its real name
|
|
||||||
// TODO why - there is no reason for this (remove eventually)
|
|
||||||
http.NotFound(c, req);
|
|
||||||
|
|
||||||
case pathutil.Ext(req.Url.Path) == ".go":
|
|
||||||
serveGoSource(c, req.Url.Path[1 : len(req.Url.Path)]); // strip leading '/' from name
|
|
||||||
|
|
||||||
default:
|
|
||||||
// TODO not good enough - don't want to download files
|
|
||||||
// want to see them
|
|
||||||
fileServer.ServeHTTP(c, req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Packages
|
|
||||||
|
|
||||||
type pakDesc struct {
|
|
||||||
dirname string; // relative to goroot
|
|
||||||
pakname string; // same as last component of importpath
|
|
||||||
importpath string; // import "___"
|
|
||||||
filenames map[string] bool; // set of file (names) belonging to this package
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO if we don't plan to use the directory information, simplify to []string
|
|
||||||
type dirList []*os.Dir
|
|
||||||
|
|
||||||
func (d dirList) Len() int { return len(d) }
|
|
||||||
func (d dirList) Less(i, j int) bool { return d[i].Name < d[j].Name }
|
|
||||||
func (d dirList) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
|
||||||
|
|
||||||
|
|
||||||
func isPackageFile(dirname, filename, pakname string) bool {
|
|
||||||
// ignore test files
|
|
||||||
if strings.HasSuffix(filename, "_test.go") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine package name
|
|
||||||
prog, errors := parse(dirname + "/" + filename, parser.PackageClauseOnly);
|
|
||||||
if prog == nil {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return prog != nil && prog.Name.Value == pakname;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns the canonical URL path, the package denoted by path, and
|
|
||||||
// the list of sub-directories in the corresponding package directory.
|
|
||||||
// If there is no such package, the package descriptor pd is nil.
|
|
||||||
// If there are no sub-directories, the dirs list is nil.
|
|
||||||
func findPackage(path string) (canonical string, pd *pakDesc, dirs dirList) {
|
|
||||||
canonical = pathutil.Clean(Pkg + path) + "/";
|
|
||||||
|
|
||||||
// get directory contents, if possible
|
|
||||||
importpath := pathutil.Clean(path); // no trailing '/'
|
|
||||||
dirname := pathutil.Join(*pkgroot, importpath);
|
|
||||||
if !isDir(dirname) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd, err1 := os.Open(dirname, os.O_RDONLY, 0);
|
|
||||||
if err1 != nil {
|
|
||||||
log.Stderrf("open %s: %v", dirname, err1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
list, err2 := fd.Readdir(-1);
|
|
||||||
if err2 != nil {
|
|
||||||
log.Stderrf("readdir %s: %v", dirname, err2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the package name is is the directory name within its parent
|
|
||||||
_, pakname := pathutil.Split(dirname);
|
|
||||||
|
|
||||||
// collect all files belonging to the package and count the
|
|
||||||
// number of sub-directories
|
|
||||||
filenames := make(map[string]bool);
|
|
||||||
nsub := 0;
|
|
||||||
for i, entry := range list {
|
|
||||||
switch {
|
|
||||||
case isGoFile(&entry) && isPackageFile(dirname, entry.Name, pakname):
|
|
||||||
// add file to package desc
|
|
||||||
if tmp, found := filenames[entry.Name]; found {
|
|
||||||
panic("internal error: same file added more than once: " + entry.Name);
|
|
||||||
}
|
|
||||||
filenames[entry.Name] = true;
|
|
||||||
case isPkgDir(&entry):
|
|
||||||
nsub++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make the list of sub-directories, if any
|
|
||||||
var subdirs dirList;
|
|
||||||
if nsub > 0 {
|
|
||||||
subdirs = make(dirList, nsub);
|
|
||||||
nsub = 0;
|
|
||||||
for i, entry := range list {
|
|
||||||
if isPkgDir(&entry) {
|
|
||||||
// make a copy here so sorting (and other code) doesn't
|
|
||||||
// have to make one every time an entry is moved
|
|
||||||
copy := new(os.Dir);
|
|
||||||
*copy = entry;
|
|
||||||
subdirs[nsub] = copy;
|
|
||||||
nsub++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Sort(subdirs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there are no package files, then there is no package
|
|
||||||
if len(filenames) == 0 {
|
|
||||||
return canonical, nil, subdirs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return canonical, &pakDesc{dirname, pakname, importpath, filenames}, subdirs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (p *pakDesc) Doc() (*doc.PackageDoc, *parseErrors) {
|
|
||||||
if p == nil {
|
|
||||||
return nil, nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute documentation
|
|
||||||
var r doc.DocReader;
|
|
||||||
i := 0;
|
|
||||||
for filename := range p.filenames {
|
|
||||||
prog, err := parse(p.dirname + "/" + filename, parser.ParseComments);
|
|
||||||
if err != nil {
|
|
||||||
return nil, err;
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
// first file - initialize doc
|
|
||||||
r.Init(prog.Name.Value, p.importpath);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
r.AddProgram(prog);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.Doc(), nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type PageInfo struct {
|
|
||||||
PDoc *doc.PackageDoc;
|
|
||||||
Dirs dirList;
|
|
||||||
}
|
|
||||||
|
|
||||||
func servePkg(c *http.Conn, r *http.Request) {
|
|
||||||
path := r.Url.Path;
|
|
||||||
path = path[len(Pkg) : len(path)];
|
|
||||||
canonical, desc, dirs := findPackage(path);
|
|
||||||
|
|
||||||
if r.Url.Path != canonical {
|
|
||||||
http.Redirect(c, canonical, http.StatusMovedPermanently);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdoc, errors := desc.Doc();
|
|
||||||
if errors != nil {
|
|
||||||
serveParseErrors(c, errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf io.ByteBuffer;
|
|
||||||
if false { // TODO req.Params["format"] == "text"
|
|
||||||
err := packageText.Execute(PageInfo{pdoc, dirs}, &buf);
|
|
||||||
if err != nil {
|
|
||||||
log.Stderrf("packageText.Execute: %s", err);
|
|
||||||
}
|
|
||||||
serveText(c, buf.Data());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
err := packageHtml.Execute(PageInfo{pdoc, dirs}, &buf);
|
|
||||||
if err != nil {
|
|
||||||
log.Stderrf("packageHtml.Execute: %s", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if path == "" {
|
|
||||||
path = "."; // don't display an empty path
|
|
||||||
}
|
|
||||||
servePage(c, path + " - Go package documentation", buf.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Server
|
|
||||||
|
|
||||||
func loggingHandler(h http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(c *http.Conn, req *http.Request) {
|
|
||||||
log.Stderrf("%s\t%s", c.RemoteAddr, req.Url);
|
|
||||||
h.ServeHTTP(c, req);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func exec(c *http.Conn, args []string) bool {
|
|
||||||
r, w, err := os.Pipe();
|
|
||||||
if err != nil {
|
|
||||||
log.Stderrf("os.Pipe(): %v\n", err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bin := args[0];
|
|
||||||
fds := []*os.File{nil, w, w};
|
|
||||||
if *verbose {
|
|
||||||
log.Stderrf("executing %v", args);
|
|
||||||
}
|
|
||||||
pid, err := os.ForkExec(bin, args, os.Environ(), goroot, fds);
|
|
||||||
defer r.Close();
|
|
||||||
w.Close();
|
|
||||||
if err != nil {
|
|
||||||
log.Stderrf("os.ForkExec(%q): %v\n", bin, err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf io.ByteBuffer;
|
|
||||||
io.Copy(r, &buf);
|
|
||||||
wait, err := os.Wait(pid, 0);
|
|
||||||
if err != nil {
|
|
||||||
os.Stderr.Write(buf.Data());
|
|
||||||
log.Stderrf("os.Wait(%d, 0): %v\n", pid, err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if !wait.Exited() || wait.ExitStatus() != 0 {
|
|
||||||
os.Stderr.Write(buf.Data());
|
|
||||||
log.Stderrf("executing %v failed (exit status = %d)", args, wait.ExitStatus());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if *verbose {
|
|
||||||
os.Stderr.Write(buf.Data());
|
|
||||||
}
|
|
||||||
if c != nil {
|
|
||||||
c.SetHeader("content-type", "text/plain; charset=utf-8");
|
|
||||||
c.Write(buf.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func sync(c *http.Conn, r *http.Request) {
|
|
||||||
args := []string{"/bin/sh", "-c", *syncCmd};
|
|
||||||
if !exec(c, args) {
|
|
||||||
*syncMin = 0; // disable sync
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
syncTime.set();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func usage() {
|
|
||||||
fmt.Fprintf(os.Stderr,
|
|
||||||
"usage: godoc package [name ...]\n"
|
|
||||||
" godoc -http=:6060\n"
|
|
||||||
);
|
|
||||||
flag.PrintDefaults();
|
|
||||||
os.Exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse();
|
|
||||||
|
|
||||||
// Check usage first; get usage message out early.
|
|
||||||
switch {
|
|
||||||
case *httpaddr != "":
|
|
||||||
if flag.NArg() != 0 {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if flag.NArg() == 0 {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Chdir(goroot); err != nil {
|
|
||||||
log.Exitf("chdir %s: %v", goroot, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
readTemplates();
|
|
||||||
|
|
||||||
if *httpaddr != "" {
|
|
||||||
var handler http.Handler = http.DefaultServeMux;
|
|
||||||
if *verbose {
|
|
||||||
log.Stderrf("Go Documentation Server\n");
|
|
||||||
log.Stderrf("address = %s\n", *httpaddr);
|
|
||||||
log.Stderrf("goroot = %s\n", goroot);
|
|
||||||
log.Stderrf("pkgroot = %s\n", *pkgroot);
|
|
||||||
log.Stderrf("tmplroot = %s\n", *tmplroot);
|
|
||||||
handler = loggingHandler(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Handle(Pkg, http.HandlerFunc(servePkg));
|
|
||||||
if *syncCmd != "" {
|
|
||||||
http.Handle("/debug/sync", http.HandlerFunc(sync));
|
|
||||||
}
|
|
||||||
http.Handle("/", http.HandlerFunc(serveFile));
|
|
||||||
|
|
||||||
// The server may have been restarted; always wait 1sec to
|
|
||||||
// give the forking server a chance to shut down and release
|
|
||||||
// the http port.
|
|
||||||
time.Sleep(1e9);
|
|
||||||
|
|
||||||
// Start sync goroutine, if enabled.
|
|
||||||
if *syncCmd != "" && *syncMin > 0 {
|
|
||||||
go func() {
|
|
||||||
if *verbose {
|
|
||||||
log.Stderrf("sync every %dmin", *syncMin);
|
|
||||||
}
|
|
||||||
for *syncMin > 0 {
|
|
||||||
sync(nil, nil);
|
|
||||||
time.Sleep(int64(*syncMin) * (60 * 1e9));
|
|
||||||
}
|
|
||||||
if *verbose {
|
|
||||||
log.Stderrf("periodic sync stopped");
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := http.ListenAndServe(*httpaddr, handler); err != nil {
|
|
||||||
log.Exitf("ListenAndServe %s: %v", *httpaddr, err)
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if *html {
|
|
||||||
packageText = packageHtml;
|
|
||||||
parseerrorText = parseerrorHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
_, desc, dirs := findPackage(flag.Arg(0));
|
|
||||||
pdoc, errors := desc.Doc();
|
|
||||||
if errors != nil {
|
|
||||||
err := parseerrorText.Execute(errors, os.Stderr);
|
|
||||||
if err != nil {
|
|
||||||
log.Stderrf("parseerrorText.Execute: %s", err);
|
|
||||||
}
|
|
||||||
os.Exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pdoc != nil && flag.NArg() > 1 {
|
|
||||||
args := flag.Args();
|
|
||||||
pdoc.Filter(args[1 : len(args)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
packageText.Execute(PageInfo{pdoc, dirs}, os.Stdout);
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
{.section Dirs}
|
|
||||||
<h2>Subdirectories</h2>
|
|
||||||
{.repeated section @}
|
|
||||||
<a href="{Name|html}/">{Name|html}</a><br />
|
|
||||||
{.end}
|
|
||||||
<hr />
|
|
||||||
{.end}
|
|
||||||
{.section PDoc}
|
|
||||||
<h1>package {PackageName|html}</h1>
|
|
||||||
<p><code>import "{ImportPath|html}"</code></p>
|
|
||||||
|
|
||||||
{Doc|html-comment}
|
|
||||||
{.section Consts}
|
|
||||||
<h2>Constants</h2>
|
|
||||||
{.repeated section @}
|
|
||||||
{Doc|html-comment}
|
|
||||||
<pre>{Decl|html}</pre>
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.section Vars}
|
|
||||||
<hr />
|
|
||||||
<h2>Variables</h2>
|
|
||||||
{.repeated section @}
|
|
||||||
{Doc|html-comment}
|
|
||||||
<pre>{Decl|html}</pre>
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.section Funcs}
|
|
||||||
<hr />
|
|
||||||
{.repeated section @}
|
|
||||||
<h2>func {Name|html}</h2>
|
|
||||||
<p><code>{Decl|html}</code></p>
|
|
||||||
{Doc|html-comment}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.section Types}
|
|
||||||
{.repeated section @}
|
|
||||||
<hr />
|
|
||||||
<h2>type {.section Type}{Name|html}{.end}</h2>
|
|
||||||
{Doc|html-comment}
|
|
||||||
<p><pre>{Decl|html}</pre></p>
|
|
||||||
{.repeated section Factories}
|
|
||||||
<h3>func {Name|html}</h3>
|
|
||||||
<p><code>{Decl|html}</code></p>
|
|
||||||
{Doc|html-comment}
|
|
||||||
{.end}
|
|
||||||
{.repeated section Methods}
|
|
||||||
<h3>func ({Recv|html}) {Name|html}</h3>
|
|
||||||
<p><code>{Decl|html}</code></p>
|
|
||||||
{Doc|html-comment}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
{.section Dirs}
|
|
||||||
SUBDIRECTORIES
|
|
||||||
{.repeated section @}
|
|
||||||
{Name}
|
|
||||||
{.end}
|
|
||||||
|
|
||||||
{.end}
|
|
||||||
{.section PDoc}
|
|
||||||
PACKAGE
|
|
||||||
|
|
||||||
package {PackageName}
|
|
||||||
import "{ImportPath}"
|
|
||||||
{.section Doc}
|
|
||||||
|
|
||||||
{@}
|
|
||||||
{.end}
|
|
||||||
{.section Consts}
|
|
||||||
|
|
||||||
CONSTANTS
|
|
||||||
{.repeated section @}
|
|
||||||
{# the .repeated section, .section idiom skips over nils in the array}
|
|
||||||
|
|
||||||
{Decl}
|
|
||||||
|
|
||||||
{Doc}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.section Vars}
|
|
||||||
|
|
||||||
VARIABLES
|
|
||||||
{.repeated section @}
|
|
||||||
|
|
||||||
{Decl}
|
|
||||||
|
|
||||||
{Doc}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.section Funcs}
|
|
||||||
|
|
||||||
FUNCTIONS
|
|
||||||
{.repeated section @}
|
|
||||||
|
|
||||||
{Decl}
|
|
||||||
|
|
||||||
{Doc}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.section Types}
|
|
||||||
|
|
||||||
TYPES
|
|
||||||
{.repeated section @}
|
|
||||||
|
|
||||||
{Decl}
|
|
||||||
|
|
||||||
{Doc}
|
|
||||||
{.repeated section Factories}
|
|
||||||
|
|
||||||
{Decl}
|
|
||||||
|
|
||||||
{Doc}
|
|
||||||
{.end}
|
|
||||||
{.repeated section Methods}
|
|
||||||
|
|
||||||
{Decl}
|
|
||||||
|
|
||||||
{Doc}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<h1>Parse errors in {filename}</h1>
|
|
||||||
<pre>
|
|
||||||
{.repeated section list}
|
|
||||||
{src}{.section msg}<b><font color=red>«{msg|html}»</font></b>{.end}{.end}</pre>
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
parse errors:
|
|
||||||
{.repeated section list}
|
|
||||||
{.section msg}
|
|
||||||
{filename}:{line}: {msg}
|
|
||||||
{.end}
|
|
||||||
{.end}
|
|
||||||
Loading…
Reference in New Issue