cmd/gotelemetry/internal/view: let gotelemetry view open browser

cmd/gotelemetry/internal/browser utility is copied from the go project.

Change-Id: I244d5223d23457e6d76e9fc0bf258d08567241b5
Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/524078
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/cmd/gotelemetry/internal/browser/browser.go b/cmd/gotelemetry/internal/browser/browser.go
new file mode 100644
index 0000000..cd73110
--- /dev/null
+++ b/cmd/gotelemetry/internal/browser/browser.go
@@ -0,0 +1,68 @@
+// Copyright 2016 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 browser provides utilities for interacting with users' browsers.
+// This is a copy of the go project's src/cmd/internal/browser.
+package browser
+
+import (
+	"os"
+	"os/exec"
+	"runtime"
+	"time"
+)
+
+// Commands returns a list of possible commands to use to open a url.
+func Commands() [][]string {
+	var cmds [][]string
+	if exe := os.Getenv("BROWSER"); exe != "" {
+		cmds = append(cmds, []string{exe})
+	}
+	switch runtime.GOOS {
+	case "darwin":
+		cmds = append(cmds, []string{"/usr/bin/open"})
+	case "windows":
+		cmds = append(cmds, []string{"cmd", "/c", "start"})
+	default:
+		if os.Getenv("DISPLAY") != "" {
+			// xdg-open is only for use in a desktop environment.
+			cmds = append(cmds, []string{"xdg-open"})
+		}
+	}
+	cmds = append(cmds,
+		[]string{"chrome"},
+		[]string{"google-chrome"},
+		[]string{"chromium"},
+		[]string{"firefox"},
+	)
+	return cmds
+}
+
+// Open tries to open url in a browser and reports whether it succeeded.
+func Open(url string) bool {
+	for _, args := range Commands() {
+		cmd := exec.Command(args[0], append(args[1:], url)...)
+		if cmd.Start() == nil && appearsSuccessful(cmd, 3*time.Second) {
+			return true
+		}
+	}
+	return false
+}
+
+// appearsSuccessful reports whether the command appears to have run successfully.
+// If the command runs longer than the timeout, it's deemed successful.
+// If the command runs within the timeout, it's deemed successful if it exited cleanly.
+func appearsSuccessful(cmd *exec.Cmd, timeout time.Duration) bool {
+	errc := make(chan error, 1)
+	go func() {
+		errc <- cmd.Wait()
+	}()
+
+	select {
+	case <-time.After(timeout):
+		return true
+	case err := <-errc:
+		return err == nil
+	}
+}
diff --git a/cmd/gotelemetry/internal/view/view.go b/cmd/gotelemetry/internal/view/view.go
index da81476..ce816aa 100644
--- a/cmd/gotelemetry/internal/view/view.go
+++ b/cmd/gotelemetry/internal/view/view.go
@@ -27,6 +27,7 @@
 	"time"
 
 	"golang.org/x/telemetry"
+	"golang.org/x/telemetry/cmd/gotelemetry/internal/browser"
 	"golang.org/x/telemetry/internal/config"
 	"golang.org/x/telemetry/internal/configstore"
 	tcounter "golang.org/x/telemetry/internal/counter"
@@ -37,6 +38,7 @@
 	addr     = flag.String("addr", "localhost:4040", "server listens on the given TCP network address")
 	dev      = flag.Bool("dev", false, "rebuild static assets on save")
 	fsConfig = flag.String("config", "", "load a config from the filesystem")
+	open     = flag.Bool("open", true, "open the browser to the server address")
 
 	//go:embed *
 	content embed.FS
@@ -55,7 +57,11 @@
 	if err != nil {
 		log.Fatal(err)
 	}
-	fmt.Printf("server listening at http://%s\n", listener.Addr())
+	addr := fmt.Sprintf("http://%s", listener.Addr())
+	fmt.Printf("server listening at %s\n", addr)
+	if *open {
+		browser.Open(addr)
+	}
 	log.Fatal(http.Serve(listener, mux))
 }