cmd/viewcore: add -p <port> option to 'html' subcommand
In interactive mode, the command returns and resumes
further command processing immediately after starting the
web server.
Change-Id: I2e4768c931213bc9ef1107aff6d7973c0488bfe0
Reviewed-on: https://go-review.googlesource.com/129035
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/cmd/viewcore/html.go b/cmd/viewcore/html.go
index 564a547..7027cf2 100644
--- a/cmd/viewcore/html.go
+++ b/cmd/viewcore/html.go
@@ -15,7 +15,9 @@
"golang.org/x/debug/internal/gocore"
)
-func serveHTML(c *gocore.Process) {
+// serveHTML starts and serves a webserver on the port.
+// If async is true, it returns immediately after starting the server.
+func serveHTML(c *gocore.Process, port int, async bool) {
http.HandleFunc("/object", func(w http.ResponseWriter, r *http.Request) {
objs, ok := r.URL.Query()["o"]
if !ok || len(objs) != 1 {
@@ -199,8 +201,18 @@
p(c.Stats(), "")
fmt.Fprintf(w, "</table>\n")
})
- fmt.Println("serving on :8080")
- http.ListenAndServe(":8080", nil)
+
+ if port <= 0 {
+ port = 8080
+ }
+ fmt.Printf("start serving on http://localhost:%d\n", port)
+
+ httpAddr := fmt.Sprintf(":%d", port)
+ if async {
+ go http.ListenAndServe(httpAddr, nil)
+ return
+ }
+ http.ListenAndServe(httpAddr, nil)
}
func htmlObject(w http.ResponseWriter, c *gocore.Process, name string, a core.Address, t *gocore.Type, live map[core.Address]bool) {
diff --git a/cmd/viewcore/main.go b/cmd/viewcore/main.go
index 050d0ab..b480ffc 100644
--- a/cmd/viewcore/main.go
+++ b/cmd/viewcore/main.go
@@ -15,6 +15,7 @@
"sort"
"strconv"
"strings"
+ "sync"
"text/tabwriter"
"github.com/chzyer/readline" // TODO: vendor
@@ -117,11 +118,9 @@
cmdHTML = &cobra.Command{
Use: "html",
- Short: "start an http server on :8080 for browsing core file data",
+ Short: "start an http server for browsing core file data on the port specified with -port",
Args: cobra.ExactArgs(0),
Run: runHTML,
-
- // TODO: port flag
}
cmdRead = &cobra.Command{
@@ -133,6 +132,8 @@
)
type config struct {
+ interactive bool
+
// Set based on os.Args[1]
corefile string
@@ -149,6 +150,8 @@
cmdRoot.PersistentFlags().StringVar(&cfg.exePath, "exe", "", "main executable file")
cmdRoot.PersistentFlags().StringVar(&cfg.cpuprof, "prof", "", "write cpu profile of viewcore to this file for viewcore's developers")
+ cmdHTML.Flags().IntP("port", "p", 8080, "port for http server")
+
cmdRoot.AddCommand(
cmdOverview,
cmdMappings,
@@ -272,6 +275,9 @@
exitf("%v\n", err)
}
+ // Interactive mode.
+ cfg.interactive = true
+
// Create a dummy root to run in shell.
root := &cobra.Command{}
// Make all subcommands of viewcore available in the shell.
@@ -454,7 +460,6 @@
fmt.Fprintf(t, "%d\t%d\t%d\t %s\n", e.count, e.size, e.count*e.size, e.name)
}
t.Flush()
-
}
func runBreakdown(cmd *cobra.Command, args []string) {
@@ -647,12 +652,32 @@
}
}
+// httpServer is the singleton http server, initialized by
+// the first call to runHTML.
+var httpServer struct {
+ sync.Mutex
+ port int
+}
+
func runHTML(cmd *cobra.Command, args []string) {
+ httpServer.Lock()
+ defer httpServer.Unlock()
+ if httpServer.port != 0 {
+ fmt.Printf("already serving on http://localhost:%d\n", httpServer.port)
+ return
+ }
_, c, err := readCore()
if err != nil {
exitf("%v\n", err)
}
- serveHTML(c)
+
+ port, err := cmd.Flags().GetInt("port")
+ if err != nil {
+ exitf("%v\n", err)
+ }
+ serveHTML(c, port, cfg.interactive)
+ httpServer.port = port
+ // TODO: launch web browser
}
func runRead(cmd *cobra.Command, args []string) {