Use sessionctl to run mods

Testing: ran spinning_square_rs with fargo and cargo test

Change-Id: Id3fa20325f093c5ad73b1fb165a17f686d07e55b
diff --git a/src/lib.rs b/src/lib.rs
index 1bbd0b5..0478950 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -30,6 +30,7 @@
 use std::io::Write;
 use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::time::SystemTime;
 
 fn copy_to_target(
     source_path: &PathBuf, verbose: bool, config: &FuchsiaConfig,
@@ -54,21 +55,30 @@
 
 fn run_program_on_target(
     filename: &str, verbose: bool, nocapture: bool, config: &FuchsiaConfig,
-    target_options: &TargetOptions<'_, '_>, run_mode: RunMode, params: &[&str],
-    test_args: Option<&str>,
+    target_options: &TargetOptions<'_, '_>, run_mode: RunMode, story_name: &str, mod_name: &str,
+    params: &[&str], test_args: Option<&str>,
 ) -> Result<(), Error> {
     let source_path = PathBuf::from(&filename);
     let stripped_source_path = strip_binary(&source_path)?;
     let destination_path = copy_to_target(&stripped_source_path, verbose, config, target_options)?;
-    let mut command_string = (match run_mode {
-        RunMode::Tiles => "tiles_ctl add ",
-        RunMode::Ermine => "ermine_ctl add ",
-        RunMode::Run => "run ",
-        RunMode::Normal => "",
-    })
-    .to_string();
+    let mut command_string = match run_mode {
+        RunMode::Tiles => "tiles_ctl add ".to_string(),
+        RunMode::Ermine => format!(
+            "sessionctl --story_name={} --mod_name={} --mod_url=",
+            story_name, mod_name
+        ),
+        RunMode::Run => "run ".to_string(),
+        RunMode::Normal => "".to_string(),
+    };
     command_string.push_str(&destination_path);
 
+    match run_mode {
+        RunMode::Ermine => {
+            command_string.push_str(" add_mod");
+        }
+        _ => (),
+    }
+
     if nocapture {
         command_string.push_str(" --");
         command_string.push_str(NOCAPTURE);
@@ -220,7 +230,7 @@
 fn run_binary(
     run_cargo_options: &RunCargoOptions, target_options: &TargetOptions<'_, '_>, params: &[&str],
 ) -> Result<(), Error> {
-    run_cargo(run_cargo_options, "run", params, target_options, None, None)?;
+    run_cargo(run_cargo_options, RUN, params, target_options, None, None)?;
     Ok(())
 }
 
@@ -293,11 +303,21 @@
     }
 }
 
+fn random_story_name() -> String {
+    let secs = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
+        Ok(n) => n.as_secs(),
+        Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+    };
+    format!("fargo-story-{}", secs)
+}
+
 #[derive(Debug)]
 pub struct RunCargoOptions {
     pub verbose: bool,
     pub release: bool,
     pub run_mode: RunMode,
+    pub story_name: Option<String>,
+    pub mod_name: Option<String>,
     pub disable_cross: bool,
     pub nocapture: bool,
     pub manifest_path: Option<PathBuf>,
@@ -310,6 +330,8 @@
             release,
             nocapture: false,
             run_mode: RunMode::Normal,
+            story_name: None,
+            mod_name: None,
             disable_cross: false,
             manifest_path: None,
         }
@@ -321,6 +343,8 @@
             release: self.release,
             nocapture: self.nocapture,
             run_mode: self.run_mode,
+            story_name: self.story_name.clone(),
+            mod_name: self.mod_name.clone(),
             disable_cross,
             manifest_path: self.manifest_path.clone(),
         }
@@ -332,6 +356,8 @@
             release: release,
             nocapture: self.nocapture,
             run_mode: self.run_mode,
+            story_name: self.story_name.clone(),
+            mod_name: self.mod_name.clone(),
             disable_cross: self.disable_cross,
             manifest_path: self.manifest_path.clone(),
         }
@@ -343,6 +369,8 @@
             release: self.release,
             nocapture: nocapture,
             run_mode: self.run_mode,
+            story_name: self.story_name.clone(),
+            mod_name: self.mod_name.clone(),
             disable_cross: self.disable_cross,
             manifest_path: self.manifest_path.clone(),
         }
@@ -354,6 +382,34 @@
             release: self.release,
             nocapture: self.nocapture,
             run_mode: run_mode,
+            story_name: self.story_name.clone(),
+            mod_name: self.mod_name.clone(),
+            disable_cross: self.disable_cross,
+            manifest_path: self.manifest_path.clone(),
+        }
+    }
+
+    pub fn story_name(&self, story_name: &Option<&str>) -> RunCargoOptions {
+        RunCargoOptions {
+            verbose: self.verbose,
+            release: self.release,
+            nocapture: self.nocapture,
+            run_mode: self.run_mode,
+            story_name: story_name.map(|name| name.to_string()),
+            mod_name: self.mod_name.clone(),
+            disable_cross: self.disable_cross,
+            manifest_path: self.manifest_path.clone(),
+        }
+    }
+
+    pub fn mod_name(&self, mod_name: &Option<&str>) -> RunCargoOptions {
+        RunCargoOptions {
+            verbose: self.verbose,
+            release: self.release,
+            nocapture: self.nocapture,
+            run_mode: self.run_mode,
+            story_name: self.story_name.clone(),
+            mod_name: mod_name.map(|name| name.to_string()),
             disable_cross: self.disable_cross,
             manifest_path: self.manifest_path.clone(),
         }
@@ -365,10 +421,28 @@
             release: self.release,
             nocapture: self.nocapture,
             run_mode: self.run_mode,
+            story_name: self.story_name.clone(),
+            mod_name: self.mod_name.clone(),
             disable_cross: self.disable_cross,
             manifest_path: manifest_path,
         }
     }
+
+    pub fn get_story_name(&self) -> String {
+        if let Some(ref name) = self.story_name {
+            name.clone()
+        } else {
+            random_story_name()
+        }
+    }
+
+    pub fn get_mod_name(&self) -> String {
+        if let Some(ref name) = self.mod_name {
+            name.clone()
+        } else {
+            DEFAULT_MOD_NAME.to_string()
+        }
+    }
 }
 
 fn get_triple_cpu(target_options: &TargetOptions<'_, '_>) -> String {
@@ -414,9 +488,14 @@
     runner: Option<PathBuf>, options: &RunCargoOptions, nocapture: bool,
     target_options: &TargetOptions<'_, '_>, additional_target_args: Option<&str>,
 ) -> Result<String, Error> {
-    let tiles_arg = format!("--{}", TILES);
-    let ermine_arg = format!("--{}", ERMINE);
-    let run_arg = format!("--{}", RUN);
+    let tiles_arg = format!("--{}", RUN_WITH_TILES);
+    let ermine_arg = format!(
+        "--{} --story-name={} --mod-name={}",
+        RUN_WITH_SESSIONCTL,
+        options.get_story_name(),
+        options.get_mod_name()
+    );
+    let run_arg = format!("--{}", RUN_WITH_RUN);
     let nocapture_arg = format!("--{}", NOCAPTURE);
 
     let fargo_path = if runner.is_some() {
@@ -486,6 +565,8 @@
 ///         release: true,
 ///         nocapture: false,
 ///         run_mode: RunMode::Normal,
+///         story_name: None,
+///         mod_name: None,
 ///         disable_cross: false,
 ///         manifest_path: None,
 ///     },
@@ -657,9 +738,13 @@
     Ok(())
 }
 
-static TILES: &str = "run-with-tiles";
-static RUN: &str = "run-with-run";
-static ERMINE: &str = "run-with-ermine";
+static RUN: &str = "run";
+static RUN_WITH_TILES: &str = "run-with-tiles";
+static RUN_WITH_RUN: &str = "run-with-run";
+static RUN_WITH_SESSIONCTL: &str = "run-with-sessionctl";
+static STORY_NAME: &str = "story-name";
+static MOD_NAME: &str = "mod-name";
+static DEFAULT_MOD_NAME: &str = "fargo";
 
 static CHECK: &str = "check";
 static RELEASE: &str = "release";
@@ -822,19 +907,37 @@
                     ),
             )
             .subcommand(
-                SubCommand::with_name("run")
+                SubCommand::with_name(RUN)
                     .about("Run binary on Fuchsia device or emulator")
                     .arg(Arg::with_name(RELEASE).long(RELEASE).help(RELEASE_HELP))
                     .arg(
-                        Arg::with_name(TILES)
-                            .long(TILES)
+                        Arg::with_name(STORY_NAME)
+                            .long(STORY_NAME)
+                            .short("n")
+                            .value_name(STORY_NAME)
+                            .help("Name of story to pass to sessionctl"),
+                    )
+                    .arg(
+                        Arg::with_name(MOD_NAME)
+                            .long(MOD_NAME)
+                            .short("m")
+                            .value_name(MOD_NAME)
+                            .help("Name of mod to pass to sessionctl"),
+                    )
+                    .arg(
+                        Arg::with_name(RUN_WITH_TILES)
+                            .long(RUN_WITH_TILES)
                             .help("Use tiles_ctl add to run binary."),
                     )
-                    .arg(Arg::with_name(RUN).long(RUN).help("Use run to run binary."))
                     .arg(
-                        Arg::with_name(ERMINE)
-                            .long(ERMINE)
-                            .help("Use ermine_ctl to run binary."),
+                        Arg::with_name(RUN_WITH_RUN)
+                            .long(RUN_WITH_RUN)
+                            .help("Use run to run binary."),
+                    )
+                    .arg(
+                        Arg::with_name(RUN_WITH_SESSIONCTL)
+                            .long(RUN_WITH_SESSIONCTL)
+                            .help("Use sessionctl to run binary."),
                     )
                     .arg(
                         Arg::with_name("example")
@@ -917,15 +1020,33 @@
                             .help("Display all output when running tests."),
                     )
                     .arg(
-                        Arg::with_name(TILES)
-                            .long(TILES)
+                        Arg::with_name(RUN_WITH_TILES)
+                            .long(RUN_WITH_TILES)
                             .help("Use tiles to run binary."),
                     )
-                    .arg(Arg::with_name(RUN).long(RUN).help("Use run to run binary."))
                     .arg(
-                        Arg::with_name(ERMINE)
-                            .long(ERMINE)
-                            .help("Use ermine_ctl to run binary."),
+                        Arg::with_name(RUN_WITH_RUN)
+                            .long(RUN_WITH_RUN)
+                            .help("Use run to run binary."),
+                    )
+                    .arg(
+                        Arg::with_name(RUN_WITH_SESSIONCTL)
+                            .long(RUN_WITH_SESSIONCTL)
+                            .help("Use sessionctl to run binary."),
+                    )
+                    .arg(
+                        Arg::with_name(STORY_NAME)
+                            .long(STORY_NAME)
+                            .short("n")
+                            .value_name(STORY_NAME)
+                            .help("Name of story to pass to sessionctl"),
+                    )
+                    .arg(
+                        Arg::with_name(MOD_NAME)
+                            .long(MOD_NAME)
+                            .short("m")
+                            .value_name(MOD_NAME)
+                            .help("Name of mod to pass to sessionctl"),
                     )
                     .arg(
                         Arg::with_name("run_on_target_params")
@@ -969,6 +1090,8 @@
         release: false,
         nocapture: false,
         run_mode: RunMode::Normal,
+        story_name: None,
+        mod_name: None,
         disable_cross,
         manifest_path: None,
     };
@@ -1053,7 +1176,7 @@
         return Ok(());
     }
 
-    if let Some(run_matches) = matches.subcommand_matches("run") {
+    if let Some(run_matches) = matches.subcommand_matches(RUN) {
         let mut params = vec![];
         if let Some(example) = run_matches.value_of("example") {
             params.push("--example");
@@ -1062,14 +1185,16 @@
 
         let manifest_path = convert_manifest_path(&run_matches.value_of(MANIFEST_PATH));
         let run_mode = run_switches_to_mode(
-            run_matches.is_present(TILES),
-            run_matches.is_present(RUN),
-            run_matches.is_present(ERMINE),
+            run_matches.is_present(RUN_WITH_TILES),
+            run_matches.is_present(RUN_WITH_RUN),
+            run_matches.is_present(RUN_WITH_SESSIONCTL),
         );
         return run_binary(
             &run_cargo_options
                 .release(run_matches.is_present(RELEASE))
                 .run_mode(run_mode)
+                .story_name(&run_matches.value_of(STORY_NAME))
+                .mod_name(&run_matches.value_of(MOD_NAME))
                 .manifest_path(manifest_path),
             &target_options,
             &params,
@@ -1173,6 +1298,8 @@
                 release: false,
                 nocapture: false,
                 run_mode: RunMode::Normal,
+                story_name: None,
+                mod_name: None,
                 disable_cross: disable_cross,
                 manifest_path: None,
             },
@@ -1192,9 +1319,9 @@
         let test_args = run_on_target_matches.value_of("test_args");
         let (program, args) = run_params.split_first().unwrap();
         let run_mode = run_switches_to_mode(
-            run_on_target_matches.is_present(TILES),
-            run_on_target_matches.is_present(RUN),
-            run_on_target_matches.is_present(ERMINE),
+            run_on_target_matches.is_present(RUN_WITH_TILES),
+            run_on_target_matches.is_present(RUN_WITH_RUN),
+            run_on_target_matches.is_present(RUN_WITH_SESSIONCTL),
         );
         return run_program_on_target(
             program,
@@ -1203,6 +1330,12 @@
             &fuchsia_config,
             &target_options,
             run_mode,
+            run_on_target_matches
+                .value_of(STORY_NAME)
+                .unwrap_or(&random_story_name()),
+            run_on_target_matches
+                .value_of(MOD_NAME)
+                .unwrap_or(DEFAULT_MOD_NAME),
             args,
             test_args,
         );