mirror of https://github.com/golang/go.git
- initial steps towards showing directory tree instead of
just a single directory - all pieces present but not well integrated - directory tree served at the moment under /tree R=rsc http://go/go-review/1018016
This commit is contained in:
parent
b67352110f
commit
49d295d592
|
|
@ -0,0 +1,6 @@
|
|||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr><td><a href="{Path|html}">{Name|html}</a></td></tr>
|
||||
{.repeated section Subdirs}
|
||||
<tr><td></td><td>{@|dir}</td></tr>
|
||||
{.end}
|
||||
</table>
|
||||
|
|
@ -85,9 +85,6 @@ var (
|
|||
pkgroot = flag.String("pkgroot", "src/pkg", "root package source directory (if unrooted, relative to goroot)");
|
||||
tmplroot = flag.String("tmplroot", "lib/godoc", "root template directory (if unrooted, relative to goroot)");
|
||||
|
||||
// periodic sync
|
||||
syncTime RWValue; // time of last sync
|
||||
|
||||
// layout control
|
||||
tabwidth = flag.Int("tabwidth", 4, "tab width");
|
||||
)
|
||||
|
|
@ -99,7 +96,6 @@ func init() {
|
|||
goroot = "/home/r/go-release/go";
|
||||
}
|
||||
flag.StringVar(&goroot, "goroot", goroot, "Go root directory");
|
||||
syncTime.set(nil); // have a reasonable initial value (time is shown on web page)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -131,6 +127,58 @@ func htmlEscape(s string) string {
|
|||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Directory trees
|
||||
|
||||
type Directory struct {
|
||||
Path string; // including Name
|
||||
Name string;
|
||||
Subdirs []*Directory
|
||||
}
|
||||
|
||||
|
||||
func newDirTree0(path, name string) *Directory {
|
||||
list, _ := io.ReadDir(path); // ignore errors
|
||||
// determine number of subdirectories n
|
||||
n := 0;
|
||||
for _, d := range list {
|
||||
if isPkgDir(d) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
// create Directory node
|
||||
var subdirs []*Directory;
|
||||
if n > 0 {
|
||||
subdirs = make([]*Directory, n);
|
||||
i := 0;
|
||||
for _, d := range list {
|
||||
if isPkgDir(d) {
|
||||
subdirs[i] = newDirTree0(pathutil.Join(path, d.Name), d.Name);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(path, "src/") {
|
||||
path = path[len("src/") : len(path)];
|
||||
}
|
||||
return &Directory{path, name, subdirs};
|
||||
}
|
||||
|
||||
|
||||
func newDirTree(root string) *Directory {
|
||||
d, err := os.Lstat(root);
|
||||
if err != nil {
|
||||
log.Stderrf("%v", err);
|
||||
return nil;
|
||||
}
|
||||
if !isPkgDir(d) {
|
||||
log.Stderrf("not a package directory: %s", d.Name);
|
||||
return nil;
|
||||
}
|
||||
return newDirTree0(root, d.Name);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Parsing
|
||||
|
||||
|
|
@ -310,6 +358,15 @@ func textFmt(w io.Writer, x interface{}, format string) {
|
|||
}
|
||||
|
||||
|
||||
// Template formatter for "dir" format.
|
||||
func dirFmt(w io.Writer, x interface{}, format string) {
|
||||
_ = x.(*Directory); // die quickly if x has the wrong type
|
||||
if err := dirsHtml.Execute(x, w); err != nil {
|
||||
log.Stderrf("dirsHtml.Execute: %s", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Template formatter for "link" format.
|
||||
func linkFmt(w io.Writer, x interface{}, format string) {
|
||||
type Positioner interface {
|
||||
|
|
@ -375,6 +432,7 @@ var fmap = template.FormatterMap{
|
|||
"": textFmt,
|
||||
"html": htmlFmt,
|
||||
"html-comment": htmlCommentFmt,
|
||||
"dir": dirFmt,
|
||||
"link": linkFmt,
|
||||
"infoClass": infoClassFmt,
|
||||
"infoLine": infoLineFmt,
|
||||
|
|
@ -397,6 +455,7 @@ func readTemplate(name string) *template.Template {
|
|||
|
||||
|
||||
var (
|
||||
dirsHtml,
|
||||
godocHtml,
|
||||
packageHtml,
|
||||
packageText,
|
||||
|
|
@ -408,6 +467,7 @@ var (
|
|||
func readTemplates() {
|
||||
// have to delay until after flags processing,
|
||||
// so that main has chdir'ed to goroot.
|
||||
dirsHtml = readTemplate("dirs.html");
|
||||
godocHtml = readTemplate("godoc.html");
|
||||
packageHtml = readTemplate("package.html");
|
||||
packageText = readTemplate("package.txt");
|
||||
|
|
@ -420,6 +480,8 @@ func readTemplates() {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Generic HTML wrapper
|
||||
|
||||
var pkgTree RWValue; // *Directory tree of packages, updated with each sync
|
||||
|
||||
func servePage(c *http.Conn, title, query string, content []byte) {
|
||||
type Data struct {
|
||||
Title string;
|
||||
|
|
@ -428,7 +490,7 @@ func servePage(c *http.Conn, title, query string, content []byte) {
|
|||
Content []byte;
|
||||
}
|
||||
|
||||
_, ts := syncTime.get();
|
||||
_, ts := pkgTree.get();
|
||||
d := Data{
|
||||
Title: title,
|
||||
Timestamp: time.SecondsToLocalTime(ts).String(),
|
||||
|
|
@ -672,6 +734,21 @@ func servePkg(c *http.Conn, r *http.Request) {
|
|||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Directory tree
|
||||
|
||||
// TODO(gri): Temporary - integrate with package serving.
|
||||
|
||||
func serveTree(c *http.Conn, r *http.Request) {
|
||||
dir, _ := pkgTree.get();
|
||||
|
||||
var buf bytes.Buffer;
|
||||
dirFmt(&buf, dir, "");
|
||||
|
||||
servePage(c, "Package tree", "", buf.Bytes());
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Search
|
||||
|
||||
|
|
@ -692,7 +769,7 @@ func search(c *http.Conn, r *http.Request) {
|
|||
if index, timestamp := searchIndex.get(); index != nil {
|
||||
result.Query = query;
|
||||
result.Hit, result.Alt = index.(*Index).Lookup(query);
|
||||
_, ts := syncTime.get();
|
||||
_, ts := pkgTree.get();
|
||||
result.Accurate = timestamp >= ts;
|
||||
result.Legend = &infoClasses;
|
||||
}
|
||||
|
|
@ -718,6 +795,7 @@ func search(c *http.Conn, r *http.Request) {
|
|||
|
||||
func registerPublicHandlers(mux *http.ServeMux) {
|
||||
mux.Handle(Pkg, http.HandlerFunc(servePkg));
|
||||
mux.Handle("/tree", http.HandlerFunc(serveTree)); // TODO(gri): integrate with package serving
|
||||
mux.Handle("/search", http.HandlerFunc(search));
|
||||
mux.Handle("/", http.HandlerFunc(serveFile));
|
||||
}
|
||||
|
|
@ -726,7 +804,7 @@ func registerPublicHandlers(mux *http.ServeMux) {
|
|||
// Indexing goroutine.
|
||||
func indexer() {
|
||||
for {
|
||||
_, ts := syncTime.get();
|
||||
_, ts := pkgTree.get();
|
||||
if _, timestamp := searchIndex.get(); timestamp < ts {
|
||||
// index possibly out of date - make a new one
|
||||
// (could use a channel to send an explicit signal
|
||||
|
|
|
|||
|
|
@ -101,12 +101,13 @@ func dosync(c *http.Conn, r *http.Request) {
|
|||
args := []string{"/bin/sh", "-c", *syncCmd};
|
||||
switch exec(c, args) {
|
||||
case 0:
|
||||
// sync succeeded and some files have changed
|
||||
syncTime.set(nil);
|
||||
// sync succeeded and some files have changed;
|
||||
// update package tree
|
||||
pkgTree.set(newDirTree(*pkgroot));
|
||||
fallthrough;
|
||||
case 1:
|
||||
// sync failed because no files changed
|
||||
// don't change the sync time
|
||||
// sync failed because no files changed;
|
||||
// don't change the package tree
|
||||
syncDelay.set(*syncMin); // revert to regular sync schedule
|
||||
default:
|
||||
// sync failed because of an error - back off exponentially, but try at least once a day
|
||||
|
|
@ -170,10 +171,8 @@ func main() {
|
|||
http.Handle("/debug/sync", http.HandlerFunc(dosync));
|
||||
}
|
||||
|
||||
// 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);
|
||||
// Compute package tree with corresponding timestamp.
|
||||
pkgTree.set(newDirTree(*pkgroot));
|
||||
|
||||
// Start sync goroutine, if enabled.
|
||||
if *syncCmd != "" && *syncMin > 0 {
|
||||
|
|
@ -193,6 +192,12 @@ func main() {
|
|||
// Start indexing goroutine.
|
||||
go indexer();
|
||||
|
||||
// The server may have been restarted; always wait 1sec to
|
||||
// give the forking server a chance to shut down and release
|
||||
// the http port.
|
||||
// TODO(gri): Do we still need this?
|
||||
time.Sleep(1e9);
|
||||
|
||||
// Start http server.
|
||||
if err := http.ListenAndServe(*httpaddr, handler); err != nil {
|
||||
log.Exitf("ListenAndServe %s: %v", *httpaddr, err);
|
||||
|
|
@ -200,6 +205,10 @@ func main() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Command line mode.
|
||||
// No package tree; set it to nil so we have a reasonable time stamp.
|
||||
pkgTree.set(nil);
|
||||
|
||||
if *html {
|
||||
packageText = packageHtml;
|
||||
parseerrorText = parseerrorHtml;
|
||||
|
|
|
|||
Loading…
Reference in New Issue