v2/services/mgmt,v/tools/mgmt/device: install package override (vdl+client)

This change modifies the device Install API to accept an override for packages
to install (on top of what's in the envelope). The motivation is to provide
packages like ACL files, which should not come from the publisher in the app
envelope, but rather be specified by the installer.

Part of this CL are also the client-side changes needed to support this,
specifically in the device command-line tool.

Server-side changes to come in a future CL.

Change-Id: Ic97db5163bc064a8cf56b9d62e68b68eaba6364d
diff --git a/tools/mgmt/device/impl/local_install.go b/tools/mgmt/device/impl/local_install.go
index dbdc6f5..21200c7 100644
--- a/tools/mgmt/device/impl/local_install.go
+++ b/tools/mgmt/device/impl/local_install.go
@@ -22,7 +22,7 @@
 	"v.io/core/veyron2/services/security/access"
 	"v.io/core/veyron2/uniqueid"
 
-	"v.io/core/veyron/services/mgmt/lib/packages"
+	pkglib "v.io/core/veyron/services/mgmt/lib/packages"
 	"v.io/lib/cmdline"
 )
 
@@ -44,6 +44,7 @@
 
 func init() {
 	cmdInstallLocal.Flags.Var(&configOverride, "config", "JSON-encoded device.Config object, of the form: '{\"flag1\":\"value1\",\"flag2\":\"value2\"}'")
+	cmdInstallLocal.Flags.Var(&packagesOverride, "packages", "JSON-encoded application.Packages object, of the form: '{\"pkg1\":{\"File\":\"object name 1\"},\"pkg2\":{\"File\":\"object name 2\"}}'")
 }
 
 type openAuthorizer struct{}
@@ -170,7 +171,7 @@
 	}
 	h.Write(bytes)
 	part := binary.PartInfo{Checksum: hex.EncodeToString(h.Sum(nil)), Size: int64(len(bytes))}
-	return []binary.PartInfo{part}, packages.MediaInfoForFileName(fileName), nil
+	return []binary.PartInfo{part}, pkglib.MediaInfoForFileName(fileName), nil
 }
 
 func (binaryInvoker) Upload(repository.BinaryUploadContext, int32) error {
@@ -210,7 +211,7 @@
 	// Directory packages first get zip'ped.
 	if info.IsDir() {
 		fileName = filepath.Join(tmpZipDir, info.Name()+".zip")
-		if err := packages.CreateZip(fileName, p); err != nil {
+		if err := pkglib.CreateZip(fileName, p); err != nil {
 			return "", "", err
 		}
 	}
@@ -293,15 +294,25 @@
 		}
 		envelope.Packages[pname] = application.PackageSpec{File: oname}
 	}
+	packagesRewritten := application.Packages{}
+	for pname, pspec := range packagesOverride {
+		_, oname, err := servePackage(pspec.File, server, tmpZipDir)
+		if err != nil {
+			return err
+		}
+		pspec.File = oname
+		packagesRewritten[pname] = pspec
+	}
 	appName, err := server.serve("application", repository.ApplicationServer(envelopeInvoker(envelope)))
 	if err != nil {
 		return err
 	}
-	appID, err := device.ApplicationClient(deviceName).Install(gctx, appName, device.Config(configOverride))
+	appID, err := device.ApplicationClient(deviceName).Install(gctx, appName, device.Config(configOverride), packagesRewritten)
 	// Reset the value for any future invocations of "install" or
 	// "install-local" (we run more than one command per process in unit
 	// tests).
 	configOverride = configFlag{}
+	packagesOverride = packagesFlag{}
 	if err != nil {
 		return fmt.Errorf("Install failed: %v", err)
 	}