[sessionctl] Allow mod short name for add_mod

This allows users to continue specifying a mod's package name and has
sessionctl resolve it to a full package path. Users will still be able
to specify a full package url:

fx shell sessionctl add_mod slider_mod
fx shell sessionctl add_mod fuchsia-pkg://fuchsia.com/slider_mod#meta/slider_mod.cmx

TEST=sessionctl_unittests
MF-180 #done

Change-Id: I6d8551f3467deef3d63674e6b27d11bce69121ef
diff --git a/bin/sessionctl/main.cc b/bin/sessionctl/main.cc
index 792a674..7dec5ce 100644
--- a/bin/sessionctl/main.cc
+++ b/bin/sessionctl/main.cc
@@ -66,22 +66,22 @@
   Defaults --focus_mod and --focus_story to 'true'.
 
   MOD_URL
-    Mods have a unique "mod_url". It's the mod package's name.
-    In BUILD.gn fuchsia_package_name = "mod_url" or mod_url comes from
-    flutter_app("mod_url") when there is no fuchsia_package_name set.
+    This can be either the mod's full package url or the mod component's name.
+    The mod components name will be converted to the following package url
+    format: fuchsia-pkg://fuchsia.com/MOD_URL#meta/MOD_URL.cmx.
 
   optional: --story_name, --mod_name, --focus_mod, --focus_story
 
 remove_mod
   Usage: [--story_name=foo] remove_mod MOD_NAME
 
-  Removes an existing mod by name. If the mod was added with add_mod, 
+  Removes an existing mod by name. If the mod was added with add_mod,
   use the value you passed to add_mod's --mod_name flag or the default
   value which would be the mod_url.
   Defaults --story_name to MOD_NAME.
 
   MOD_NAME
-      The name of the mod.
+    The name of the mod.
 
   optional: --story_name
 
diff --git a/bin/sessionctl/session_ctl_app.cc b/bin/sessionctl/session_ctl_app.cc
index f25db72..5e9b39f 100644
--- a/bin/sessionctl/session_ctl_app.cc
+++ b/bin/sessionctl/session_ctl_app.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <regex>
+
 #include "peridot/bin/sessionctl/session_ctl_app.h"
 #include "peridot/bin/sessionctl/session_ctl_constants.h"
 
@@ -77,6 +79,21 @@
   std::string mod_name = mod_url;
   std::string story_name = mod_url;
 
+  if (mod_url.find(kFuchsiaPkgPrefix) == 0) {
+    // Extract the component name from the mod url and use it as the mod and
+    // story name
+    std::regex pkg_regex(".*#meta/(\\w+)\\.cmx");
+    std::smatch match;
+    if (std::regex_search(mod_url, match, pkg_regex)) {
+      mod_name = match[1];
+      story_name = match[1];
+    }
+  } else {
+    // Replace mod url short name with full package path
+    mod_url =
+        fxl::StringPrintf(kFuchsiaPkgPath, mod_url.c_str(), mod_url.c_str());
+  }
+
   // If the following options aren't specified, their respective values will
   // remain unchanged.
   command_line.GetOptionValue(kStoryNameFlagString, &story_name);
diff --git a/bin/sessionctl/session_ctl_app_unittest.cc b/bin/sessionctl/session_ctl_app_unittest.cc
index 652a2b6..0dc36ff 100644
--- a/bin/sessionctl/session_ctl_app_unittest.cc
+++ b/bin/sessionctl/session_ctl_app_unittest.cc
@@ -82,8 +82,9 @@
 
 TEST_F(SessionCtlAppTest, AddMod) {
   // Add a mod
-  auto command_line =
-      fxl::CommandLineFromInitializerList({"sessionctl", "add_mod", "mod_url"});
+  auto command_line = fxl::CommandLineFromInitializerList(
+      {"sessionctl", "add_mod",
+       "fuchsia-pkg://fuchsia.com/mod_url#meta/mod_url.cmx"});
   SessionCtlApp sessionctl = CreateSessionCtl(command_line);
   RunLoopUntilCommandExecutes([&] {
     return sessionctl.ExecuteCommand(kAddModCommandString, command_line);
@@ -95,6 +96,8 @@
   EXPECT_EQ("mod_url", story_data->story_name);
   EXPECT_EQ("mod_url",
             test_executor_.last_commands().at(0).add_mod().mod_name.at(0));
+  EXPECT_EQ("fuchsia-pkg://fuchsia.com/mod_url#meta/mod_url.cmx",
+            test_executor_.last_commands().at(0).add_mod().intent.handler);
   EXPECT_EQ(1, test_executor_.execute_count());
 }
 
@@ -111,8 +114,9 @@
   auto story_data = GetStoryData("s");
   ASSERT_TRUE(story_data);
   EXPECT_EQ("s", story_data->story_name);
-  EXPECT_EQ("m",
-            test_executor_.last_commands().at(0).add_mod().mod_name.at(0));
+  EXPECT_EQ("m", test_executor_.last_commands().at(0).add_mod().mod_name.at(0));
+  EXPECT_EQ("fuchsia-pkg://fuchsia.com/mod_url#meta/mod_url.cmx",
+            test_executor_.last_commands().at(0).add_mod().intent.handler);
   EXPECT_EQ(1, test_executor_.execute_count());
 }
 
diff --git a/bin/sessionctl/session_ctl_constants.h b/bin/sessionctl/session_ctl_constants.h
index df09d2e..40fb2cc 100644
--- a/bin/sessionctl/session_ctl_constants.h
+++ b/bin/sessionctl/session_ctl_constants.h
@@ -28,6 +28,11 @@
 // the user does not set a required flag.
 constexpr char kGetUsageErrorString[] = "GetUsage";
 
+// Fuchsia package paths for add_mod
+constexpr char kFuchsiaPkgPrefix[] = "fuchsia-pkg://";
+constexpr char kFuchsiaPkgPath[] = "fuchsia-pkg://fuchsia.com/%s#meta/%s.cmx";
+
+// hub paths to debug services.
 constexpr char kSessionCtlServiceGlobPath[] =
     "/hub/c/sessionmgr.cmx/*/out/debug/sessionctl";
 constexpr char kBasemgrDebugServiceGlobPath[] =