From e299a270855ccd228acc9836b345ed48b29a0ecd Mon Sep 17 00:00:00 2001
From: James Tucker <raggi@google.com>
Date: Thu, 2 May 2019 18:12:21 +0000
Subject: [PATCH] [pm serve] fix interpretation of -d/-repo

The -d flag was altered some time ago to allow pointing at the repository
serving directory rather than the repository root. A recent regression caused
the interpretation to change, however, there is also now a discrepancy
between the meaning of -repo and -d. We now interpret -d to mean the
repository serving directory, and -repo to mean the repository root. As SDK
consumers are presently using -d, this restores the prior behavior for that
flag, while making the -repo flag behavior consistent across other commands.

Change-Id: I50d7567194101d3cf2c6af1bf83a33bc481f4290
---
 garnet/go/src/pm/cmd/pm/serve/serve.go      | 56 +++++++++++++--------
 garnet/go/src/pm/cmd/pm/serve/serve_test.go | 32 ++++++++++++
 2 files changed, 68 insertions(+), 20 deletions(-)

diff --git a/garnet/go/src/pm/cmd/pm/serve/serve.go b/garnet/go/src/pm/cmd/pm/serve/serve.go
index 4dab53f6a95..0a029dd9f20 100644
--- a/garnet/go/src/pm/cmd/pm/serve/serve.go
+++ b/garnet/go/src/pm/cmd/pm/serve/serve.go
@@ -15,6 +15,7 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"sync"
 	"time"
 
 	"fuchsia.googlesource.com/pm/build"
@@ -26,18 +27,22 @@ import (
 // server is a default http server only parameterized for tests.
 var server http.Server
 
-func Run(cfg *build.Config, args []string) error {
-	fs := flag.NewFlagSet("serve", flag.ExitOnError)
-	repoDir := fs.String("d", "", "(deprecated, use -repo) path to the repository")
-
-	config := &repo.Config{}
-	config.Vars(fs)
+var (
+	fs            = flag.NewFlagSet("serve", flag.ExitOnError)
+	repoServeDir  = fs.String("d", "", "(deprecated, use -repo) path to the repository")
+	listen        = fs.String("l", ":8083", "HTTP listen address")
+	auto          = fs.Bool("a", true, "Host auto endpoint for realtime client updates")
+	quiet         = fs.Bool("q", false, "Don't print out information about requests")
+	encryptionKey = fs.String("e", "", "Path to a symmetric blob encryption key *UNSAFE*")
+	publishList   = fs.String("p", "", "path to a package list file to be auto-published")
+	config        = &repo.Config{}
+	initOnce      sync.Once
+)
 
-	listen := fs.String("l", ":8083", "HTTP listen address")
-	auto := fs.Bool("a", true, "Host auto endpoint for realtime client updates")
-	quiet := fs.Bool("q", false, "Don't print out information about requests")
-	encryptionKey := fs.String("e", "", "Path to a symmetric blob encryption key *UNSAFE*")
-	publishList := fs.String("p", "", "path to a package list file to be auto-published")
+func ParseFlags(args []string) error {
+	// the flags added by vars can't be added more than once, so when tests invoke
+	// this func more than once, it causes a failure.
+	initOnce.Do(func() { config.Vars(fs) })
 
 	fs.Usage = func() {
 		fmt.Fprintf(os.Stderr, "usage: %s serve", filepath.Base(os.Args[0]))
@@ -50,12 +55,23 @@ func Run(cfg *build.Config, args []string) error {
 	}
 	config.ApplyDefaults()
 
-	if *repoDir == "" {
-		*repoDir = config.RepoDir
+	// The -d flag points at $reporoot/repository, so the "repo" for publishing is
+	// one directory above that.
+	// If -d is passed, it takes priority.
+	if *repoServeDir == "" {
+		*repoServeDir = filepath.Join(config.RepoDir, "repository")
+	} else {
+		config.RepoDir = filepath.Dir(*repoServeDir)
+	}
+	return nil
+}
+
+func Run(cfg *build.Config, args []string) error {
+	if err := ParseFlags(args); err != nil {
+		return err
 	}
-	repoPubDir := filepath.Join(*repoDir, "repository")
 
-	repo, err := repo.New(*repoDir)
+	repo, err := repo.New(config.RepoDir)
 	if err != nil {
 		return err
 	}
@@ -64,7 +80,7 @@ func Run(cfg *build.Config, args []string) error {
 	}
 
 	if err := repo.Init(); err != nil && err != os.ErrExist {
-		return fmt.Errorf("repository at %q is not valid or could not be initialized: %s", *repoDir, err)
+		return fmt.Errorf("repository at %q is not valid or could not be initialized: %s", config.RepoDir, err)
 	}
 
 	if *auto {
@@ -102,7 +118,7 @@ func Run(cfg *build.Config, args []string) error {
 			}
 		}
 
-		timestampPath := filepath.Join(repoPubDir, "timestamp.json")
+		timestampPath := filepath.Join(*repoServeDir, "timestamp.json")
 		if err = w.Add(timestampPath); err != nil {
 			return fmt.Errorf("failed to watch %s: %s", timestampPath, err)
 		}
@@ -138,7 +154,7 @@ func Run(cfg *build.Config, args []string) error {
 		publishAll()
 	}
 
-	dirServer := http.FileServer(http.Dir(repoPubDir))
+	dirServer := http.FileServer(http.Dir(*repoServeDir))
 	http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		switch r.URL.Path {
 		case "/":
@@ -151,7 +167,7 @@ func Run(cfg *build.Config, args []string) error {
 	}))
 
 	cs := pmhttp.NewConfigServer(func() []byte {
-		b, err := ioutil.ReadFile(filepath.Join(repoPubDir, "root.json"))
+		b, err := ioutil.ReadFile(filepath.Join(*repoServeDir, "root.json"))
 		if err != nil {
 			log.Printf("%s", err)
 		}
@@ -161,7 +177,7 @@ func Run(cfg *build.Config, args []string) error {
 
 	if !*quiet {
 		fmt.Printf("%s [pm serve] serving %s at http://%s\n",
-			time.Now().Format("2006-01-02 15:04:05"), *repoDir, *listen)
+			time.Now().Format("2006-01-02 15:04:05"), config.RepoDir, *listen)
 	}
 
 	server.Addr = *listen
diff --git a/garnet/go/src/pm/cmd/pm/serve/serve_test.go b/garnet/go/src/pm/cmd/pm/serve/serve_test.go
index 9bc0a24a9e6..398f36b7b1e 100644
--- a/garnet/go/src/pm/cmd/pm/serve/serve_test.go
+++ b/garnet/go/src/pm/cmd/pm/serve/serve_test.go
@@ -23,6 +23,38 @@ import (
 	"fuchsia.googlesource.com/sse"
 )
 
+func TestParseFlags(t *testing.T) {
+	// poor mans reset, for the cases covered below
+	resetFlags := func() {
+		config.RepoDir = ""
+		*repoServeDir = ""
+	}
+	defer resetFlags()
+	if err := ParseFlags([]string{"-repo", "amber-files"}); err != nil {
+		t.Fatal(err)
+	}
+	if got, want := config.RepoDir, "amber-files"; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+	if got, want := *repoServeDir, "amber-files/repository"; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+
+	resetFlags()
+	if err := ParseFlags([]string{"-d", "amber-files/repository"}); err != nil {
+		t.Fatal(err)
+	}
+	if got, want := config.RepoDir, "amber-files"; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+	if got, want := *repoServeDir, "amber-files/repository"; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+
+	// TODO: add additional coverage (needs some re-arrangement to be able to
+	// re-set flag defaults)
+}
+
 func TestServer(t *testing.T) {
 	cfg := build.TestConfig()
 	build.BuildTestPackage(cfg)
-- 
GitLab