Commit bbc2c038 authored by Robert Griesemer's avatar Robert Griesemer

- godoc periodic sync for Linux and Darwin

- support debug/sync (if automatic sync is enabled in the first place)
- removed debug/restart feature

R=rsc
DELTA=97  (37 added, 27 deleted, 33 changed)
OCL=30068
CL=30079
parent 0f62ac42
...@@ -79,14 +79,13 @@ var ( ...@@ -79,14 +79,13 @@ var (
verbose = flag.Bool("v", false, "verbose mode"); verbose = flag.Bool("v", false, "verbose mode");
// file system roots // file system roots
launchdir string; // directory from which godoc was launched
goroot string; goroot string;
pkgroot = flag.String("pkgroot", "src/lib", "root package source directory (if unrooted, relative to goroot)"); pkgroot = flag.String("pkgroot", "src/lib", "root package source directory (if unrooted, relative to goroot)");
tmplroot = flag.String("tmplroot", "usr/gri/pretty", "root template directory (if unrooted, relative to goroot)"); tmplroot = flag.String("tmplroot", "usr/gri/pretty", "root template directory (if unrooted, relative to goroot)");
// workspace control // periodic sync
p4binary = flag.String("p4", "/usr/local/scripts/p4", "p4 binary"); syncCmd = flag.String("sync", "", "sync command; disabled if empty");
syncSleep = flag.Int("sync", 0, "p4 sync interval in minutes; disabled if <= 0"); syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0");
syncTime timeStamp; // time of last p4 sync syncTime timeStamp; // time of last p4 sync
// layout control // layout control
...@@ -589,36 +588,59 @@ func loggingHandler(h http.Handler) http.Handler { ...@@ -589,36 +588,59 @@ func loggingHandler(h http.Handler) http.Handler {
} }
func p4sync() bool { func exec(c *http.Conn, args []string) bool {
if *verbose { r, w, err := os.Pipe();
log.Stderrf("p4 sync"); if err != nil {
log.Stderrf("os.Pipe(): %v\n", err);
return false;
} }
args := []string{*p4binary, "sync"};
var fds []*os.File; bin := args[0];
fds := []*os.File{nil, w, w};
if *verbose { if *verbose {
fds = []*os.File{os.Stdin, os.Stdout, os.Stderr}; log.Stderrf("executing %v", args);
} }
pid, err := os.ForkExec(*p4binary, args, os.Environ(), "", fds); pid, err := os.ForkExec(bin, args, os.Environ(), goroot, fds);
defer r.Close();
w.Close();
if err != nil { if err != nil {
log.Stderrf("os.ForkExec(%s): %v", *p4binary, err); log.Stderrf("os.ForkExec(%q): %v\n", bin, err);
return false; return false;
} }
os.Wait(pid, 0);
syncTime.set(); 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; return true;
} }
func restartGodoc(c *http.Conn, r *http.Request) { func sync(c *http.Conn, r *http.Request) {
binary := os.Args[0]; args := []string{"/bin/sh", "-c", *syncCmd};
fds := []*os.File{os.Stdin, os.Stdout, os.Stderr}; if !exec(c, args) {
pid, err := os.ForkExec(binary, os.Args, os.Environ(), launchdir, fds); *syncMin = 0; // disable sync
if err != nil { return;
log.Stderrf("os.ForkExec(%s): %v", binary, err);
return; // do not terminate
} }
log.Stderrf("restarted %s, pid = %d\n", binary, pid); syncTime.set();
os.Exit(0);
} }
...@@ -647,12 +669,6 @@ func main() { ...@@ -647,12 +669,6 @@ func main() {
} }
} }
var err os.Error;
if launchdir, err = os.Getwd(); err != nil {
log.Stderrf("unable to determine current working directory - restart may fail");
launchdir = "";
}
if err := os.Chdir(goroot); err != nil { if err := os.Chdir(goroot); err != nil {
log.Exitf("chdir %s: %v", goroot, err); log.Exitf("chdir %s: %v", goroot, err);
} }
...@@ -671,36 +687,30 @@ func main() { ...@@ -671,36 +687,30 @@ func main() {
} }
http.Handle(Pkg, http.HandlerFunc(servePkg)); http.Handle(Pkg, http.HandlerFunc(servePkg));
if syscall.OS != "darwin" { if *syncCmd != "" {
http.Handle("/debug/restart", http.HandlerFunc(restartGodoc)); http.Handle("/debug/sync", http.HandlerFunc(sync));
} else {
log.Stderrf("warning: debug/restart disabled (running on darwin)\n");
} }
http.Handle("/", http.HandlerFunc(serveFile)); http.Handle("/", http.HandlerFunc(serveFile));
// The server may have been restarted; always wait 1sec to // The server may have been restarted; always wait 1sec to
// give the forking server a chance to shut down and release // give the forking server a chance to shut down and release
// the http port. (This is necessary because under OS X Exec // the http port.
// won't work if there are more than one thread running.)
time.Sleep(1e9); time.Sleep(1e9);
// Start p4 sync goroutine, if enabled. // Start sync goroutine, if enabled.
if syscall.OS != "darwin" { if *syncCmd != "" && *syncMin > 0 {
if *syncSleep > 0 { go func() {
go func() { if *verbose {
if *verbose { log.Stderrf("sync every %dmin", *syncMin);
log.Stderrf("p4 sync every %dmin", *syncSleep); }
} for *syncMin > 0 {
for p4sync() { sync(nil, nil);
time.Sleep(int64(*syncSleep) * (60 * 1e9)); time.Sleep(int64(*syncMin) * (60 * 1e9));
} }
if *verbose { if *verbose {
log.Stderrf("periodic p4 sync stopped"); log.Stderrf("periodic sync stopped");
} }
}(); }();
}
} else {
log.Stderrf("warning: sync disabled (running on darwin)\n");
} }
if err := http.ListenAndServe(*httpaddr, handler); err != nil { if err := http.ListenAndServe(*httpaddr, handler); err != nil {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment