Initial commit
Change-Id: I8a2bd53b6ff90008ea5c7915c56ed4deb5d0d86f
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..324c57f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target/
+**/*.rs.bk
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..f4de997
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,212 @@
+[root]
+name = "fargo"
+version = "0.1.0"
+dependencies = [
+ "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uname 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "atty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bitflags"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clap"
+version = "2.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dtoa"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "itoa"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num-traits"
+version = "0.1.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "quote"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive_internals"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "strsim"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "syn"
+version = "0.11.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "synom"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "term_size"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "uname"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "vec_map"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-build"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
+"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
+"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
+"checksum clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f"
+"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
+"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
+"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc"
+"checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6"
+"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
+"checksum serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c6b751a2e8d5df57a5ff71b5b4fc8aaee9ee28ff1341d640dd130bb5f4f7a"
+"checksum serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6ca58905ebd3c3b285a8a6d4f3ac92b92c0d7951d5649b1bdd212549c06639"
+"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
+"checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
+"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
+"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
+"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
+"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
+"checksum uname 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8"
+"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
+"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
+"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
+"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
+"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..ff6b025
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "fargo"
+version = "0.1.0"
+authors = ["Rob Tsuk <robtsuk@google.com>"]
+
+[dependencies]
+clap = "2"
+serde = "1.0.9"
+serde_derive = "1.0.9"
+serde_json = "1.0.2"
+uname = "0.1.1"
\ No newline at end of file
diff --git a/README.md b/README.md
index 8b90b74..5e204f1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,36 @@
-Fuchsia Open Source Template Repository
-=======================================
+# fargo
-This repository is a template that we will use when creating new open source
-repositories for Fuchsia.
+Fargo is a prototype Fuchsia-specific wrapper around Cargo.
+
+ USAGE:
+ fargo [FLAGS] [SUBCOMMAND]
+
+ FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+ -v Print verbose output while performing commands
+
+ SUBCOMMANDS:
+ build Build binary targeting Fuchsia device or emulator
+ build-tests Build for Fuchsia device or emulator
+ help Prints this message or the help of the given subcommand(s)
+ restart Stop all Fuchsia emulators and start a new one
+ run Run binary on Fuchsia device or emulator
+ ssh Open a shell on Fuchsia device or emulator
+ start Start a Fuchsia emulator
+ stop Stop all Fuchsia emulators
+ test Run unit tests on Fuchsia device or emulator
+
+The `fargo-test` directory contains something one can use to test-drive.
+
+__At the moment fargo requires the FUCHSIA\_ROOT environmental variable be set to the path to a Fuchsia build.__ The goal is to transition
+fargo to using something like an SDK instead.
+
+Currently fargo does not support building artifacts that need additional libraries.
+
+## To Do
+
+* ~~Clean up build/build-test~~
+* ~~Add support for release builds~~
+* Add support for depending on the FIDL generated crates.
+* Add support for crates like cairo-rs that need native libraries.
diff --git a/fargo-test/Cargo.lock b/fargo-test/Cargo.lock
new file mode 100644
index 0000000..8089307
--- /dev/null
+++ b/fargo-test/Cargo.lock
@@ -0,0 +1,69 @@
+[root]
+name = "fargo-test"
+version = "0.1.0"
+dependencies = [
+ "magenta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mxruntime 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bitflags"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "conv"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "custom_derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "magenta"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "magenta-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "magenta-sys"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mxruntime"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "magenta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "magenta-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mxruntime-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mxruntime-sys"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "magenta-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[metadata]
+"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
+"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
+"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
+"checksum magenta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92159d95603bd96e44850aa5b458656a372b3324940f3523a20d08f0f9cd8760"
+"checksum magenta-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07fd18dd6819f5a24387638769d95fe6e9145eb15c1756d721620604306b7b72"
+"checksum mxruntime 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d267fa561985cefb55172834a020f0e77339dbda7287482fd4b58936e792089a"
+"checksum mxruntime-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3f2afc13950ce3a42515cfc3bdc949f552b0e71109c52481d250ec0e0d9eb8"
diff --git a/fargo-test/Cargo.toml b/fargo-test/Cargo.toml
new file mode 100644
index 0000000..5730de4
--- /dev/null
+++ b/fargo-test/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "fargo-test"
+version = "0.1.0"
+authors = ["Rob Tsuk <robtsuk@google.com>"]
+
+[dependencies]
+magenta = "0.1.0"
+mxruntime = "0.1.0"
+
+[[test]]
+name = "bork"
+path = "test/bork_bork.rs"
\ No newline at end of file
diff --git a/fargo-test/src/main.rs b/fargo-test/src/main.rs
new file mode 100644
index 0000000..7cdef14
--- /dev/null
+++ b/fargo-test/src/main.rs
@@ -0,0 +1,30 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern crate magenta;
+
+fn main() {
+ println!("Hello, world!");
+ println!("Hello, world!");
+ println!("Hello, world!");
+ println!("Hello, world!");
+ println!("Hello, world!");
+ println!("Hello, world!");
+ println!("Hello, world!");
+}
+
+#[cfg(test)]
+mod tests {
+
+ use magenta::{Channel, ChannelOpts};
+
+ #[test]
+ fn noop_test() {}
+
+ #[test]
+ fn channel_call_test() {
+ // Create a pair of channels
+ let (p1, p2) = Channel::create(ChannelOpts::Normal).unwrap();
+ }
+}
diff --git a/fargo-test/test/bork_bork.rs b/fargo-test/test/bork_bork.rs
new file mode 100644
index 0000000..985c594
--- /dev/null
+++ b/fargo-test/test/bork_bork.rs
@@ -0,0 +1,9 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[test]
+fn test_dogs() {
+ let dogs = "good";
+ assert_eq!(dogs, "good");
+}
diff --git a/src/cargo_interop.rs b/src/cargo_interop.rs
new file mode 100644
index 0000000..88f217a
--- /dev/null
+++ b/src/cargo_interop.rs
@@ -0,0 +1,52 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Structs for deserializing the output of cargo commands
+// Derived from inspection of the output of cargo commands
+// run with the "--message-format json" parameter.
+
+#[derive(Deserialize,Debug)]
+pub struct Profile {
+ pub test: bool,
+}
+
+#[derive(Deserialize,Debug)]
+pub struct Target {
+ pub kind: Vec<String>,
+}
+
+#[derive(Deserialize,Debug)]
+pub struct Artifact {
+ #[serde(default)]
+ pub filenames: Vec<String>,
+ pub profile: Profile,
+ pub target: Target,
+}
+
+#[derive(Deserialize,Debug)]
+pub struct Code {
+ code: Option<String>,
+ explanation: String,
+}
+
+#[derive(Deserialize,Debug)]
+pub struct Span {
+ file_name: String,
+ label: Option<String>,
+ line_start: i32,
+ line_end: i32,
+}
+
+#[derive(Deserialize,Debug)]
+pub struct Message {
+ level: String,
+ message: String,
+ code: Option<Code>,
+ spans: Vec<Span>,
+}
+
+#[derive(Deserialize,Debug)]
+pub struct MessageWrapper {
+ message: Option<Message>,
+}
diff --git a/src/device.rs b/src/device.rs
new file mode 100644
index 0000000..a217de6
--- /dev/null
+++ b/src/device.rs
@@ -0,0 +1,132 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env;
+use std::path::PathBuf;
+use std::process::{Command, Stdio};
+use std::str;
+use sdk::fuchsia_root;
+use utils::is_mac;
+
+pub fn netaddr() -> Result<String, String> {
+ let fuchsia_root = fuchsia_root();
+ let netaddr_binary = fuchsia_root.join("out/build-magenta/tools/netaddr");
+ let netaddr_result = Command::new(netaddr_binary)
+ .arg("--fuchsia")
+ .output()
+ .expect("Couldn't run netaddr.");
+ if netaddr_result.status.success() {
+ Ok(str::from_utf8(&netaddr_result.stdout).unwrap().trim().to_string())
+ } else {
+ Err(format!("netaddr failed with: {}",
+ String::from_utf8_lossy(&netaddr_result.stderr)))
+ }
+}
+
+pub fn scp_to_device(netaddr: &String,
+ source_path: &PathBuf,
+ destination_path: &String)
+ -> Result<(), String> {
+ let destination_with_address = format!("[{}]:{}", netaddr, destination_path);
+ let fuchsia_root = fuchsia_root();
+ let ssh_config = fuchsia_root.join("out/debug-x86-64/ssh-keys/ssh_config");
+ let ssh_result = Command::new("scp")
+ .arg("-q")
+ .arg("-F")
+ .arg(ssh_config)
+ .arg(source_path)
+ .arg(destination_with_address)
+ .status()
+ .expect("Unable to run ssh.");
+
+ if ssh_result.success() {
+ Ok(())
+ } else {
+ Err(format!("scp failed with error {:?}", ssh_result))
+ }
+}
+
+pub fn ssh(command: &str) {
+ let netaddr_result = netaddr();
+ let fuchsia_root = fuchsia_root();
+ let ssh_config = fuchsia_root.join("out/debug-x86-64/ssh-keys/ssh_config");
+ match netaddr_result {
+ Ok(netaddr) => {
+ let ssh_result = Command::new("ssh")
+ .arg("-q")
+ .arg("-F")
+ .arg(ssh_config)
+ .arg(netaddr)
+ .arg(command)
+ .status()
+ .expect("Unable to run ssh.");
+ if !ssh_result.success() {
+ println!("ssh failed: {}", ssh_result);
+ }
+
+ }
+
+ Err(netaddr_err) => {
+ println!("{}", netaddr_err);
+ }
+ }
+}
+
+pub fn start_emulator(with_graphics: bool) {
+ let fuchsia_root = fuchsia_root();
+ let run_magenta_script = fuchsia_root.join("scripts/run-magenta-x86-64");
+ let user_bootfs = fuchsia_root.join("out/debug-x86-64/user.bootfs");
+ let user_bootfs_str = user_bootfs.to_str().unwrap();
+ let mut args = vec!["-N", "-x", user_bootfs_str];
+ if with_graphics {
+ args.push("-g");
+ }
+ let child = Command::new(run_magenta_script)
+ .args(&args)
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .spawn()
+ .expect("Unable to run magenta.");
+ println!("emulator started with process ID {}", child.id());
+
+ if is_mac() {
+
+ let user = env::var("USER").unwrap();
+
+ println!("Calling sudo ifconfig to bring up tap0 interface; password may be required.");
+
+ let chown_status = Command::new("sudo")
+ .arg("chown")
+ .arg(user)
+ .arg("/dev/tap0")
+ .status()
+ .expect("Couldn't run chown.");
+
+ if chown_status.success() {
+ let ifconfig_status = Command::new("sudo")
+ .arg("ifconfig")
+ .arg("tap0")
+ .arg("inet6")
+ .arg("fc00::/7")
+ .arg("up")
+ .status()
+ .expect("Couldn't run ifconfig.");
+
+ if ifconfig_status.success() {
+ println!("tap0 enabled");
+ // If sudo needed a password, sometimes the terminal gets into a funky state
+ Command::new("stty").arg("sane").status().expect("Couldn run stty");
+ } else {
+ println!("ifconfig failed");
+ }
+ }
+ }
+}
+
+pub fn stop_emulator() {
+ let _ = Command::new("killall")
+ .arg("qemu-system-x86_64")
+ .status()
+ .expect("Could not run killall.");
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..4e3022f
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,299 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern crate clap;
+extern crate serde;
+#[macro_use]
+extern crate serde_derive;
+extern crate serde_json;
+extern crate uname;
+
+mod cargo_interop;
+mod device;
+mod sdk;
+mod utils;
+
+use cargo_interop::Artifact;
+use clap::{App, Arg, SubCommand};
+use device::{netaddr, scp_to_device, ssh, start_emulator, stop_emulator};
+use sdk::{rust_c_path, rust_linker_path};
+use std::path::PathBuf;
+use std::process::Command;
+use std::str;
+use utils::strip_binary;
+
+fn build_tests(verbose: bool, release: bool, test_target: &String) -> bool {
+ if verbose {
+ println!("# build tests phase 1");
+ }
+ let mut args = vec!["test", "--target", "x86_64-unknown-fuchsia", "--no-run"];
+ if release {
+ args.push("--release");
+ }
+ if test_target.len() > 0 {
+ args.push("--test");
+ args.push(test_target.as_str());
+ }
+ let build_command = Command::new("cargo")
+ .env("RUSTC", rust_c_path().to_str().unwrap())
+ .env("CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_LINKER",
+ rust_linker_path().to_str().unwrap())
+ .args(args)
+ .status()
+ .expect("cargo command failed to start");
+
+ build_command.success()
+}
+
+fn run_tests(verbose: bool, release: bool, test_target: &String, params: &Vec<String>) {
+ if !build_tests(verbose, release, test_target) {
+ return;
+ }
+ if verbose {
+ println!("# build tests phase 2");
+ }
+ let mut args = vec!["test",
+ "--target",
+ "x86_64-unknown-fuchsia",
+ "-q",
+ "--no-run",
+ "--message-format",
+ "JSON"];
+ if release {
+ args.push("--release");
+ }
+
+ if test_target.len() > 0 {
+ args.push("--test");
+ args.push(test_target.as_str());
+ }
+
+ let output = Command::new("cargo")
+ .env("RUSTC", rust_c_path().to_str().unwrap())
+ .env("CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_LINKER",
+ rust_linker_path().to_str().unwrap())
+ .args(args)
+ .output()
+ .expect("cargo command failed to start");
+
+ if output.status.success() {
+ let netaddr_result = netaddr();
+ match netaddr_result {
+ Ok(netaddr) => {
+ let artifacts = str::from_utf8(&output.stdout).unwrap().trim().split('\n');
+ for artifact_line in artifacts {
+ if verbose {
+ println!("# {}", artifact_line);
+ }
+ let artifact: Artifact = serde_json::from_str(&artifact_line).unwrap();
+ if verbose {
+ println!("# {:?}", artifact);
+ }
+ if artifact.profile.test {
+ for filename in artifact.filenames {
+ let source_path = PathBuf::from(&filename);
+ let stripped_source_path = strip_binary(&source_path);
+ let destination_path = format!("/tmp/{}",
+ stripped_source_path.file_name()
+ .unwrap()
+ .to_string_lossy());
+ println!("copying {} to {}",
+ source_path.to_string_lossy(),
+ destination_path);
+ let scp_result =
+ scp_to_device(&netaddr, &stripped_source_path, &destination_path);
+ match scp_result {
+ Ok(_) => {
+ let command_string = if params.len() > 0 {
+ let param_string = params.join(" ");
+ destination_path + " " + ¶m_string
+ } else {
+ destination_path
+ };
+ if verbose {
+ println!("running {}", command_string);
+ }
+ ssh(&command_string);
+ }
+ Err(scp_err) => {
+ println!("scp failed with: {}", scp_err);
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Err(netaddr_err) => {
+ println!("{}", netaddr_err);
+ }
+ }
+ } else {
+ println!("cargo test command failed");
+ }
+}
+
+fn build_binary(verbose: bool, release: bool) -> bool {
+ if verbose {
+ println!("# build binary phase 1");
+ }
+ let mut args = vec!["build", "--target", "x86_64-unknown-fuchsia"];
+ if release {
+ args.push("--release");
+ }
+ let build_command = Command::new("cargo")
+ .env("RUSTC", rust_c_path().to_str().unwrap())
+ .env("CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_LINKER",
+ rust_linker_path().to_str().unwrap())
+ .args(args)
+ .status()
+ .expect("cargo command failed to start");
+
+ build_command.success()
+}
+
+fn run_binary(verbose: bool, release: bool) {
+ if !build_binary(verbose, release) {
+ return;
+ }
+ let mut args = vec!["build", "--target", "x86_64-unknown-fuchsia"];
+ if release {
+ args.push("--release");
+ }
+ let output = Command::new("cargo")
+ .env("RUSTC", rust_c_path().to_str().unwrap())
+ .env("CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_LINKER",
+ rust_linker_path().to_str().unwrap())
+ .args(args)
+ .arg("--message-format")
+ .arg("JSON")
+ .output()
+ .expect("cargo command failed to start");
+ if output.status.success() {
+ let netaddr_result = netaddr();
+ match netaddr_result {
+ Ok(netaddr) => {
+ let artifacts = str::from_utf8(&output.stdout).unwrap().trim().split('\n');
+ for artifact_line in artifacts {
+ if verbose {
+ println!("# {}", artifact_line);
+ }
+ let artifact: Artifact = serde_json::from_str(&artifact_line).unwrap();
+ if verbose {
+ println!("# {:?}", artifact);
+ }
+ if artifact.target.kind.contains(&"bin".to_string()) {
+ for filename in artifact.filenames {
+ let source_path = PathBuf::from(&filename);
+ let stripped_source_path = strip_binary(&source_path);
+ let destination_path = format!("/tmp/{}",
+ stripped_source_path.file_name()
+ .unwrap()
+ .to_string_lossy());
+ println!("copying {} to {}",
+ stripped_source_path.to_string_lossy(),
+ destination_path);
+ let scp_result =
+ scp_to_device(&netaddr, &stripped_source_path, &destination_path);
+ match scp_result {
+ Ok(_) => {
+ println!("running {}", destination_path);
+ ssh(&destination_path);
+ }
+ Err(scp_err) => {
+ println!("scp failed with: {}", scp_err);
+
+ }
+ }
+ }
+ }
+ }
+ }
+ Err(netaddr_err) => {
+ println!("{}", netaddr_err);
+ }
+ }
+ }
+
+}
+
+fn main() {
+ let matches = App::new("fargo")
+ .version("v0.1.0")
+ .arg(Arg::with_name("verbose")
+ .short("v")
+ .help("Print verbose output while performing commands"))
+ .subcommand(SubCommand::with_name("build-tests")
+ .about("Build for Fuchsia device or emulator")
+ .arg(Arg::with_name("test")
+ .long("test")
+ .value_name("test")
+ .help("Test only the specified test target"))
+ .arg(Arg::with_name("release")
+ .long("release")
+ .help("Build release")))
+ .subcommand(SubCommand::with_name("test")
+ .about("Run unit tests on Fuchsia device or emulator")
+ .arg(Arg::with_name("release")
+ .long("release")
+ .help("Build release"))
+ .arg(Arg::with_name("test")
+ .long("test")
+ .value_name("test")
+ .help("Test only the specified test target"))
+ .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("Build release")))
+ .subcommand(SubCommand::with_name("run")
+ .about("Run binary on Fuchsia device or emulator")
+ .arg(Arg::with_name("release")
+ .long("release")
+ .help("Build release")))
+ .subcommand(SubCommand::with_name("start")
+ .about("Start a Fuchsia emulator")
+ .arg(Arg::with_name("graphics")
+ .short("g")
+ .help("Start a simulator with graphics enabled")))
+ .subcommand(SubCommand::with_name("stop").about("Stop all Fuchsia emulators"))
+ .subcommand(SubCommand::with_name("restart")
+ .about("Stop all Fuchsia emulators and start a new one")
+ .arg(Arg::with_name("graphics")
+ .short("g")
+ .help("Start a simulator with graphics enabled")))
+ .subcommand(SubCommand::with_name("ssh")
+ .about("Open a shell on Fuchsia device or emulator"))
+ .get_matches();
+
+ let verbose = matches.is_present("verbose");
+ if let Some(test_matches) = matches.subcommand_matches("test") {
+ let test_params = test_matches.values_of_lossy("test_params").unwrap_or(vec![]);
+ let test_target = test_matches.value_of("test").unwrap_or("").to_string();
+ run_tests(verbose,
+ test_matches.is_present("release"),
+ &test_target,
+ &test_params);
+ } else if let Some(build_matches) = matches.subcommand_matches("build") {
+ build_binary(verbose, build_matches.is_present("release"));
+ } else if let Some(run_matches) = matches.subcommand_matches("run") {
+ run_binary(verbose, run_matches.is_present("release"));
+ } else if let Some(build_test_matches) = matches.subcommand_matches("build-tests") {
+ let test_target = build_test_matches.value_of("test").unwrap_or("").to_string();
+ build_tests(verbose,
+ build_test_matches.is_present("release"),
+ &test_target);
+ } else if let Some(start_matches) = matches.subcommand_matches("start") {
+ start_emulator(start_matches.is_present("graphics"));
+ } else if let Some(_) = matches.subcommand_matches("stop") {
+ stop_emulator();
+ } else if let Some(restart_matches) = matches.subcommand_matches("restart") {
+ stop_emulator();
+ start_emulator(restart_matches.is_present("graphics"));
+ } else if let Some(_) = matches.subcommand_matches("ssh") {
+ ssh("");
+ }
+}
diff --git a/src/sdk.rs b/src/sdk.rs
new file mode 100644
index 0000000..cc8d430
--- /dev/null
+++ b/src/sdk.rs
@@ -0,0 +1,44 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::path::PathBuf;
+use std::env;
+use utils::is_mac;
+
+pub fn fuchsia_root() -> PathBuf {
+ let fuchsia_root_value = match env::var("FUCHSIA_ROOT") {
+ Ok(val) => val,
+ Err(_) => {
+ panic!("You must set the environmental variable FUCHSIA_ROOT to point to a Fuchsia \
+ tree with a debug-x86-64 build including the rust module")
+ }
+ };
+ PathBuf::from(fuchsia_root_value)
+}
+
+fn rust_buildtools_path() -> PathBuf {
+ let platform_name = if is_mac() {
+ "rust-x86_64-apple-darwin"
+ } else {
+ "rust-x86_64-unknown-linux-gnu"
+ };
+ fuchsia_root().join("buildtools/rust").join(platform_name)
+}
+
+pub fn rust_c_path() -> PathBuf {
+ rust_buildtools_path().join("bin/rustc")
+}
+
+pub fn rust_linker_path() -> PathBuf {
+ fuchsia_root().join("out/debug-x86-64/host_x64/x86_64-unknown-fuchsia-cc")
+}
+
+pub fn strip_tool_path() -> PathBuf {
+ let platform_name = if is_mac() {
+ "clang+llvm-x86_64-darwin"
+ } else {
+ "clang+llvm-x86_64-linux"
+ };
+ fuchsia_root().join("buildtools/toolchain").join(platform_name).join("bin/strip")
+}
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..b303489
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,38 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::path::PathBuf;
+use std::process::Command;
+use std::str;
+use std::time::Duration;
+use uname::uname;
+use sdk::strip_tool_path;
+
+#[allow(dead_code)]
+pub fn duration_as_milliseconds(duration: &Duration) -> u64 {
+ let subsec_ms: u64 = duration.subsec_nanos() as u64 / 1000000;
+ let dur_ms = duration.as_secs() * 1000 + subsec_ms;
+ dur_ms
+}
+
+pub fn is_mac() -> bool {
+ uname().unwrap().sysname == "Darwin"
+}
+
+pub fn strip_binary(binary: &PathBuf) -> PathBuf {
+ let file_name = binary.file_name().unwrap();
+ let new_file_name = file_name.to_string_lossy().into_owned() + "_stripped";
+ let target_path = binary.parent().unwrap().join(new_file_name);
+ let strip_result = Command::new(strip_tool_path())
+ .arg(binary)
+ .arg("-o")
+ .arg(&target_path)
+ .status()
+ .expect("strip command failed to start");
+
+ if !strip_result.success() {
+ panic!("strip failed with error {:?}", strip_result)
+ }
+ target_path
+}