veyron/tools/mgmt/device: Add uninstall command

Change-Id: I12953086b035c49c27c843104b5d5cc57c1c883f
diff --git a/tools/mgmt/device/doc.go b/tools/mgmt/device/doc.go
index 26d2164..abda7c0 100644
--- a/tools/mgmt/device/doc.go
+++ b/tools/mgmt/device/doc.go
@@ -10,6 +10,7 @@
 The device commands are:
    install       Install the given application.
    install-local Install the given application from the local system.
+   uninstall     Uninstall the given application installation.
    start         Start an instance of the given application.
    associate     Tool for creating associations between Vanadium blessings and a
                  system account
@@ -107,6 +108,16 @@
    JSON-encoded device.Config object, of the form:
    '{"flag1":"value1","flag2":"value2"}'
 
+Device Uninstall
+
+Uninstall the given application installation.
+
+Usage:
+   device uninstall <installation>
+
+<installation> is the veyron object name of the application installation to
+uninstall.
+
 Device Start
 
 Start an instance of the given application.
diff --git a/tools/mgmt/device/impl/impl.go b/tools/mgmt/device/impl/impl.go
index 2600b4e..7e9a4a6 100644
--- a/tools/mgmt/device/impl/impl.go
+++ b/tools/mgmt/device/impl/impl.go
@@ -12,19 +12,6 @@
 	"v.io/lib/cmdline"
 )
 
-var cmdInstall = &cmdline.Command{
-	Run:      runInstall,
-	Name:     "install",
-	Short:    "Install the given application.",
-	Long:     "Install the given application.",
-	ArgsName: "<device> <application>",
-	ArgsLong: `
-<device> is the veyron object name of the device manager's app service.
-
-<application> is the veyron object name of the application.
-`,
-}
-
 type configFlag device.Config
 
 func (c *configFlag) String() string {
@@ -44,6 +31,19 @@
 	cmdInstall.Flags.Var(&configOverride, "config", "JSON-encoded device.Config object, of the form: '{\"flag1\":\"value1\",\"flag2\":\"value2\"}'")
 }
 
+var cmdInstall = &cmdline.Command{
+	Run:      runInstall,
+	Name:     "install",
+	Short:    "Install the given application.",
+	Long:     "Install the given application.",
+	ArgsName: "<device> <application>",
+	ArgsLong: `
+<device> is the veyron object name of the device manager's app service.
+
+<application> is the veyron object name of the application.
+`,
+}
+
 func runInstall(cmd *cmdline.Command, args []string) error {
 	if expected, got := 2, len(args); expected != got {
 		return cmd.UsageErrorf("install: incorrect number of arguments, expected %d, got %d", expected, got)
@@ -61,6 +61,30 @@
 	return nil
 }
 
+var cmdUninstall = &cmdline.Command{
+	Run:      runUninstall,
+	Name:     "uninstall",
+	Short:    "Uninstall the given application installation.",
+	Long:     "Uninstall the given application installation.",
+	ArgsName: "<installation>",
+	ArgsLong: `
+<installation> is the veyron object name of the application installation to
+uninstall.
+`,
+}
+
+func runUninstall(cmd *cmdline.Command, args []string) error {
+	if expected, got := 1, len(args); expected != got {
+		return cmd.UsageErrorf("uninstall: incorrect number of arguments, expected %d, got %d", expected, got)
+	}
+	installName := args[0]
+	if err := device.ApplicationClient(installName).Uninstall(gctx); err != nil {
+		return fmt.Errorf("Uninstall failed: %v", err)
+	}
+	fmt.Fprintf(cmd.Stdout(), "Successfully uninstalled: %q\n", installName)
+	return nil
+}
+
 var cmdStart = &cmdline.Command{
 	Run:      runStart,
 	Name:     "start",
diff --git a/tools/mgmt/device/impl/root.go b/tools/mgmt/device/impl/root.go
index 9c3f4ad..6082e6c 100644
--- a/tools/mgmt/device/impl/root.go
+++ b/tools/mgmt/device/impl/root.go
@@ -19,6 +19,6 @@
 		Long: `
 The device tool facilitates interaction with the veyron device manager.
 `,
-		Children: []*cmdline.Command{cmdInstall, cmdInstallLocal, cmdStart, associateRoot(), cmdDescribe, cmdClaim, cmdStop, cmdSuspend, cmdResume, cmdRevert, cmdUpdate, cmdDebug, aclRoot()},
+		Children: []*cmdline.Command{cmdInstall, cmdInstallLocal, cmdUninstall, cmdStart, associateRoot(), cmdDescribe, cmdClaim, cmdStop, cmdSuspend, cmdResume, cmdRevert, cmdUpdate, cmdDebug, aclRoot()},
 	}
 }