Merge "services/device/device: allow overriding app title when publish'ing"
diff --git a/services/device/device/doc.go b/services/device/device/doc.go
index 732c29c..8a01b17 100644
--- a/services/device/device/doc.go
+++ b/services/device/device/doc.go
@@ -379,13 +379,14 @@
 Device publish
 
 Publishes the given application(s) to the binary and application servers. The
-binaries should be in $V23_ROOT/release/go/bin/[<GOOS>_<GOARCH>]. The binary is
-published as <binserv>/<binary name>/<GOOS>-<GOARCH>/<TIMESTAMP>. The
+<title> can be optionally specified with @<title> (defaults to the binary name).
+The binaries should be in $V23_ROOT/release/go/bin/[<GOOS>_<GOARCH>]. The binary
+is published as <binserv>/<binary name>/<GOOS>-<GOARCH>/<TIMESTAMP>. The
 application envelope is published as <appserv>/<binary name>/0. Optionally, adds
 blessing patterns to the Read and Resolve AccessLists.
 
 Usage:
-   device publish [flags] <binary name> ...
+   device publish [flags] <binary name>[@<title>] ...
 
 The device publish flags are:
  -appserv=applications
diff --git a/services/device/device/publish.go b/services/device/device/publish.go
index 7412cda..129360c 100644
--- a/services/device/device/publish.go
+++ b/services/device/device/publish.go
@@ -34,11 +34,13 @@
 	Short: "Publish the given application(s).",
 	Long: `
 Publishes the given application(s) to the binary and application servers.
+The <title> can be optionally specified with @<title> (defaults to the binary
+name).
 The binaries should be in $V23_ROOT/release/go/bin/[<GOOS>_<GOARCH>].
 The binary is published as <binserv>/<binary name>/<GOOS>-<GOARCH>/<TIMESTAMP>.
 The application envelope is published as <appserv>/<binary name>/0.
 Optionally, adds blessing patterns to the Read and Resolve AccessLists.`,
-	ArgsName: "<binary name> ...",
+	ArgsName: "<binary name>[@<title>] ...",
 }
 
 var binaryService, applicationService, readBlessings, goarchFlag, goosFlag string
@@ -78,7 +80,11 @@
 	return nil
 }
 
-func publishOne(cmd *cmdline.Command, binPath, binaryName string) error {
+func publishOne(cmd *cmdline.Command, binPath, binary string) error {
+	binaryName, title := binary, binary
+	if parts := strings.SplitN(binary, "@", 2); len(parts) == 2 {
+		binaryName, title = parts[0], parts[1]
+	}
 	// Step 1, upload the binary to the binary service.
 
 	// TODO(caprita): Instead of the current timestamp, use each binary's
@@ -113,7 +119,7 @@
 	envelope, err := appClient.Match(gctx, profiles)
 	if verror.ErrorID(err) == verror.ErrNoExist.ID {
 		// There was nothing published yet, create a new envelope.
-		envelope = application.Envelope{Title: binaryName}
+		envelope = application.Envelope{Title: title}
 	} else if err != nil {
 		return err
 	}
diff --git a/services/internal/binarylib/client.go b/services/internal/binarylib/client.go
index 3420c0c..e8330c3 100644
--- a/services/internal/binarylib/client.go
+++ b/services/internal/binarylib/client.go
@@ -318,11 +318,11 @@
 
 func UploadFromFile(ctx *context.T, von, path string) (*security.Signature, error) {
 	file, err := os.Open(path)
-	defer file.Close()
 	if err != nil {
-		vlog.Errorf("Open(%v) failed: %v", err)
+		vlog.Errorf("Open(%v) failed: %v", path, err)
 		return nil, verror.New(errOperationFailed, ctx)
 	}
+	defer file.Close()
 	mediaInfo, err := packages.LoadMediaInfo(path)
 	if err != nil {
 		mediaInfo = packages.MediaInfoForFileName(path)