Merge "x/ref: Move packages without external users into internal."
diff --git a/cmd/namespace/doc.go b/cmd/namespace/doc.go
index c7a3aa8..8c8570e 100644
--- a/cmd/namespace/doc.go
+++ b/cmd/namespace/doc.go
@@ -70,11 +70,15 @@
 Returns all matching entries from the namespace.
 
 Usage:
-   namespace glob <pattern>
+   namespace glob [flags] <pattern>
 
 <pattern> is a glob pattern that is matched against all the names below the
 specified mount name.
 
+The namespace glob flags are:
+ -l=false
+   Long listing format.
+
 Namespace Mount
 
 Adds server <server> to the namespace with name <name>.
diff --git a/cmd/namespace/impl.go b/cmd/namespace/impl.go
index 5380f01..f7ff5f1 100644
--- a/cmd/namespace/impl.go
+++ b/cmd/namespace/impl.go
@@ -6,6 +6,7 @@
 
 import (
 	"fmt"
+	"sort"
 	"time"
 
 	"v.io/v23"
@@ -17,6 +18,7 @@
 )
 
 var (
+	flagLongGlob            bool
 	flagInsecureResolve     bool
 	flagInsecureResolveToMT bool
 )
@@ -49,18 +51,47 @@
 		vlog.Infof("ns.Glob(%q) failed: %v", pattern, err)
 		return err
 	}
+	if flagLongGlob {
+		// Show all the information we received.
+		for res := range c {
+			switch v := res.(type) {
+			case *naming.MountEntry:
+				fmt.Fprint(cmd.Stdout(), v.Name)
+				for _, s := range v.Servers {
+					delta := s.Deadline.Time.Sub(time.Now())
+					fmt.Fprintf(cmd.Stdout(), " %s (Expires in %d sec)", s.Server, int(delta.Seconds()))
+				}
+				fmt.Fprintln(cmd.Stdout())
+			case *naming.GlobError:
+				fmt.Fprintf(cmd.Stderr(), "Error: %s: %v\n", v.Name, v.Error)
+			}
+		}
+		return nil
+	}
+	// Show a sorted list of unique names, and any errors.
+	resultSet := make(map[string]struct{})
+	errors := []*naming.GlobError{}
 	for res := range c {
 		switch v := res.(type) {
 		case *naming.MountEntry:
-			fmt.Fprint(cmd.Stdout(), v.Name)
-			for _, s := range v.Servers {
-				fmt.Fprintf(cmd.Stdout(), " %s (Deadline %s)", s.Server, s.Deadline.Time)
+			if v.Name != "" {
+				resultSet[v.Name] = struct{}{}
 			}
-			fmt.Fprintln(cmd.Stdout())
 		case *naming.GlobError:
-			fmt.Fprintf(cmd.Stderr(), "Error: %s: %v\n", v.Name, v.Error)
+			errors = append(errors, v)
 		}
 	}
+	results := []string{}
+	for r := range resultSet {
+		results = append(results, r)
+	}
+	sort.Strings(results)
+	for _, result := range results {
+		fmt.Fprintln(cmd.Stdout(), result)
+	}
+	for _, err := range errors {
+		fmt.Fprintf(cmd.Stderr(), "Error: %s: %v\n", err.Name, err.Error)
+	}
 	return nil
 }
 
@@ -205,6 +236,7 @@
 }
 
 func root() *cmdline.Command {
+	cmdGlob.Flags.BoolVar(&flagLongGlob, "l", false, "Long listing format.")
 	cmdResolve.Flags.BoolVar(&flagInsecureResolve, "insecure", false, "Insecure mode: May return results from untrusted servers and invoke Resolve on untrusted mounttables")
 	cmdResolveToMT.Flags.BoolVar(&flagInsecureResolveToMT, "insecure", false, "Insecure mode: May return results from untrusted servers and invoke Resolve on untrusted mounttables")
 	return &cmdline.Command{
diff --git a/test/v23tests/v23tests.go b/test/v23tests/v23tests.go
index 9f78de7..3496356 100644
--- a/test/v23tests/v23tests.go
+++ b/test/v23tests/v23tests.go
@@ -8,6 +8,7 @@
 	"errors"
 	"fmt"
 	"io/ioutil"
+	"math/rand"
 	"os"
 	"os/exec"
 	"path"
@@ -18,9 +19,11 @@
 	"testing"
 	"time"
 
+	"v.io/x/lib/vlog"
+
 	"v.io/v23"
 	"v.io/v23/security"
-	"v.io/x/lib/vlog"
+
 	"v.io/x/ref/envvar"
 	"v.io/x/ref/services/agent"
 	"v.io/x/ref/test"
@@ -554,15 +557,33 @@
 // function.
 func buildPkg(binDir, pkg string) (bool, string, error) {
 	binFile := filepath.Join(binDir, path.Base(pkg))
+	vlog.Infof("buildPkg: %v .. %v", binDir, pkg)
 	if _, err := os.Stat(binFile); err != nil {
 		if !os.IsNotExist(err) {
 			return false, "", err
 		}
-		cmd := exec.Command("v23", "go", "build", "-o", binFile, pkg)
+		baseName := path.Base(binFile)
+		tmpdir, err := ioutil.TempDir(binDir, baseName+"-")
+		if err != nil {
+			return false, "", err
+		}
+		defer os.RemoveAll(tmpdir)
+		uniqueBinFile := filepath.Join(tmpdir, baseName)
+
+		cmd := exec.Command("v23", "go", "build", "-x", "-o", uniqueBinFile, pkg)
 		if output, err := cmd.CombinedOutput(); err != nil {
 			vlog.VI(1).Infof("\n%v:\n%v\n", strings.Join(cmd.Args, " "), string(output))
 			return false, "", err
 		}
+		if err := os.Rename(uniqueBinFile, binFile); err != nil {
+			// It seems that on some systems a rename may fail if another rename
+			// is in progress in the same directory. We back a random amount of time
+			// in the hope that a second attempt will succeed.
+			time.Sleep(time.Duration(rand.Int63n(1000)) * time.Millisecond)
+			if err := os.Rename(uniqueBinFile, binFile); err != nil {
+				return false, "", err
+			}
+		}
 		return false, binFile, nil
 	}
 	return true, binFile, nil