Add app-dir option alongside app-name

A .cmx file I use references a "test/" path instead of "bin/". This CL
allows passing in the directory of the binary.

Change-Id: I70db0b91b948d7daef3f027d099f8c65142acf89
diff --git a/src/command_line.rs b/src/command_line.rs
index c6e3f97..67cce85 100644
--- a/src/command_line.rs
+++ b/src/command_line.rs
@@ -68,6 +68,10 @@
     #[structopt(long)]
     cmx_path: Option<PathBuf>,
 
+    /// Directory of app as it appears in the manifest file.
+    #[structopt(long, default_value = "bin")]
+    app_dir: String,
+
     /// Name of app as it appears in the manifest file.
     #[structopt(long, default_value = "app")]
     app_name: String,
@@ -150,6 +154,10 @@
     #[structopt(long)]
     cmx_path: Option<PathBuf>,
 
+    /// Directory of app as it appears in the manifest file.
+    #[structopt(long, default_value = "bin")]
+    app_dir: String,
+
     /// Name of app as it appears in the manifest file.
     #[structopt(long, default_value = "app")]
     app_name: String,
@@ -178,6 +186,10 @@
     #[structopt(long)]
     run_with_sessionctl: bool,
 
+    /// Directory of app as it appears in the manifest file.
+    #[structopt(long, default_value = "bin")]
+    app_dir: String,
+
     /// Name of app as it appears in the manifest file.
     #[structopt(long, default_value = "app")]
     app_name: String,
@@ -224,6 +236,10 @@
     #[structopt(long)]
     run_with_sessionctl: bool,
 
+    /// Directory of app as it appears in the manifest file.
+    #[structopt(long, default_value = "bin")]
+    app_dir: String,
+
     /// Name of app as it appears in the manifest file.
     #[structopt(long, default_value = "app")]
     app_name: String,
@@ -306,6 +322,10 @@
     #[structopt(long)]
     cmx_path: Option<PathBuf>,
 
+    /// Directory of app as it appears in the manifest file.
+    #[structopt(long, default_value = "bin")]
+    app_dir: String,
+
     /// Name of app as it appears in the manifest file.
     #[structopt(long, default_value = "app")]
     app_name: String,
@@ -397,6 +417,7 @@
                     .release(autotest_opts.release)
                     .manifest_path(opt.manifest_path)
                     .cmx_path(autotest_opts.cmx_path)
+                    .app_dir(&Some(&autotest_opts.app_dir))
                     .app_name(&Some(&autotest_opts.app_name))
                     .nocapture(autotest_opts.nocapture),
                 &target_options,
@@ -432,6 +453,7 @@
                     disable_cross: opt.disable_cross_env,
                     manifest_path: None,
                     cmx_path: None,
+                    app_dir: None,
                     app_name: None,
                 },
                 cargo_opts.subcommand.as_ref(),
@@ -534,6 +556,7 @@
                     .run_mode(run_mode)
                     .story_name(&to_opt_str(&run.story_name))
                     .mod_name(&to_opt_str(&run.mod_name))
+                    .app_dir(&Some(&run.app_dir))
                     .app_name(&Some(&run.app_name))
                     .manifest_path(opt.manifest_path)
                     .cmx_path(run.cmx_path),
@@ -560,6 +583,7 @@
                 &run_cargo_options,
                 &run_on_target.story_name.unwrap_or(random_story_name()),
                 &run_on_target.mod_name.unwrap_or(DEFAULT_MOD_NAME.to_string()),
+                &run_on_target.app_dir,
                 &run_on_target.app_name,
                 &run_params,
                 None,
@@ -640,6 +664,7 @@
             return run_tests(
                 &run_cargo_options
                     .cmx_path(cmx_path)
+                    .app_dir(&Some(&test_opts.app_dir))
                     .app_name(&Some(&test_opts.app_name))
                     .run_mode(run_mode)
                     .release(test_opts.release)
diff --git a/src/lib.rs b/src/lib.rs
index be4deb0..75cf70b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -48,6 +48,7 @@
     run_cargo_options: &RunCargoOptions,
     story_name: &str,
     mod_name: &str,
+    app_dir: &str,
     app_name: &str,
     params: &[&str],
     test_args: Option<&str>,
@@ -55,7 +56,7 @@
     let source_path = PathBuf::from(&filename);
 
     let target_string =
-        make_package(verbose, target_options, &run_cargo_options, &source_path, app_name)?;
+        make_package(verbose, target_options, &run_cargo_options, &source_path, app_dir, app_name)?;
 
     let mut command_string = match run_mode {
         RunMode::Tiles => "tiles_ctl add ".to_string(),
@@ -254,6 +255,7 @@
     pub nocapture: bool,
     pub manifest_path: Option<PathBuf>,
     pub cmx_path: Option<PathBuf>,
+    pub app_dir: Option<String>,
     pub app_name: Option<String>,
 }
 
@@ -294,6 +296,10 @@
         Self { cmx_path, ..self.clone() }
     }
 
+    pub fn app_dir(&self, app_dir: &Option<&str>) -> RunCargoOptions {
+        Self { app_dir: app_dir.map(|name| name.to_string()), ..self.clone() }
+    }
+
     pub fn app_name(&self, app_name: &Option<&str>) -> RunCargoOptions {
         Self { app_name: app_name.map(|name| name.to_string()), ..self.clone() }
     }
@@ -384,6 +390,7 @@
     );
     let manifest_path_string;
     let cmx_arg = format!("--{}", CMX_PATH);
+    let app_dir_arg = format!("--{}", APP_DIR);
     let app_name_arg = format!("--{}", APP_NAME);
     let run_arg = format!("--{}", RUN_WITH_RUN);
     let nocapture_arg = format!("--{}", NOCAPTURE);
@@ -438,6 +445,11 @@
         runner_args.push(&args_for_target);
     }
 
+    if let Some(app_dir) = options.app_dir.as_ref() {
+        runner_args.push(&app_dir_arg);
+        runner_args.push(&app_dir);
+    }
+
     if let Some(app_name) = options.app_name.as_ref() {
         runner_args.push(&app_name_arg);
         runner_args.push(&app_name);
@@ -484,6 +496,7 @@
 ///         disable_cross: false,
 ///         manifest_path: None,
 ///         cmx_path: None,
+///         app_dir: None,
 ///         app_name: None,
 ///     },
 ///     "help",
@@ -642,6 +655,7 @@
 static RUN_WITH_RUN: &str = "run-with-run";
 static RUN_WITH_SESSIONCTL: &str = "run-with-sessionctl";
 static DEFAULT_MOD_NAME: &str = "fargo";
+static APP_DIR: &str = "app-dir";
 static APP_NAME: &str = "app-name";
 
 static NOCAPTURE: &str = "nocapture";
diff --git a/src/package.rs b/src/package.rs
index 2d5e25e..48b7bef 100644
--- a/src/package.rs
+++ b/src/package.rs
@@ -112,6 +112,7 @@
     package_path: &Path,
     cmx_path: &Path,
     package_name: &str,
+    app_dir: &str,
     app_name: &str,
 ) -> Result<(), Error> {
     if verbose {
@@ -189,7 +190,7 @@
 
     writeln!(
         manifest,
-        r#"bin/{}={}
+        r#"{}/{}={}
 lib/ld.so.1={}
 lib/libfdio.so={}
 lib/libsyslog.so={}
@@ -203,6 +204,7 @@
 {}
 {}
 "#,
+        app_dir,
         app_name,
         binary_path.to_string_lossy(),
         libc_path,
@@ -358,6 +360,7 @@
     target_options: &TargetOptions<'_, '_>,
     run_cargo_options: &RunCargoOptions,
     binary_path: &Path,
+    app_dir: &str,
     app_name: &str,
 ) -> Result<String, Error> {
     let temp_dir = tempdir()?;
@@ -400,6 +403,7 @@
         &package_path,
         &formatted_path,
         &package_name,
+        app_dir,
         app_name,
     )?;
     pm_build(verbose, &target_options, &manifest_path, &output_path).context("pm_build failed")?;