Use structopt instead of using Clap directly

Using structopt removes a lot of boiler plate and will
make it easier to move to argh later if that becomes
possible.

In the process, remove load-driver as Ben tells me
that this isn’t going to be the way Rust drivers
work moving forward.

Change-Id: I43c5b47d03f9b33d7dbd04ea8a84c46a8c3ff0fe
diff --git a/Cargo.lock b/Cargo.lock
index f902d83..fc8cc27 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -107,6 +107,7 @@
  "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "uname 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -176,6 +177,14 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "inotify"
 version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -310,6 +319,16 @@
 ]
 
 [[package]]
+name = "proc-macro-error"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "0.4.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -318,6 +337,14 @@
 ]
 
 [[package]]
+name = "proc-macro2"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "quote"
 version = "0.6.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -326,6 +353,14 @@
 ]
 
 [[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "redox_syscall"
 version = "0.1.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -384,6 +419,27 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "structopt"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt-derive 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "syn"
 version = "0.15.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -394,6 +450,16 @@
 ]
 
 [[package]]
+name = "syn"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "synstructure"
 version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -429,6 +495,11 @@
 ]
 
 [[package]]
+name = "unicode-segmentation"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "unicode-width"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -439,6 +510,11 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "vec_map"
 version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -519,6 +595,7 @@
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
 "checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
 "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
 "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
@@ -533,8 +610,11 @@
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
 "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
 "checksum notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3572d71f13ea8ed41867accd971fd564aa75934cf7a1fae03ddb8c74a8a49943"
+"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097"
 "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
+"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
 "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
+"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
 "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
 "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
 "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
@@ -544,13 +624,18 @@
 "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
 "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+"checksum structopt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ac9d6e93dd792b217bf89cda5c14566e3043960c6f9da890c2ba5d09d07804c"
+"checksum structopt-derive 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ae9e5165d463a0dea76967d021f8d0f9316057bf5163aa2a4843790e842ff37"
 "checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e"
+"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
 "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
 "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
 "checksum uname 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8"
+"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
 "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
 "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
 "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
 "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
diff --git a/Cargo.toml b/Cargo.toml
index 6c5f426..d07347e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@
 serde = "1.0"
 serde_derive = "1.0"
 serde_json = "1.0"
+structopt = "0.3"
 toml = "0.4"
 
 [[bin]]
diff --git a/src/bin/fargo.rs b/src/bin/fargo.rs
index 895fa0d..6ab5eff 100644
--- a/src/bin/fargo.rs
+++ b/src/bin/fargo.rs
@@ -1,6 +1,6 @@
 #![recursion_limit = "1024"]
 
-use fargo::run;
+use fargo::command_line::run;
 use itertools::Itertools;
 
 fn main() {
diff --git a/src/command_line.rs b/src/command_line.rs
new file mode 100644
index 0000000..665b379
--- /dev/null
+++ b/src/command_line.rs
@@ -0,0 +1,637 @@
+use crate::{
+    autotest, build_binary, build_doc,
+    build_rustc::build_rustc,
+    check_binary,
+    cross::run_pkg_config,
+    device::{netls, ssh, start_emulator, stop_emulator, StartEmulatorOptions},
+    sdk::TargetOptions,
+    enable_networking, format_project,
+    package::make_package,
+    random_story_name, run_binary, run_cargo, run_configure, run_program_on_target,
+    run_switches_to_mode, run_tests, write_config, FuchsiaConfig, RunCargoOptions, RunMode,
+    DEFAULT_MOD_NAME,
+};
+use failure::Error;
+use std::path::PathBuf;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+enum FargoCommand {
+    /// Auto build and test in Fuchsia device or emulator
+    Autotest(Autotest),
+    /// Build binary targeting Fuchsia device or emulator
+    Build(Build),
+    /// Build rustc targeting Fuchsia
+    BuildRustc(BuildRustc),
+    /// Run a cargo command for Fuchsia. Use -- to indicate that all following arguments should be
+    /// passed to cargo.
+    Cargo(Cargo),
+    /// Check binary targeting Fuchsia device or emulator
+    Check(Build),
+    /// Run a configure script for the cross compilation environment
+    Configure(Configure),
+    /// Build a package's documentation
+    Doc(Doc),
+    /// Enable networking for a running emulator
+    EnableNetworking,
+    /// Run cargo fmt using the Fuchsia toolchain
+    Fmt,
+    /// List visible Fuchsia devices
+    ListDevices,
+    /// Make a Fuchsia package from an unstripped binary
+    MakePackage(MakePackage),
+    /// Run pkg-config for the cross compilation environment
+    PkgConfig(PkgConfig),
+    /// Stop all Fuchsia emulators and start a new one
+    Restart(Start),
+    /// Act as as custom runner for Cargo targeting a Fuchsia device
+    RunOnTarget(RunOnTarget),
+    /// Run binary on Fuchsia device or emulator
+    Run(Run),
+    /// Open a shell on Fuchsia device or emulator
+    Ssh,
+    /// Start a Fuchsia emulator
+    Start(Start),
+    /// Stop all Fuchsia emulators
+    Stop,
+    /// Run unit tests on Fuchsia device or emulator
+    Test(Test),
+    /// Write a .cargo/config file to allow cargo to operate correctly for Fuchsia
+    WriteConfig,
+}
+
+#[derive(Debug, StructOpt)]
+struct Autotest {
+    /// Build artifacts in release mode, with optimizations.
+    #[structopt(long)]
+    release: bool,
+
+    /// Path to sandbox file to use when running.
+    #[structopt(long)]
+    cmx_path: Option<PathBuf>,
+
+    /// Display all output when running tests.
+    #[structopt(long)]
+    nocapture: bool,
+}
+
+#[derive(Debug, StructOpt)]
+struct Build {
+    /// Build artifacts in release mode, with optimizations.
+    #[structopt(long)]
+    release: bool,
+
+    /// Build artifacts in release mode, with optimizations.
+    #[structopt(short = "p", long)]
+    package: Option<String>,
+
+    /// Name of the bin target to run.
+    #[structopt(long)]
+    bin: Option<String>,
+
+    /// Build only the specified test target.
+    #[structopt(long)]
+    test: Option<String>,
+
+    /// Build all the tests.
+    #[structopt(long)]
+    tests: bool,
+
+    /// Build a specific example from the examples/ dir.
+    #[structopt(long)]
+    example: Option<String>,
+
+    /// Build all the examples.
+    #[structopt(long)]
+    examples: bool,
+}
+
+#[derive(Debug, StructOpt)]
+struct BuildRustc {
+    #[structopt(long)]
+    rust_root: PathBuf,
+}
+
+#[derive(Debug, StructOpt)]
+struct Cargo {
+    subcommand: String,
+    cargo_params: Vec<String>,
+}
+
+#[derive(Debug, StructOpt)]
+struct Configure {
+    /// Don't pass --host to configure.
+    #[structopt(long)]
+    no_host: bool,
+
+    configure_params: Vec<String>,
+}
+
+#[derive(Debug, StructOpt)]
+struct Doc {
+    /// Opens the docs in a browser after the operation
+    #[structopt(long)]
+    open: bool,
+
+    /// Don't build documentation for dependencies
+    #[structopt(long)]
+    no_deps: bool,
+}
+
+#[derive(Debug, StructOpt)]
+struct MakePackage {
+    /// Path to the binary to package
+    #[structopt(long)]
+    binary_path: PathBuf,
+
+    /// Path to sandbox file to use when running.
+    #[structopt(long)]
+    cmx_path: PathBuf,
+
+    /// Name of app as it appears in the manifest file.
+    #[structopt(long, default_value = "app")]
+    app_name: String,
+}
+
+#[derive(Debug, StructOpt)]
+struct PkgConfig {
+    pkg_config_params: Vec<String>,
+}
+
+#[derive(Debug, StructOpt)]
+struct Run {
+    /// Build artifacts in release mode, with optimizations.
+    #[structopt(long)]
+    release: bool,
+
+    /// Use run to run the binary.
+    #[structopt(long)]
+    run_with_run: bool,
+
+    /// Use tiles_ctl add to run the binary.
+    #[structopt(long)]
+    run_with_tiles: bool,
+
+    /// Use Use sessionctl to run the binary.
+    #[structopt(long)]
+    run_with_sessionctl: bool,
+
+    /// Name of app as it appears in the manifest file.
+    #[structopt(long, default_value = "app")]
+    app_name: String,
+
+    /// Name of story to pass to sessionctl.
+    #[structopt(short = "n", long)]
+    story_name: Option<String>,
+
+    /// Name of mod to pass to sessionctl.
+    #[structopt(short, long)]
+    mod_name: Option<String>,
+
+    /// Path to sandbox file to use when running.
+    #[structopt(long)]
+    cmx_path: Option<PathBuf>,
+
+    /// Package to build.
+    #[structopt(short, long)]
+    package: Option<String>,
+
+    /// Name of the bin target to run.
+    #[structopt(long)]
+    bin: Option<String>,
+
+    /// Run a specific example from the examples/ dir.
+    #[structopt(long)]
+    example: Option<String>,
+}
+
+#[derive(Debug, StructOpt)]
+struct RunOnTarget {
+    /// Path to the binary to run.
+    binary_to_run: String,
+
+    /// Use run to run the binary.
+    #[structopt(long)]
+    run_with_run: bool,
+
+    /// Use tiles_ctl add to run the binary.
+    #[structopt(long)]
+    run_with_tiles: bool,
+
+    /// Use Use sessionctl to run the binary.
+    #[structopt(long)]
+    run_with_sessionctl: bool,
+
+    /// Name of app as it appears in the manifest file.
+    #[structopt(long, default_value = "app")]
+    app_name: String,
+
+    /// Name of story to pass to sessionctl.
+    #[structopt(short = "n", long)]
+    story_name: Option<String>,
+
+    /// Name of mod to pass to sessionctl.
+    #[structopt(short, long)]
+    mod_name: Option<String>,
+
+    /// Path to sandbox file to use when running.
+    #[structopt(long)]
+    cmx_path: Option<PathBuf>,
+
+    /// Additional arguments for the binary.
+    runner_args: Vec<String>,
+
+    /// Display all output when running tests.
+    #[structopt(long)]
+    nocapture: bool,
+}
+
+#[derive(Debug, StructOpt)]
+struct Start {
+    /// Start a simulator with graphics enabled.
+    #[structopt(short = "g")]
+    graphics: bool,
+
+    /// Start a simulator with KVM (Linux only)
+    #[structopt(short = "k")]
+    kvm: bool,
+
+    /// Don't set up networking
+    #[structopt(long)]
+    no_net: bool,
+
+    /// Do not launch the virtual console service if this option is present
+    #[structopt(long)]
+    disable_virtcon: bool,
+    start_params: Vec<String>,
+}
+
+#[derive(Debug, StructOpt)]
+struct Test {
+    /// Build artifacts in release mode, with optimizations.
+    #[structopt(long)]
+    release: bool,
+
+    /// Use run to run the test.
+    #[structopt(long)]
+    run_with_run: bool,
+
+    #[structopt(long)]
+    /// Test only the specified test target.
+    test: Option<String>,
+
+    /// Display all output when running tests.
+    #[structopt(long)]
+    nocapture: bool,
+
+    /// Name of the bin target to test.
+    #[structopt(long)]
+    bin: Option<String>,
+
+    /// RunTest a specific example from the examples/ dir.
+    #[structopt(long)]
+    example: Option<String>,
+
+    /// Arguments to pass to the test runner.
+    #[structopt(long)]
+    test_args: Option<String>,
+
+    /// Path to sandbox file to use when testing via run.
+    #[structopt(long)]
+    cmx_path: Option<PathBuf>,
+
+    /// Package to build.
+    #[structopt(short, long)]
+    package: Option<String>,
+
+    test_params: Vec<String>,
+}
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "fargo", about = "Fargo is a prototype Fuchsia-specific wrapper around Cargo.")]
+struct FargoOption {
+    /// Print verbose output while performing commands
+    #[structopt(short, long)]
+    verbose: bool,
+
+    /// Disable the setting of CC, AR and such environmental variables
+    #[structopt(long)]
+    disable_cross_env: bool,
+
+    /// Name of device to target, needed if there are multiple devices visible on the network
+    #[structopt(short = "N", long)]
+    device_name: Option<String>,
+
+    /// Path to Cargo.toml
+    #[structopt(long, global = true)]
+    manifest_path: Option<PathBuf>,
+
+    #[structopt(subcommand)]
+    command: FargoCommand,
+}
+
+fn to_opt_str(value: &Option<String>) -> Option<&str> {
+    value.as_ref().map(String::as_str)
+}
+
+fn build_params(build_opts: &Build) -> Vec<&str> {
+    let mut params = vec![];
+    if let Some(package) = build_opts.package.as_ref() {
+        params.push("--package");
+        params.push(package);
+    }
+    if let Some(bin) = build_opts.bin.as_ref() {
+        params.push("--bin");
+        params.push(bin);
+    }
+    if let Some(test) = build_opts.test.as_ref() {
+        params.push("--test");
+        params.push(&test);
+    }
+    if build_opts.tests {
+        params.push("--tests");
+    }
+    if let Some(example) = build_opts.example.as_ref() {
+        params.push("--example");
+        params.push(example);
+    }
+    if build_opts.examples {
+        params.push("--examples");
+    }
+    params
+}
+
+#[doc(hidden)]
+pub fn run() -> Result<(), Error> {
+    let opt = FargoOption::from_args();
+    let verbose = opt.verbose;
+    let fuchsia_config = FuchsiaConfig::new_from_fx_exec()?;
+    if verbose {
+        println!("fuchsia_config = {:#?}", fuchsia_config);
+    }
+
+    let target_options =
+        TargetOptions::new(&fuchsia_config, opt.device_name.as_ref().map(String::as_str));
+    let run_cargo_options = RunCargoOptions { verbose, ..RunCargoOptions::default() };
+
+    match opt.command {
+        FargoCommand::Autotest(autotest_opts) => {
+            return autotest(
+                &run_cargo_options
+                    .release(autotest_opts.release)
+                    .manifest_path(opt.manifest_path)
+                    .cmx_path(autotest_opts.cmx_path)
+                    .nocapture(autotest_opts.nocapture),
+                &target_options,
+            );
+        }
+
+        FargoCommand::Build(build_opts) => {
+            let params = build_params(&build_opts);
+            build_binary(
+                &run_cargo_options.release(build_opts.release).manifest_path(opt.manifest_path),
+                &target_options,
+                &params,
+            )?;
+            return Ok(());
+        }
+
+        FargoCommand::BuildRustc(build_rustc_opts) => {
+            return build_rustc(&build_rustc_opts.rust_root, &target_options);
+        }
+
+        FargoCommand::Cargo(cargo_opts) => {
+            let cargo_params: Vec<&str> =
+                cargo_opts.cargo_params.iter().map(String::as_str).collect();
+            return run_cargo(
+                &RunCargoOptions {
+                    verbose,
+                    release: false,
+                    nocapture: false,
+                    run_mode: RunMode::Normal,
+                    story_name: None,
+                    mod_name: None,
+                    disable_cross: opt.disable_cross_env,
+                    manifest_path: None,
+                    cmx_path: None,
+                    app_name: None,
+                },
+                cargo_opts.subcommand.as_ref(),
+                &cargo_params,
+                &target_options,
+                None,
+                None,
+            );
+        }
+
+        FargoCommand::Check(build_opts) => {
+            let params = build_params(&build_opts);
+            check_binary(
+                &run_cargo_options.release(build_opts.release).manifest_path(opt.manifest_path),
+                &target_options,
+                &params,
+            )?;
+            return Ok(());
+        }
+
+        FargoCommand::Configure(config_opts) => {
+            let configure_params: Vec<&str> =
+                config_opts.configure_params.iter().map(String::as_str).collect();
+            run_configure(opt.verbose, config_opts.no_host, &configure_params, &target_options)?;
+            return Ok(());
+        }
+
+        FargoCommand::Doc(doc_opts) => {
+            return build_doc(
+                &run_cargo_options.manifest_path(opt.manifest_path),
+                &target_options,
+                doc_opts.no_deps,
+                doc_opts.open,
+            );
+        }
+
+        FargoCommand::EnableNetworking => {
+            return enable_networking();
+        }
+
+        FargoCommand::Fmt => {
+            format_project(opt.manifest_path)?;
+            return Ok(());
+        }
+
+        FargoCommand::ListDevices => {
+            return netls(opt.verbose, &target_options);
+        }
+
+        FargoCommand::MakePackage(make_package_opts) => {
+            println!(
+                "make package {}",
+                make_package(
+                    verbose,
+                    &target_options,
+                    &make_package_opts.binary_path,
+                    &make_package_opts.cmx_path,
+                    &make_package_opts.app_name
+                )?
+            );
+            return Ok(());
+        }
+
+        FargoCommand::PkgConfig(pkg_config_opts) => {
+            let pkg_params: Vec<&str> =
+                pkg_config_opts.pkg_config_params.iter().map(String::as_str).collect();
+            let exit_code = run_pkg_config(verbose, &pkg_params, &target_options)?;
+            if exit_code != 0 {
+                ::std::process::exit(exit_code);
+            }
+            return Ok(());
+        }
+
+        FargoCommand::Restart(start_opts) => {
+            stop_emulator()?;
+
+            let fx_run_params: Vec<&str> =
+                start_opts.start_params.iter().map(String::as_str).collect();
+
+            return start_emulator(
+                &StartEmulatorOptions {
+                    verbose: verbose,
+                    with_graphics: start_opts.graphics,
+                    with_kvm: start_opts.kvm,
+                    with_networking: !start_opts.no_net,
+                    disable_virtcon: start_opts.disable_virtcon,
+                },
+                &fx_run_params,
+            );
+        }
+
+        FargoCommand::Run(run) => {
+            let mut params = vec![];
+
+            if let Some(package) = run.package.as_ref() {
+                params.push("--package");
+                params.push(package);
+            }
+            if let Some(bin) = run.bin.as_ref() {
+                params.push("--bin");
+                params.push(bin);
+            }
+
+            if let Some(example) = run.example.as_ref() {
+                params.push("--example");
+                params.push(example);
+            }
+
+            let run_mode =
+                run_switches_to_mode(run.run_with_tiles, run.run_with_run, run.run_with_sessionctl);
+            return run_binary(
+                &run_cargo_options
+                    .release(run.release)
+                    .run_mode(run_mode)
+                    .story_name(&to_opt_str(&run.story_name))
+                    .mod_name(&to_opt_str(&run.mod_name))
+                    .app_name(&Some(&run.app_name))
+                    .manifest_path(opt.manifest_path)
+                    .cmx_path(run.cmx_path),
+                &target_options,
+                &params,
+            );
+        }
+
+        FargoCommand::RunOnTarget(run_on_target) => {
+            let run_cargo_options = run_cargo_options.cmx_path(run_on_target.cmx_path);
+            let run_params: Vec<&str> = run_on_target.runner_args.iter().map(|s| &**s).collect();
+            let run_mode = run_switches_to_mode(
+                run_on_target.run_with_tiles,
+                run_on_target.run_with_run,
+                run_on_target.run_with_sessionctl,
+            );
+
+            return run_program_on_target(
+                &run_on_target.binary_to_run,
+                verbose,
+                run_on_target.nocapture,
+                &fuchsia_config,
+                &target_options,
+                run_mode,
+                &run_cargo_options.cmx_path,
+                &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_name,
+                &run_params,
+                None,
+            );
+        }
+
+        FargoCommand::Ssh => {
+            return ssh(opt.verbose, &fuchsia_config, &target_options, "");
+        }
+
+        FargoCommand::Start(start_opts) => {
+            let fx_run_params: Vec<&str> =
+                start_opts.start_params.iter().map(String::as_str).collect();
+
+            return start_emulator(
+                &StartEmulatorOptions {
+                    verbose: verbose,
+                    with_graphics: start_opts.graphics,
+                    with_kvm: start_opts.kvm,
+                    with_networking: !start_opts.no_net,
+                    disable_virtcon: start_opts.disable_virtcon,
+                },
+                &fx_run_params,
+            );
+        }
+
+        FargoCommand::Stop => {
+            return stop_emulator();
+        }
+
+        FargoCommand::Test(test_opts) => {
+            let mut params = vec![];
+            if let Some(package) = test_opts.package.as_ref() {
+                params.push("--package");
+                params.push(package);
+            }
+
+            if let Some(bin) = test_opts.bin.as_ref() {
+                params.push("--bin");
+                params.push(bin);
+            }
+
+            if let Some(example) = test_opts.example.as_ref() {
+                params.push("--example");
+                params.push(example);
+            }
+
+            let test_params: Vec<&str> = test_opts.test_params.iter().map(String::as_str).collect();
+
+            params.extend(test_params);
+
+            if let Some(test) = test_opts.test.as_ref() {
+                params.push("--test");
+                params.push(test);
+            }
+
+            let test_args = test_opts.test_args;
+
+            let run_mode = run_switches_to_mode(false, test_opts.run_with_run, false);
+            return run_tests(
+                &run_cargo_options
+                    .cmx_path(test_opts.cmx_path)
+                    .run_mode(run_mode)
+                    .release(test_opts.release)
+                    .manifest_path(opt.manifest_path)
+                    .nocapture(test_opts.nocapture),
+                false,
+                &target_options,
+                &params,
+                to_opt_str(&test_args),
+            );
+        }
+
+        FargoCommand::WriteConfig => {
+            return write_config(&run_cargo_options, &target_options);
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index b9b74a9..f83aa43 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,28 +12,26 @@
 mod cross;
 mod device;
 mod package;
+pub mod command_line;
 mod sdk;
 mod utils;
 
 pub use crate::sdk::{FuchsiaConfig, TargetOptions};
 
-use crate::build_rustc::build_rustc;
-use crate::cross::{pkg_config_path, run_configure, run_pkg_config};
+use crate::cross::{pkg_config_path, run_configure};
 use crate::device::{
-    enable_networking, netaddr, netls, scp_to_device, ssh, start_emulator, stop_emulator,
-    StartEmulatorOptions,
+    enable_networking, netaddr, scp_to_device, ssh,
 };
 use crate::package::make_package;
 use crate::{
     sdk::{
-        cargo_out_dir, cargo_path, clang_archiver_path, clang_c_compiler_path,
+        cargo_path, clang_archiver_path, clang_c_compiler_path,
         clang_cpp_compiler_path, clang_ranlib_path, clang_resource_dir, rustc_path, rustdoc_path,
         shared_libraries_path, sysroot_path, zircon_build_path,
     },
     utils::strip_binary,
 };
 
-use clap::{App, AppSettings, Arg, SubCommand};
 use failure::{bail, err_msg, format_err, Error, ResultExt};
 use std::fs;
 use std::fs::File;
@@ -251,31 +249,7 @@
     if open {
         args.push("--open");
     }
-    run_cargo(run_cargo_options, DOC, &args, &target_options, None, None)
-}
-
-fn load_driver(
-    run_cargo_options: &RunCargoOptions,
-    config: &FuchsiaConfig,
-    target_options: &TargetOptions<'_, '_>,
-) -> Result<(), Error> {
-    let args = vec![];
-    run_cargo(run_cargo_options, "build", &args, target_options, None, None)?;
-    let cwd = std::env::current_dir()?;
-    let package = cwd
-        .file_name()
-        .ok_or(err_msg("No current directory"))?
-        .to_str()
-        .ok_or(err_msg("Invalid current directory"))?;
-    let filename = cargo_out_dir(target_options)?.join(format!("lib{}.so", package));
-    let destination_path =
-        copy_to_target(&filename, run_cargo_options.verbose, config, target_options)?;
-    let command_string = format!("dm add-driver:{}", destination_path);
-    if run_cargo_options.verbose {
-        println!("running {}", command_string);
-    }
-    ssh(run_cargo_options.verbose, config, target_options, &command_string)?;
-    Ok(())
+    run_cargo(run_cargo_options, "doc", &args, &target_options, None, None)
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -500,14 +474,6 @@
     Ok(runner_args.join(" "))
 }
 
-fn convert_manifest_path(possible_path: &Option<&str>) -> Option<PathBuf> {
-    if let Some(path) = possible_path {
-        Some(PathBuf::from(path))
-    } else {
-        None
-    }
-}
-
 fn format_project(manifest_path: Option<PathBuf>) -> Result<(), Error> {
     let mut cmd = Command::new(cargo_path()?);
     if let Some(ref manifest_path) = manifest_path {
@@ -699,836 +665,17 @@
 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 APP_NAME: &str = "app-name";
-static DEFAULT_APP_NAME: &str = "app";
 
-static CHECK: &str = "check";
-static RELEASE: &str = "release";
-static EXAMPLE: &str = "example";
-static EXAMPLES: &str = "examples";
-
-static TEST: &str = "test";
-static TEST_TARGET_NAME: &str = "test";
 static NOCAPTURE: &str = "nocapture";
 
-static DOC: &str = "doc";
-static DOC_OPEN: &str = "open";
-static DOC_NO_DEPS: &str = "no-deps";
-
 static X64: &str = "x64";
 
-static SUBCOMMAND: &str = "subcommand";
-
-static DISABLE_CROSS_ENV: &str = "disable-cross-env";
-
-static NO_NET: &str = "no-net";
-static FX_RUN_PARAMS: &str = "fx-run-params";
-static MANIFEST_PATH: &str = "manifest-path";
 static CMX_PATH: &str = "cmx-path";
 
-static RELEASE_HELP: &str = "Build artifacts in release mode, with optimizations";
-
-static START: &str = "start";
-static RESTART: &str = "restart";
-static GRAPHICS: &str = "graphics";
-static KVM: &str = "kvm";
-static DISABLE_VIRTCON: &str = "disable-virtcon";
-
-static WRITE_CONFIG: &str = "write-config";
-
-static BUILD_RUSTC: &str = "build-rustc";
-static RUST_ROOT: &str = "rust-root";
-
 static RUN_ON_TARGET: &str = "run-on-target";
 
-static MAKE_PACKAGE: &str = "make-package";
-static BINARY_PATH: &str = "binary-path";
-
 static FORMAT: &str = "fmt";
 
-/// Arguments which configure the startup of an emulator.
-///
-/// Used when `start`ing or `restart`ing.
-fn emulator_args() -> Vec<Arg<'static, 'static>> {
-    vec![
-        Arg::with_name(GRAPHICS).short("g").help("Start a simulator with graphics enabled"),
-        Arg::with_name(KVM).short("k").help("Start a simulator with KVM (Linux only)"),
-        Arg::with_name(DISABLE_VIRTCON)
-            .long(DISABLE_VIRTCON)
-            .help("Do not launch the virtual console service if this option is present"),
-        Arg::with_name(NO_NET).long(NO_NET).help("Don't set up networking."),
-        Arg::with_name(FX_RUN_PARAMS).index(1).multiple(true),
-    ]
-}
 
-#[doc(hidden)]
-pub fn run() -> Result<(), Error> {
-    let emulator_args = emulator_args();
-
-    let global_matches = App::new("fargo")
-        .version("v0.2.0")
-        .setting(AppSettings::GlobalVersion)
-        .setting(AppSettings::ArgRequiredElseHelp)
-        .about("Fargo is a prototype Fuchsia-specific wrapper around Cargo")
-        .arg(
-            Arg::with_name("verbose")
-                .long("verbose")
-                .short("v")
-                .help("Print verbose output while performing commands"),
-        )
-        .arg(
-            Arg::with_name(DISABLE_CROSS_ENV)
-                .long(DISABLE_CROSS_ENV)
-                .help("Disable the setting of CC, AR and such environmental variables."),
-        )
-        .arg(
-            Arg::with_name("device-name")
-                .long("device-name")
-                .short("N")
-                .value_name("device-name")
-                .help(
-                    "Name of device to target, needed if there are multiple devices visible \
-                     on the network",
-                ),
-        )
-        .arg(
-            Arg::with_name(MANIFEST_PATH)
-                .long(MANIFEST_PATH)
-                .value_name(MANIFEST_PATH)
-                .global(true)
-                .help("Path to Cargo.toml"),
-        )
-        .subcommand(
-            SubCommand::with_name("autotest")
-                .about("Auto build and test in Fuchsia device or emulator")
-                .arg(
-                    Arg::with_name(CMX_PATH)
-                        .long(CMX_PATH)
-                        .value_name(CMX_PATH)
-                        .help("Path to sandbox file to use when running"),
-                )
-                .arg(Arg::with_name(RELEASE).long(RELEASE).help("Build release"))
-                .arg(
-                    Arg::with_name(NOCAPTURE)
-                        .long(NOCAPTURE)
-                        .help("Display all output when running tests."),
-                ),
-        )
-        .subcommand(
-            SubCommand::with_name(TEST)
-                .about("Run unit tests on Fuchsia device or emulator")
-                .arg(Arg::with_name(RELEASE).long(RELEASE).help(RELEASE_HELP))
-                .arg(
-                    Arg::with_name(NOCAPTURE)
-                        .long(NOCAPTURE)
-                        .help("Display all output when running tests."),
-                )
-                .arg(
-                    Arg::with_name(TEST_TARGET_NAME)
-                        .long(TEST_TARGET_NAME)
-                        .value_name(TEST_TARGET_NAME)
-                        .help("Test only the specified test target"),
-                )
-                .arg(
-                    Arg::with_name(EXAMPLE)
-                        .long(EXAMPLE)
-                        .takes_value(true)
-                        .help("Test a specific example from the examples/ dir."),
-                )
-                .arg(
-                    Arg::with_name("package")
-                        .short("p")
-                        .long("package")
-                        .takes_value(true)
-                        .help("Package to run tests for"),
-                )
-                .arg(
-                    Arg::with_name("bin")
-                        .long("bin")
-                        .value_name("bin")
-                        .help("Name of the bin target to run"),
-                )
-                .arg(
-                    Arg::with_name("test_args")
-                        .long("args")
-                        .value_name("args")
-                        .help("arguments to pass to the test runner"),
-                )
-                .arg(
-                    Arg::with_name(CMX_PATH)
-                        .long(CMX_PATH)
-                        .value_name(CMX_PATH)
-                        .help("Path to sandbox file to use when running"),
-                )
-                .arg(Arg::with_name(RUN_WITH_RUN).long(RUN_WITH_RUN).help("Use run to run tests."))
-                .arg(Arg::with_name("test_params").index(1).multiple(true)),
-        )
-        .subcommand(
-            SubCommand::with_name("build")
-                .about("Build binary targeting Fuchsia device or emulator")
-                .arg(Arg::with_name(RELEASE).long(RELEASE).help(RELEASE_HELP))
-                .arg(
-                    Arg::with_name("package")
-                        .short("p")
-                        .long("package")
-                        .takes_value(true)
-                        .help("Package to build"),
-                )
-                .arg(
-                    Arg::with_name("bin")
-                        .long("bin")
-                        .takes_value(true)
-                        .help("Name of the bin target to run"),
-                )
-                .arg(
-                    Arg::with_name("test")
-                        .long("test")
-                        .takes_value(true)
-                        .help("Build only the specified test target"),
-                )
-                .arg(Arg::with_name("tests").long("tests").help("Build all the tests"))
-                .arg(
-                    Arg::with_name(EXAMPLE)
-                        .long(EXAMPLE)
-                        .takes_value(true)
-                        .help("Build a specific example from the examples/ dir."),
-                )
-                .arg(
-                    Arg::with_name("examples")
-                        .long("examples")
-                        .help("Build all examples in the examples/ dir."),
-                ),
-        )
-        .subcommand(
-            SubCommand::with_name(CHECK)
-                .about("Check binary targeting Fuchsia device or emulator")
-                .arg(Arg::with_name(RELEASE).long(RELEASE).help(RELEASE_HELP))
-                .arg(
-                    Arg::with_name("package")
-                        .short("p")
-                        .long("package")
-                        .takes_value(true)
-                        .help("Package to build"),
-                )
-                .arg(
-                    Arg::with_name("bin")
-                        .long("bin")
-                        .takes_value(true)
-                        .help("Name of the bin target to run"),
-                )
-                .arg(
-                    Arg::with_name("test")
-                        .long("test")
-                        .takes_value(true)
-                        .help("Build only the specified test target"),
-                )
-                .arg(Arg::with_name("tests").long("tests").help("Build all the tests"))
-                .arg(
-                    Arg::with_name(EXAMPLE)
-                        .long(EXAMPLE)
-                        .takes_value(true)
-                        .help("Check a specific example from the examples/ dir."),
-                )
-                .arg(
-                    Arg::with_name(EXAMPLES)
-                        .long(EXAMPLES)
-                        .help("Check all examples in the examples/ dir."),
-                ),
-        )
-        .subcommand(
-            SubCommand::with_name(DOC)
-                .about("Build a package's documentation")
-                .arg(Arg::with_name(RELEASE).long(RELEASE).help(RELEASE_HELP))
-                .arg(
-                    Arg::with_name(DOC_NO_DEPS)
-                        .long(DOC_NO_DEPS)
-                        .help("Don't build documentation for dependencies"),
-                )
-                .arg(
-                    Arg::with_name(DOC_OPEN)
-                        .long(DOC_OPEN)
-                        .help("Opens the docs in a browser after the operation"),
-                ),
-        )
-        .subcommand(
-            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(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(APP_NAME)
-                        .long(APP_NAME)
-                        .value_name(APP_NAME)
-                        .default_value(DEFAULT_APP_NAME)
-                        .help("Name of app as it appears in the manifest file."),
-                )
-                .arg(
-                    Arg::with_name(CMX_PATH)
-                        .long(CMX_PATH)
-                        .value_name(CMX_PATH)
-                        .help("Path to sandbox file to use when running"),
-                )
-                .arg(
-                    Arg::with_name(RUN_WITH_TILES)
-                        .long(RUN_WITH_TILES)
-                        .help("Use tiles_ctl add to run binary."),
-                )
-                .arg(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("package")
-                        .short("p")
-                        .long("package")
-                        .value_name("package")
-                        .help("Package to build"),
-                )
-                .arg(
-                    Arg::with_name("bin")
-                        .long("bin")
-                        .value_name("bin")
-                        .help("Name of the bin target to run"),
-                )
-                .arg(
-                    Arg::with_name(EXAMPLE)
-                        .long(EXAMPLE)
-                        .value_name(EXAMPLE)
-                        .help("Run a specific example from the examples/ dir."),
-                ),
-        )
-        .subcommand(
-            SubCommand::with_name("load-driver")
-                .about("Build driver and load it on Fuchsia device or emulator.")
-                .arg(Arg::with_name(RELEASE).long(RELEASE).help("Build release")),
-        )
-        .subcommand(SubCommand::with_name("list-devices").about("List visible Fuchsia devices"))
-        .subcommand(
-            SubCommand::with_name(START).about("Start a Fuchsia emulator").args(&emulator_args),
-        )
-        .subcommand(SubCommand::with_name("stop").about("Stop all Fuchsia emulators"))
-        .subcommand(
-            SubCommand::with_name("enable-networking")
-                .about("Enable networking for a running emulator"),
-        )
-        .subcommand(
-            SubCommand::with_name(RESTART)
-                .about("Stop all Fuchsia emulators and start a new one")
-                .args(&emulator_args),
-        )
-        .subcommand(
-            SubCommand::with_name("ssh").about("Open a shell on Fuchsia device or emulator"),
-        )
-        .subcommand(
-            SubCommand::with_name("cargo")
-                .about(
-                    "Run a cargo command for Fuchsia. Use -- to indicate that all following \
-                     arguments should be passed to cargo.",
-                )
-                .arg(Arg::with_name(SUBCOMMAND).required(true))
-                .arg(Arg::with_name("cargo_params").index(2).multiple(true)),
-        )
-        .subcommand(
-            SubCommand::with_name(RUN_ON_TARGET)
-                .about("Act as a test runner for cargo")
-                .arg(
-                    Arg::with_name("test_args")
-                        .long("args")
-                        .value_name("args")
-                        .help("arguments to pass to the test runner"),
-                )
-                .arg(
-                    Arg::with_name(CMX_PATH)
-                        .long(CMX_PATH)
-                        .value_name(CMX_PATH)
-                        .help("Path to sandbox file to use when running"),
-                )
-                .arg(
-                    Arg::with_name(NOCAPTURE)
-                        .long(NOCAPTURE)
-                        .help("Display all output when running tests."),
-                )
-                .arg(
-                    Arg::with_name(RUN_WITH_TILES)
-                        .long(RUN_WITH_TILES)
-                        .help("Use tiles to run binary."),
-                )
-                .arg(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(APP_NAME)
-                        .long(APP_NAME)
-                        .value_name(APP_NAME)
-                        .default_value(DEFAULT_APP_NAME)
-                        .help("Name of app"),
-                )
-                .arg(Arg::with_name("run_on_target_params").index(1).multiple(true))
-                .setting(AppSettings::Hidden),
-        )
-        .subcommand(
-            SubCommand::with_name("pkg-config")
-                .about("Run pkg-config for the cross compilation environment")
-                .arg(Arg::with_name("pkgconfig_param").index(1).multiple(true)),
-        )
-        .subcommand(
-            SubCommand::with_name("configure")
-                .about("Run a configure script for the cross compilation environment")
-                .arg(Arg::with_name("configure_param").index(1).multiple(true))
-                .arg(
-                    Arg::with_name("no-host")
-                        .long("no-host")
-                        .help("Don't pass --host to configure"),
-                ),
-        )
-        .subcommand(
-            SubCommand::with_name(WRITE_CONFIG).about(
-                "Write a .cargo/config file to allow cargo to operate correctly for Fuchsia",
-            ),
-        )
-        .subcommand(
-            SubCommand::with_name(BUILD_RUSTC)
-                .arg(
-                    Arg::with_name(RUST_ROOT)
-                        .long(RUST_ROOT)
-                        .value_name(RUST_ROOT)
-                        .required(true)
-                        .help("Path to rust checkout"),
-                )
-                .about("Build rustc targeting Fuchsia"),
-        )
-        .subcommand(
-            SubCommand::with_name(MAKE_PACKAGE)
-                .arg(
-                    Arg::with_name(BINARY_PATH)
-                        .long(BINARY_PATH)
-                        .value_name(BINARY_PATH)
-                        .required(true)
-                        .help("Path to the binary to package"),
-                )
-                .arg(
-                    Arg::with_name(CMX_PATH)
-                        .long(CMX_PATH)
-                        .value_name(CMX_PATH)
-                        .help("Path to sandbox file to use when running"),
-                )
-                .arg(
-                    Arg::with_name(APP_NAME)
-                        .long(APP_NAME)
-                        .value_name(APP_NAME)
-                        .default_value(DEFAULT_APP_NAME)
-                        .help("Name of app"),
-                )
-                .about("Make a Fuchsia package from an unstripped binary"),
-        )
-        .subcommand(
-            SubCommand::with_name(FORMAT).about("Run cargo fmt using the Fuchsia toolchain"),
-        )
-        .get_matches();
-
-    let verbose = global_matches.is_present("verbose");
-    let disable_cross = global_matches.is_present(DISABLE_CROSS_ENV);
-
-    let fuchsia_config = FuchsiaConfig::new_from_fx_exec()?;
-    if verbose {
-        println!("fuchsia_config = {:#?}", fuchsia_config);
-    }
-
-    let target_options =
-        TargetOptions::new(&fuchsia_config, global_matches.value_of("device-name"));
-
-    let run_cargo_options = RunCargoOptions { verbose, ..RunCargoOptions::default() };
-
-    if verbose {
-        println!("target_options = {:#?}", target_options);
-    }
-
-    if let Some(autotest_matches) = global_matches.subcommand_matches("autotest") {
-        let manifest_path = convert_manifest_path(&autotest_matches.value_of(MANIFEST_PATH));
-        return autotest(
-            &run_cargo_options
-                .release(autotest_matches.is_present(RELEASE))
-                .manifest_path(manifest_path)
-                .cmx_path(autotest_matches.value_of(CMX_PATH).map(|s| PathBuf::from(s)))
-                .nocapture(autotest_matches.is_present(NOCAPTURE)),
-            &target_options,
-        );
-    }
-
-    if let Some(test_matches) = global_matches.subcommand_matches(TEST) {
-        let mut params = vec![];
-        if let Some(package) = test_matches.value_of("package") {
-            params.push("--package");
-            params.push(package);
-        }
-        if let Some(bin) = test_matches.value_of("bin") {
-            params.push("--bin");
-            params.push(bin);
-        }
-        if let Some(example) = test_matches.value_of(EXAMPLE) {
-            params.push("--example");
-            params.push(example);
-        }
-        if let Some(test_params) = test_matches.values_of("test_params") {
-            params.extend(test_params.collect::<Vec<_>>());
-        }
-        if let Some(test) = test_matches.value_of(TEST_TARGET_NAME) {
-            params.push("--test");
-            params.push(test);
-        }
-
-        let test_args = test_matches.value_of("test_args");
-        let manifest_path = convert_manifest_path(&test_matches.value_of(MANIFEST_PATH));
-        let run_mode = run_switches_to_mode(
-            test_matches.is_present(RUN_WITH_TILES),
-            test_matches.is_present(RUN_WITH_RUN),
-            test_matches.is_present(RUN_WITH_SESSIONCTL),
-        );
-        return run_tests(
-            &run_cargo_options
-                .cmx_path(test_matches.value_of(CMX_PATH).map(|s| PathBuf::from(s)))
-                .run_mode(run_mode)
-                .release(test_matches.is_present(RELEASE))
-                .manifest_path(manifest_path)
-                .nocapture(test_matches.is_present(NOCAPTURE)),
-            false,
-            &target_options,
-            &params,
-            test_args,
-        );
-    }
-
-    if let Some(build_matches) = global_matches.subcommand_matches("build") {
-        let mut params = vec![];
-        if let Some(package) = build_matches.value_of("package") {
-            params.push("--package");
-            params.push(package);
-        }
-        if let Some(bin) = build_matches.value_of("bin") {
-            params.push("--bin");
-            params.push(bin);
-        }
-        if let Some(test) = build_matches.value_of("test") {
-            params.push("--test");
-            params.push(test);
-        }
-        if build_matches.is_present("tests") {
-            params.push("--tests");
-        }
-        if let Some(example) = build_matches.value_of(EXAMPLE) {
-            params.push("--example");
-            params.push(example);
-        }
-        if build_matches.is_present("examples") {
-            params.push("--examples");
-        }
-
-        let manifest_path = convert_manifest_path(&build_matches.value_of(MANIFEST_PATH));
-        build_binary(
-            &run_cargo_options
-                .release(build_matches.is_present(RELEASE))
-                .manifest_path(manifest_path),
-            &target_options,
-            &params,
-        )?;
-        return Ok(());
-    }
-
-    if let Some(check_matches) = global_matches.subcommand_matches(CHECK) {
-        let mut params = vec![];
-        if let Some(example) = check_matches.value_of(EXAMPLE) {
-            params.push("--example");
-            params.push(example);
-        }
-        if let Some(package) = check_matches.value_of("package") {
-            params.push("--package");
-            params.push(package);
-        }
-        if let Some(bin) = check_matches.value_of("bin") {
-            params.push("--bin");
-            params.push(bin);
-        }
-        if let Some(test) = check_matches.value_of("test") {
-            params.push("--test");
-            params.push(test);
-        }
-        if check_matches.is_present("tests") {
-            params.push("--tests");
-        }
-        if check_matches.is_present(EXAMPLES) {
-            params.push("--examples");
-        }
-
-        let manifest_path = convert_manifest_path(&check_matches.value_of(MANIFEST_PATH));
-        check_binary(
-            &run_cargo_options
-                .release(check_matches.is_present(RELEASE))
-                .manifest_path(manifest_path),
-            &target_options,
-            &params,
-        )?;
-        return Ok(());
-    }
-
-    if let Some(run_matches) = global_matches.subcommand_matches(RUN) {
-        let mut params = vec![];
-        if let Some(package) = run_matches.value_of("package") {
-            params.push("--package");
-            params.push(package);
-        }
-        if let Some(bin) = run_matches.value_of("bin") {
-            params.push("--bin");
-            params.push(bin);
-        }
-        if let Some(example) = run_matches.value_of(EXAMPLE) {
-            params.push("--example");
-            params.push(example);
-        }
-
-        let manifest_path = convert_manifest_path(&run_matches.value_of(MANIFEST_PATH));
-        let run_mode = run_switches_to_mode(
-            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))
-                .app_name(&run_matches.value_of(APP_NAME))
-                .manifest_path(manifest_path)
-                .cmx_path(run_matches.value_of(CMX_PATH).map(|s| PathBuf::from(s))),
-            &target_options,
-            &params,
-        );
-    }
-
-    if let Some(load_driver_matches) = global_matches.subcommand_matches("load-driver") {
-        return load_driver(
-            &run_cargo_options.release(load_driver_matches.is_present(RELEASE)),
-            &fuchsia_config,
-            &target_options,
-        );
-    }
-
-    if let Some(doc_matches) = global_matches.subcommand_matches(DOC) {
-        let manifest_path = convert_manifest_path(&doc_matches.value_of(MANIFEST_PATH));
-        return build_doc(
-            &run_cargo_options
-                .release(doc_matches.is_present(RELEASE))
-                .manifest_path(manifest_path),
-            &target_options,
-            doc_matches.is_present(DOC_NO_DEPS),
-            doc_matches.is_present(DOC_OPEN),
-        );
-    }
-
-    if global_matches.subcommand_matches("list-devices").is_some() {
-        return netls(verbose, &target_options);
-    }
-
-    if let Some(start_matches) = global_matches.subcommand_matches(START) {
-        let fx_run_params =
-            start_matches.values_of(FX_RUN_PARAMS).map(|x| x.collect()).unwrap_or_else(|| vec![]);
-
-        return start_emulator(
-            &StartEmulatorOptions {
-                verbose: verbose,
-                with_graphics: start_matches.is_present(GRAPHICS),
-                with_kvm: start_matches.is_present(KVM),
-                with_networking: !start_matches.is_present(NO_NET),
-                disable_virtcon: start_matches.is_present(DISABLE_VIRTCON),
-            },
-            &fx_run_params,
-        );
-    }
-
-    if global_matches.subcommand_matches("stop").is_some() {
-        return stop_emulator();
-    }
-
-    if global_matches.subcommand_matches("enable-networking").is_some() {
-        return enable_networking();
-    }
-
-    if let Some(restart_matches) = global_matches.subcommand_matches(RESTART) {
-        stop_emulator()?;
-
-        let fx_run_params =
-            restart_matches.values_of(FX_RUN_PARAMS).map(|x| x.collect()).unwrap_or_else(|| vec![]);
-
-        return start_emulator(
-            &StartEmulatorOptions {
-                verbose: verbose,
-                with_graphics: restart_matches.is_present(GRAPHICS),
-                with_kvm: restart_matches.is_present(KVM),
-                with_networking: !restart_matches.is_present(NO_NET),
-                disable_virtcon: restart_matches.is_present(DISABLE_VIRTCON),
-            },
-            &fx_run_params,
-        );
-    }
-
-    if global_matches.subcommand_matches("ssh").is_some() {
-        return ssh(verbose, &fuchsia_config, &target_options, "");
-    }
-
-    if let Some(cargo_matches) = global_matches.subcommand_matches("cargo") {
-        let subcommand =
-            cargo_matches.value_of(SUBCOMMAND).expect("The cargo command requires a subcommand");
-        let cargo_params =
-            cargo_matches.values_of("cargo_params").map(|x| x.collect()).unwrap_or_else(|| vec![]);
-        return run_cargo(
-            &RunCargoOptions {
-                verbose,
-                release: false,
-                nocapture: false,
-                run_mode: RunMode::Normal,
-                story_name: None,
-                mod_name: None,
-                disable_cross: disable_cross,
-                manifest_path: None,
-                cmx_path: None,
-                app_name: None,
-            },
-            subcommand,
-            &cargo_params,
-            &target_options,
-            None,
-            None,
-        );
-    }
-
-    if let Some(run_on_target_matches) = global_matches.subcommand_matches(RUN_ON_TARGET) {
-        let run_cargo_options = run_cargo_options
-            .cmx_path(run_on_target_matches.value_of(CMX_PATH).map(|s| PathBuf::from(s)));
-
-        let run_params = run_on_target_matches
-            .values_of("run_on_target_params")
-            .map(|x| x.collect())
-            .unwrap_or_else(|| vec![]);
-        let test_args = run_on_target_matches.value_of("test_args");
-        let (program, args) =
-            run_params.split_first().expect("run on target expects at least one parameter");
-        let run_mode = run_switches_to_mode(
-            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,
-            verbose,
-            run_on_target_matches.is_present(NOCAPTURE),
-            &fuchsia_config,
-            &target_options,
-            run_mode,
-            &run_cargo_options.cmx_path,
-            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),
-            run_on_target_matches.value_of(APP_NAME).unwrap_or(DEFAULT_APP_NAME),
-            args,
-            test_args,
-        );
-    }
-
-    if let Some(pkg_matches) = global_matches.subcommand_matches("pkg-config") {
-        let pkg_params =
-            pkg_matches.values_of("pkgconfig_param").map(|x| x.collect()).unwrap_or_else(|| vec![]);
-        let exit_code = run_pkg_config(verbose, &pkg_params, &target_options)?;
-        if exit_code != 0 {
-            ::std::process::exit(exit_code);
-        }
-        return Ok(());
-    }
-
-    if let Some(configure_matches) = global_matches.subcommand_matches("configure") {
-        let configure_params = configure_matches
-            .values_of("configure_param")
-            .map(|x| x.collect())
-            .unwrap_or_else(|| vec![]);
-        run_configure(
-            verbose,
-            !configure_matches.is_present("no-host"),
-            &configure_params,
-            &target_options,
-        )?;
-        return Ok(());
-    }
-
-    if let Some(_write_config_matches) = global_matches.subcommand_matches(WRITE_CONFIG) {
-        return write_config(&run_cargo_options, &target_options);
-    }
-
-    if let Some(build_rustc_matches) = global_matches.subcommand_matches(BUILD_RUSTC) {
-        let rust_root = PathBuf::from(
-            build_rustc_matches
-                .value_of(RUST_ROOT)
-                .expect("rust_root is a required parameter of build-rustc"),
-        );
-        return build_rustc(&rust_root, &target_options);
-    }
-
-    if let Some(make_package_matches) = global_matches.subcommand_matches(MAKE_PACKAGE) {
-        let binary_path = PathBuf::from(
-            make_package_matches
-                .value_of(BINARY_PATH)
-                .expect(&format!("{} is a required parameter of {}", BINARY_PATH, MAKE_PACKAGE)),
-        );
-        let cmx_path = PathBuf::from(
-            make_package_matches
-                .value_of(CMX_PATH)
-                .expect(&format!("{} is a required parameter of {}", CMX_PATH, MAKE_PACKAGE)),
-        );
-        println!(
-            "make package {}",
-            make_package(verbose, &target_options, &binary_path, &cmx_path, "app")?
-        );
-        return Ok(());
-    }
-
-    if let Some(fmt_matches) = global_matches.subcommand_matches(FORMAT) {
-        let manifest_path = convert_manifest_path(&fmt_matches.value_of(MANIFEST_PATH));
-        format_project(manifest_path)?;
-        return Ok(());
-    }
-
-    Ok(())
-}
diff --git a/src/sdk.rs b/src/sdk.rs
index 823ac63..b54ef32 100644
--- a/src/sdk.rs
+++ b/src/sdk.rs
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use crate::get_target_triple;
 use crate::utils::is_mac;
 use crate::X64;
 use failure::{bail, Error, ResultExt};
@@ -98,12 +97,6 @@
     Ok(fuchsia_dir.join(&config.fuchsia_build_dir))
 }
 
-pub fn cargo_out_dir(options: &TargetOptions<'_, '_>) -> Result<PathBuf, Error> {
-    let fuchsia_dir = fuchsia_dir()?;
-    let target_triple = get_target_triple(options);
-    Ok(fuchsia_dir.join("garnet").join("target").join(target_triple).join("debug"))
-}
-
 pub fn host_out_dir(config: &FuchsiaConfig) -> Result<PathBuf, Error> {
     Ok(target_out_dir(config)?.join("host_x64"))
 }