diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..c980350f8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 000000000..b4b76e523
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,1064 @@
+[[package]]
+name = "advapi32-sys"
+version = "0.2.0"
+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 = "aho-corasick"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
+ "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bitflags"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cargo"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crates-io 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
+ "libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cargo-raze"
+version = "0.0.14"
+dependencies = [
+ "cargo 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hamcrest 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tera 0.11.0-beta.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "chrono"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crates-io"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "curl 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "curl"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "curl-sys"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+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 = "docopt"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.6.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 = "either"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "env_logger"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "error-chain"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "filetime"
+version = "0.1.10"
+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 = "flate2"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "fs2"
+version = "0.4.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 = "gcc"
+version = "0.3.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "git2"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "git2-curl"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "curl 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "glob"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "hamcrest"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "humansize"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "idna"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "itertools"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.1.0 (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 = "jobserver"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.15 (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 = "lazy_static"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "lazy_static"
+version = "1.0.0"
+source = "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 = "libgit2-sys"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libssh2-sys"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "log"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "matches"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "memchr"
+version = "0.1.11"
+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 = "memchr"
+version = "1.0.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 = "miniz-sys"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "miow"
+version = "0.2.1"
+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)",
+ "net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "net2"
+version = "0.2.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
+ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.1.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num_cpus"
+version = "1.6.2"
+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 = "openssl"
+version = "0.9.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "pest"
+version = "1.0.0-rc.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "pest_derive"
+version = "1.0.0-rc.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "pest 1.0.0-rc.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "psapi-sys"
+version = "0.1.0"
+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 = "quote"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rand"
+version = "0.3.15"
+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 = "redox_syscall"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "regex"
+version = "0.1.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "regex-syntax"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rustc-serialize"
+version = "0.3.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "scoped-tls"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "semver"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.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)",
+ "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_ignored"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.11 (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.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "shell-escape"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "slug"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "socket2"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
+ "ws2_32-sys 0.2.1 (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.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.15 (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 = "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 = "tar"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tempdir"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tera"
+version = "0.11.0-beta.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humansize 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest 1.0.0-rc.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest_derive 1.0.0-rc.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "term"
+version = "0.4.6"
+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)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "thread-id"
+version = "2.0.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)",
+]
+
+[[package]]
+name = "thread_local"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "thread_local"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "time"
+version = "0.1.38"
+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)",
+ "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "toml"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.5"
+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 = "unidecode"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unreachable"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "url"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "utf8-ranges"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "utf8-ranges"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "void"
+version = "1.0.2"
+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"
+
+[[package]]
+name = "ws2_32-sys"
+version = "0.2.1"
+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)",
+]
+
+[metadata]
+"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
+"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
+"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
+"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
+"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c"
+"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
+"checksum cargo 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "594a86eae348b57fdebbe894fb60c070b46ff673386901779d85f3b5418fd8c0"
+"checksum cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c47d456a36ebf0536a6705c83c1cbbcb9255fbc1d905a6ded104f479268a29"
+"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9"
+"checksum cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ebbb35d3dc9cd09497168f33de1acb79b265d350ab0ac34133b98f8509af1f"
+"checksum crates-io 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "341e08bc12f50de704649e7472d39bb55dea3ef1ff65dc4301257ea41a048a5f"
+"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
+"checksum curl 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6689276ab61f97c660669a5ecc117c36875dfc1ba301c986b16c653415bdf9d7"
+"checksum curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d5481162dc4f424d088581db2f979fa7d4c238fe9794595de61d8d7522e277de"
+"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
+"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
+"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
+"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
+"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
+"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
+"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
+"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
+"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
+"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
+"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a"
+"checksum git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa01936ac96555c083c0e8553f672616274408d9d3fc5b8696603fbf63ff43ee"
+"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e"
+"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
+"checksum hamcrest 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d9e7f519847c8937313ee2f5c9caf3cbe724cca6169ad59258b9fb86813b53"
+"checksum humansize 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "92d211e6e70b05749dce515b47684f29a3c8c38bbbb21c50b30aff9eca1b0bd3"
+"checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37"
+"checksum itertools 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e58359414720377f59889192f1ec0e726049ce5735bc21fdb0c4c8ae638305bb"
+"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
+"checksum jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "443ae8bc0af6c106e6e8b77e04684faecc1a5ce94e058f4c2b0a037b0ea1b133"
+"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
+"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
+"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc"
+"checksum libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "df18a822100352d9863b302faf6f8f25c0e77f0e60feb40e5dbe1238b7f13b1d"
+"checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75"
+"checksum libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd64ef8ee652185674455c1d450b83cbc8ad895625d543b5324d923f82e4d8"
+"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
+"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
+"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
+"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
+"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
+"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
+"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525"
+"checksum num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "8fd0f8dbb4c0960998958a796281d88c16fbe68d87b1baa6f31e2979e81fd0bd"
+"checksum num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "503e668405c5492d67cf662a81e05be40efe2e6bcf10f7794a07bd9865e704e6"
+"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"
+"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01"
+"checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790"
+"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0"
+"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584"
+"checksum openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "11ba043cb65fc9af71a431b8a36ffe8686cd4751cdf70a473ec1d01066ac7e41"
+"checksum openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98df0270d404ccd3c050a41d579c52d1db15375168bb3471e04ec0f5f378daf"
+"checksum openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "236c718c2e2c2b58a546d86ffea5194400bb15dbe01ca85325ffd357b03cf66c"
+"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
+"checksum pest 1.0.0-rc.1 (registry+https://github.com/rust-lang/crates.io-index)" = "db7f3627b99404d593124b61af5f7b73d1d4b1cd8c606380242baca93a6c51f9"
+"checksum pest_derive 1.0.0-rc.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285cc1fdf6173ba839d355fa61ff7a41bf69d0ffa45ca4ee9aa2125ce85c2b13"
+"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
+"checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478"
+"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
+"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
+"checksum redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9309631a35303bffb47e397198e3668cb544fe8834cd3da2a744441e70e524"
+"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
+"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
+"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
+"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
+"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
+"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
+"checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9"
+"checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd"
+"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
+"checksum serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c10e798e4405d7dcec3658989e35ee6706f730a9ed7c1184d5ebd84317e82f46"
+"checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
+"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
+"checksum slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f5ff4b43cb07b86c5f9236c92714a22cdf9e5a27a7d85e398e2c9403328cb8"
+"checksum socket2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12cdbddbaa27bf94cc194b8e37f5811db6fe83cea96cf99cf1f8e92b65a41371"
+"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
+"checksum syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)" = "58fd09df59565db3399efbba34ba8a2fec1307511ebd245d0061ff9d42691673"
+"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 tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b"
+"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
+"checksum tera 0.11.0-beta.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dc20257da631478e47a94e6e69e200fc28f39ed0426548759d28c766ca9d3994"
+"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
+"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
+"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
+"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
+"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
+"checksum toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e5e16033aacf7eead46cbcb62d06cf9d1c2aa1b12faa4039072f7ae5921103b"
+"checksum unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a"
+"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
+"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
+"checksum unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb95ee07cd579ed18131f2d9e7a17c25a4b76022935c7f2460d2bfae89fd2"
+"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
+"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
+"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
+"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
+"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
+"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+"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"
+"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 000000000..108d5713d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "cargo-raze"
+version = "0.0.16"
+authors = ["Alex McArther "]
+readme = "README.md"
+keywords = ["subcommand"]
+license = "Apache-2.0"
+description = """
+A Cargo subcommand to generate Bazel BUILD files
+"""
+
+[dependencies]
+rustc-serialize = "0.3"
+cargo = "0.20.0"
+itertools = "0.6.0"
+tera = "0.11.0-beta.4"
+serde_derive = "1.0.11"
+serde = "1.0.11"
+toml = "0.4.4"
+
+[dev-dependencies]
+tempdir = "0.3.5"
+lazy_static = "0.2.8"
+hamcrest = "0.1.3"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..261eeb9e9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..6a21321ae
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# cargo-raze: Bazel BUILD generation for Rust Crates
+
+A support Cargo plugin for distilling a workspace-level Cargo.toml into BUILD
+targets that code using [rules_rust](https://github.com/bazelbuild/rules_rust)
+can depend on directly.
+
+### Disclaimer
+
+This is not an official Google product (experimental or otherwise), it is just code that happens to be owned by Google.
+
diff --git a/src/bazel.rs b/src/bazel.rs
new file mode 100644
index 000000000..b7f874d1b
--- /dev/null
+++ b/src/bazel.rs
@@ -0,0 +1,271 @@
+use cargo::util::CargoResult;
+use cargo::CargoError;
+use context::CrateContext;
+use context::WorkspaceContext;
+use planning::PlannedBuild;
+use rendering::BuildRenderer;
+use rendering::FileOutputs;
+use rendering::RenderDetails;
+use tera::Context;
+use tera::Tera;
+use tera;
+
+pub struct BazelRenderer {
+ internal_renderer: Tera,
+}
+
+impl BazelRenderer {
+ pub fn new() -> BazelRenderer {
+ // Configure tera with a bogus template dir: We don't want any runtime template support
+ let mut renderer = Tera::new("src/not/a/dir/*").unwrap();
+ renderer.add_raw_templates(vec![
+ ("templates/partials/build_script.template", include_str!("templates/partials/build_script.template")),
+ ("templates/partials/remote_build_script.template", include_str!("templates/partials/remote_build_script.template")),
+ ("templates/partials/rust_binary.template", include_str!("templates/partials/rust_binary.template")),
+ ("templates/partials/remote_rust_binary.template", include_str!("templates/partials/remote_rust_binary.template")),
+ ("templates/partials/rust_library.template", include_str!("templates/partials/rust_library.template")),
+ ("templates/partials/remote_rust_library.template", include_str!("templates/partials/remote_rust_library.template")),
+ ("templates/workspace.BUILD.template", include_str!("templates/workspace.BUILD.template")),
+ ("templates/remote_workspace.BUILD.template", include_str!("templates/remote_workspace.BUILD.template")),
+ ("templates/crate.BUILD.template", include_str!("templates/crate.BUILD.template")),
+ ("templates/remote_crates.bzl.template", include_str!("templates/remote_crates.bzl.template")),
+ ("templates/remote_crate.BUILD.template", include_str!("templates/remote_crate.BUILD.template"))]).unwrap();
+
+ BazelRenderer {
+ internal_renderer: renderer,
+ }
+ }
+
+ pub fn render_crate(&self, workspace_context: &WorkspaceContext, package: &CrateContext) -> Result {
+ let mut context = Context::new();
+ context.add("workspace", &workspace_context);
+ context.add("crate", &package);
+ self.internal_renderer.render("templates/crate.BUILD.template", &context)
+ }
+
+ pub fn render_aliases(&self, workspace_context: &WorkspaceContext, all_packages: &Vec) -> Result {
+ let mut context = Context::new();
+ context.add("workspace", &workspace_context);
+ context.add("crates", &all_packages);
+ self.internal_renderer.render("templates/workspace.BUILD.template", &context)
+ }
+
+ pub fn render_remote_crate(&self, workspace_context: &WorkspaceContext, package: &CrateContext) -> Result {
+ let mut context = Context::new();
+ context.add("workspace", &workspace_context);
+ context.add("crate", &package);
+ self.internal_renderer.render("templates/remote_crate.BUILD.template", &context)
+ }
+
+ pub fn render_remote_aliases(&self, workspace_context: &WorkspaceContext, all_packages: &Vec) -> Result {
+ let mut context = Context::new();
+ context.add("workspace", &workspace_context);
+ context.add("crates", &all_packages);
+ self.internal_renderer.render("templates/remote_workspace.BUILD.template", &context)
+ }
+
+ pub fn render_bzl_fetch(&self, workspace_context: &WorkspaceContext, all_packages: &Vec) -> Result {
+ let mut context = Context::new();
+ context.add("workspace", &workspace_context);
+ context.add("crates", &all_packages);
+ self.internal_renderer.render("templates/remote_crates.bzl.template", &context)
+ }
+}
+
+impl BuildRenderer for BazelRenderer {
+ fn render_planned_build(&mut self, render_details: &RenderDetails, planned_build: &PlannedBuild) -> CargoResult> {
+ let &RenderDetails { ref path_prefix, .. } = render_details;
+ let &PlannedBuild { ref workspace_context, ref crate_contexts, .. } = planned_build;
+ let mut file_outputs = Vec::new();
+
+ for package in crate_contexts {
+ let build_file_path = format!("{}/{}BUILD", &path_prefix, &package.path);
+ let rendered_crate_build_file = try!(self.render_crate(&workspace_context, &package).map_err(|e| CargoError::from(e.to_string())));
+ file_outputs.push(FileOutputs { path: build_file_path, contents: rendered_crate_build_file })
+ }
+
+ let build_file_path = format!("{}/vendor/BUILD", &path_prefix);
+ let rendered_alias_build_file = try!(self.render_aliases(&workspace_context, &crate_contexts).map_err(|e| CargoError::from(e.to_string())));
+ file_outputs.push(FileOutputs { path: build_file_path, contents: rendered_alias_build_file });
+ Ok(file_outputs)
+ }
+
+ fn render_remote_planned_build(&mut self, render_details: &RenderDetails, planned_build: &PlannedBuild) -> CargoResult> {
+ let &RenderDetails { ref path_prefix, .. } = render_details;
+ let &PlannedBuild { ref workspace_context, ref crate_contexts, .. } = planned_build;
+ let mut file_outputs = Vec::new();
+
+ for package in crate_contexts {
+ let build_file_path = format!("{}-{}.BUILD", &package.pkg_name, &package.pkg_version);
+ let rendered_crate_build_file = try!(self.render_remote_crate(&workspace_context, &package).map_err(|e| CargoError::from(e.to_string())));
+ file_outputs.push(FileOutputs { path: build_file_path, contents: rendered_crate_build_file })
+ }
+
+ let alias_file_path = format!("{}/BUILD", &path_prefix);
+ let rendered_alias_build_file = try!(self.render_remote_aliases(&workspace_context, &crate_contexts).map_err(|e| CargoError::from(e.to_string())));
+ file_outputs.push(FileOutputs { path: alias_file_path, contents: rendered_alias_build_file });
+
+ let bzl_fetch_file_path = format!("{}/crates.bzl", &path_prefix);
+ let rendered_bzl_fetch_file = try!(self.render_bzl_fetch(&workspace_context, &crate_contexts).map_err(|e| CargoError::from(e.to_string())));
+ file_outputs.push(FileOutputs { path: bzl_fetch_file_path, contents: rendered_bzl_fetch_file });
+
+ Ok(file_outputs)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ pub use super::*;
+ pub use planning::PlannedBuild;
+ pub use rendering::RenderDetails;
+ pub use rendering::FileOutputs;
+ pub use context::*;
+ pub use hamcrest::prelude::*;
+ pub use hamcrest::core::expect;
+
+ fn dummy_render_details() -> RenderDetails {
+ RenderDetails {
+ path_prefix: "./some_render_prefix".to_owned(),
+ }
+ }
+
+ fn dummy_planned_build(crate_contexts: Vec) -> PlannedBuild {
+ PlannedBuild {
+ workspace_context: WorkspaceContext {
+ workspace_path: "//workspace/prefix".to_owned(),
+ platform_triple: "irrelevant".to_owned(),
+ gen_workspace_prefix: "".to_owned()
+ },
+ crate_contexts: crate_contexts,
+ }
+ }
+
+ fn dummy_binary_crate() -> CrateContext {
+ CrateContext {
+ pkg_name: "test-binary".to_owned(),
+ pkg_version: "1.1.1".to_owned(),
+ features: vec!["feature1".to_owned(), "feature2".to_owned()].to_owned(),
+ path: "vendor/test-binary-1.1.1/".to_owned(),
+ dependencies: Vec::new(),
+ build_dependencies: Vec::new(),
+ dev_dependencies: Vec::new(),
+ is_root_dependency: true,
+ metadeps: Vec::new(),
+ platform_triple: "irrelevant".to_owned(),
+ targets: vec![
+ BuildTarget {
+ name: "some_binary".to_owned(),
+ kind: "bin".to_owned(),
+ path: "bin/main.rs".to_owned()
+ }
+ ],
+ build_script_target: None,
+ additional_deps: Vec::new(),
+ additional_flags: Vec::new(),
+ extra_aliased_targets: Vec::new(),
+ }
+ }
+
+ fn dummy_library_crate() -> CrateContext {
+ CrateContext {
+ pkg_name: "test-library".to_owned(),
+ pkg_version: "1.1.1".to_owned(),
+ features: vec!["feature1".to_owned(), "feature2".to_owned()].to_owned(),
+ path: "vendor/test-library-1.1.1/".to_owned(),
+ dependencies: Vec::new(),
+ build_dependencies: Vec::new(),
+ dev_dependencies: Vec::new(),
+ is_root_dependency: true,
+ metadeps: Vec::new(),
+ platform_triple: "irrelevant".to_owned(),
+ targets: vec![
+ BuildTarget {
+ name: "some_library".to_owned(),
+ kind: "lib".to_owned(),
+ path: "path/lib.rs".to_owned()
+ }
+ ],
+ build_script_target: None,
+ additional_deps: Vec::new(),
+ additional_flags: Vec::new(),
+ extra_aliased_targets: Vec::new(),
+ }
+ }
+
+ fn extract_contents_matching_path(file_outputs: &Vec, crate_name: &str) -> String {
+ let mut matching_files_contents = file_outputs
+ .iter()
+ .filter(|output| output.path.contains(crate_name))
+ .map(|output| output.contents.to_owned())
+ .collect::>();
+
+ assert_that!(matching_files_contents.len(), equal_to(1));
+ matching_files_contents.pop().unwrap()
+ }
+
+ fn render_crates_for_test(contexts: Vec) -> Vec {
+ BazelRenderer::new().render_planned_build(
+ &dummy_render_details(),
+ &dummy_planned_build(contexts)) .unwrap()
+ }
+
+ #[test]
+ fn all_plans_contain_root_build_file() {
+ let file_outputs = render_crates_for_test(Vec::new());
+ let file_names = file_outputs.iter().map(|output| output.path.as_ref()).collect::>();
+
+ assert_that!(&file_names, contains(vec!["./some_render_prefix/vendor/BUILD"]).exactly());
+ }
+
+ #[test]
+ fn crates_generate_build_files() {
+ let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
+ let file_names = file_outputs.iter().map(|output| output.path.as_ref()).collect::>();
+
+ assert_that!(&file_names,
+ contains(vec!["./some_render_prefix/vendor/BUILD", "./some_render_prefix/vendor/test-library-1.1.1/BUILD"]).exactly());
+ }
+
+ #[test]
+ fn root_crates_get_build_aliases() {
+ let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
+ let root_build_contents = extract_contents_matching_path(&file_outputs, "vendor/BUILD");
+
+ expect(root_build_contents.contains("alias"),
+ format!("expected root build contents to contain an alias \
+ for test-library crate, but it just contained [{}]", root_build_contents)).unwrap();
+ }
+
+ #[test]
+ fn non_root_crates_dont_get_build_aliases() {
+ let mut non_root_crate = dummy_library_crate();
+ non_root_crate.is_root_dependency = false;
+
+ let file_outputs = render_crates_for_test(vec![non_root_crate]);
+ let root_build_contents = extract_contents_matching_path(&file_outputs, "vendor/BUILD");
+
+ expect(!root_build_contents.contains("alias"),
+ format!("expected root build contents not to contain an alias \
+ for test-library crate, but it just contained [{}]", root_build_contents)).unwrap();
+ }
+
+ #[test]
+ fn binaries_get_rust_binary_rules() {
+ let file_outputs = render_crates_for_test(vec![dummy_binary_crate()]);
+ let crate_build_contents = extract_contents_matching_path(&file_outputs, "vendor/test-binary-1.1.1/BUILD");
+
+ expect(crate_build_contents.contains("rust_binary("),
+ format!("expected crate build contents to contain rust_binary, \
+ but it just contained [{}]", crate_build_contents)).unwrap();
+ }
+
+ #[test]
+ fn libraries_get_rust_library_rules() {
+ let file_outputs = render_crates_for_test(vec![dummy_library_crate()]);
+ let crate_build_contents = extract_contents_matching_path(&file_outputs, "vendor/test-library-1.1.1/BUILD");
+
+ expect(crate_build_contents.contains("rust_library("),
+ format!("expected crate build contents to contain rust_library, \
+ but it just contained [{}]", crate_build_contents)).unwrap();
+ }
+}
diff --git a/src/context.rs b/src/context.rs
new file mode 100644
index 000000000..4e3728ce1
--- /dev/null
+++ b/src/context.rs
@@ -0,0 +1,54 @@
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
+pub struct BuildDependency {
+ pub name: String,
+ pub version: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
+pub struct BuildTarget {
+ pub name: String,
+ pub kind: String,
+ pub path: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
+pub struct Metadep {
+ pub name: String,
+ pub min_version: String,
+}
+
+#[derive(Debug, Clone, Serialize)]
+pub struct CrateContext {
+ pub pkg_name: String,
+ pub pkg_version: String,
+ pub features: Vec,
+ pub path: String,
+ pub dependencies: Vec,
+ pub build_dependencies: Vec,
+ pub dev_dependencies: Vec,
+ pub is_root_dependency: bool,
+ pub metadeps: Vec,
+ pub platform_triple: String,
+ pub targets: Vec,
+ pub build_script_target: Option,
+ pub additional_deps: Vec,
+ pub additional_flags: Vec,
+ pub extra_aliased_targets: Vec,
+ // TODO(acmcarther): Consider plugin topic
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
+pub struct WorkspaceContext {
+ /** The bazel path prefix to the vendor directory */
+ pub workspace_path: String,
+
+ /** The compilation target triple */
+ pub platform_triple: String,
+
+ /**
+ * The generated new_http_library Bazel workspace prefix.
+ *
+ * This has no effect unless the GenMode setting is Remote.
+ */
+ pub gen_workspace_prefix: String
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 000000000..6c5b3d1b9
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,161 @@
+#[macro_use]
+extern crate serde_derive;
+extern crate serde;
+extern crate cargo;
+extern crate rustc_serialize;
+extern crate itertools;
+extern crate tera;
+extern crate toml;
+
+#[cfg(test)]
+#[macro_use]
+extern crate hamcrest;
+
+mod context;
+mod planning;
+mod rendering;
+mod settings;
+mod util;
+mod bazel;
+
+use bazel::BazelRenderer;
+use cargo::CargoError;
+use cargo::CliResult;
+use cargo::util::CargoResult;
+use cargo::util::Config;
+use planning::BuildPlanner;
+use rendering::FileOutputs;
+use rendering::BuildRenderer;
+use rendering::RenderDetails;
+use settings::RazeSettings;
+use settings::GenMode;
+use std::env;
+use std::fs::File;
+use std::path::Path;
+use std::io::Read;
+use std::io::Write;
+
+#[derive(Debug, RustcDecodable)]
+struct Options {
+ arg_buildprefix: Option,
+ flag_verbose: u32,
+ flag_quiet: Option,
+ flag_host: Option,
+ flag_color: Option,
+ flag_target: Option,
+ flag_dryrun: Option,
+}
+
+const USAGE: &'static str = r#"
+Generate BUILD files for your pre-vendored Cargo dependencies.
+
+Usage:
+ cargo raze
+
+Options:
+ -h, --help Print this message
+ -v, --verbose Use verbose output
+ --host HOST Registry index to sync with
+ -q, --quiet No output printed to stdout
+ --color WHEN Coloring: auto, always, never
+ -d, --dryrun Do not emit any files
+"#;
+
+fn main() {
+ let cargo_config = Config::default().unwrap();
+ let args = env::args().collect::>();
+ let result = cargo::call_main_without_stdin(real_main, &cargo_config, USAGE, &args, false);
+
+ if let Err(e) = result {
+ cargo::exit_with_error(e, &mut *cargo_config.shell());
+ }
+}
+
+fn real_main(options: Options, cargo_config: &Config) -> CliResult {
+ try!(cargo_config.configure(options.flag_verbose,
+ options.flag_quiet,
+ &options.flag_color,
+ /* frozen = */ false,
+ /* locked = */ false));
+ let mut settings = try!(load_settings("Cargo.toml"));
+ println!("Loaded override settings: {:#?}", settings);
+
+ try!(validate_settings(&mut settings));
+
+ let mut planner = try!(BuildPlanner::new(settings.clone(), cargo_config));
+
+ if let Some(host) = options.flag_host {
+ try!(planner.set_registry_from_url(host));
+ }
+
+
+ let planned_build = try!(planner.plan_build());
+ let mut bazel_renderer = BazelRenderer::new();
+ let render_details = RenderDetails {
+ path_prefix: "./".to_owned(),
+ };
+
+ let bazel_file_outputs = match settings.genmode {
+ GenMode::Vendored => try!(bazel_renderer.render_planned_build(&render_details, &planned_build)),
+ GenMode::Remote => try!(bazel_renderer.render_remote_planned_build(&render_details, &planned_build)),
+ /* exhaustive, we control the definition */
+ };
+
+ let dry_run = options.flag_dryrun.unwrap_or(false);
+ for FileOutputs { path, contents } in bazel_file_outputs {
+ if !dry_run {
+ try!(write_to_file_loudly(&path, &contents));
+ } else {
+ println!("{}:\n{}", path, contents);
+ }
+ }
+
+ Ok(())
+}
+
+/** Verifies that the provided settings make sense. */
+fn validate_settings(settings: &mut RazeSettings) -> CargoResult<()> {
+ if !settings.workspace_path.starts_with("//") {
+ return Err(CargoError::from("raze.workspace_path must start with \"//\". Paths into local repositories (such as @local//path) are currently unsupported."))
+ }
+
+ if settings.workspace_path == "//" {
+ return Err(CargoError::from("raze.workspace_path must not be '//' (it is currently unsupported). Its probably not what you want anyway, as this would vendor the crates directly into //vendor."));
+ }
+
+ if settings.workspace_path.ends_with("/") {
+ settings.workspace_path.pop();
+ }
+
+ return Ok(())
+}
+
+fn write_to_file_loudly(path: &str, contents: &str) -> CargoResult<()> {
+ try!(File::create(&path)
+ .and_then(|mut f| f.write_all(contents.as_bytes()))
+ .map_err(|_| CargoError::from(format!("failed to create {}", path))));
+ println!("Generated {} successfully", path);
+ Ok(())
+}
+
+
+fn load_settings>(cargo_toml_path: T) -> Result {
+ let path = cargo_toml_path.as_ref();
+ let mut toml = try!(File::open(path)
+ .map_err(|e| {
+ println!("{:?}", e);
+ CargoError::from(format!("Could not load {:?}", path))
+ }));
+ let mut toml_contents = String::new();
+ try!(toml.read_to_string(&mut toml_contents)
+ .map_err(|e| {
+ println!("{:?}", e);
+ CargoError::from(format!("failed to read {:?}", path))
+ }));
+ toml::from_str::(&toml_contents)
+ .map_err(|e| {
+ println!("{:?}", e);
+ CargoError::from(format!("failed to parse {:?}", path))
+ })
+ .map(|toml| toml.raze)
+}
diff --git a/src/planning.rs b/src/planning.rs
new file mode 100644
index 000000000..171473831
--- /dev/null
+++ b/src/planning.rs
@@ -0,0 +1,298 @@
+use cargo::CargoError;
+use cargo::core::Dependency;
+use cargo::core::Package as CargoPackage;
+use cargo::core::PackageId;
+use cargo::core::PackageSet;
+use cargo::core::Resolve;
+use cargo::core::SourceId;
+use cargo::core::Workspace;
+use cargo::core::dependency::Kind;
+use cargo::ops::Packages;
+use cargo::ops;
+use cargo::util::CargoResult;
+use cargo::util::Cfg;
+use cargo::util::Config;
+use cargo::util::ToUrl;
+use context::BuildDependency;
+use context::BuildTarget;
+use context::CrateContext;
+use context::WorkspaceContext;
+use settings::RazeSettings;
+use settings::GenMode;
+use std::collections::HashSet;
+use std::env;
+use std::fs;
+use std::ops::Deref;
+use std::path::Path;
+use std::str;
+use util;
+
+pub struct PlannedBuild {
+ pub workspace_context: WorkspaceContext,
+ pub crate_contexts: Vec,
+}
+
+pub struct BuildPlanner<'a> {
+ settings: RazeSettings,
+ cargo_config: &'a Config,
+ platform_attrs: Vec,
+ registry: Option,
+}
+
+impl <'a> BuildPlanner<'a> {
+ pub fn new(settings: RazeSettings,
+ cargo_config: &'a Config) -> CargoResult> {
+ Ok(BuildPlanner {
+ platform_attrs: try!(util::fetch_attrs(&settings.target)),
+ cargo_config: cargo_config,
+ registry: None,
+ settings: settings,
+ })
+ }
+
+ pub fn set_registry_from_url(&mut self, host: String) -> CargoResult<()> {
+ match host.to_url().map(|url| SourceId::for_registry(&url)) {
+ Ok(registry_id) => {
+ self.registry = Some(registry_id);
+ Ok(())
+ },
+ Err(value) => Err(CargoError::from(value))
+ }
+ }
+
+ pub fn plan_build(&self) -> CargoResult {
+ let ResolvedPlan {root_name, packages, resolve} =
+ try!(ResolvedPlan::resolve_from_files(&self.cargo_config));
+
+ let root_package_id = try!(resolve.iter()
+ .filter(|dep| dep.name() == root_name)
+ .next()
+ .ok_or(CargoError::from("root crate should be in cargo resolve")));
+ let root_direct_deps = resolve.deps(&root_package_id).cloned().collect::>();
+
+ let mut crate_contexts = Vec::new();
+
+ let source_id = match self.registry.clone() {
+ Some(v) => v,
+ None => try!(SourceId::crates_io(&self.cargo_config)),
+ };
+
+ for id in try!(find_all_package_ids(source_id, &resolve)) {
+ let package = packages.get(&id).unwrap().clone();
+ let mut features = resolve.features(&id).clone().into_iter().collect::>();
+ features.sort();
+ let full_name = format!("{}-{}", id.name(), id.version());
+ let path = format!("./vendor/{}-{}/", id.name(), id.version());
+
+ // Verify that package is really vendored
+ if self.settings.genmode == GenMode::Vendored {
+ try!(fs::metadata(&path).map_err(|_| {
+ CargoError::from(format!("failed to find {}. Either switch to \"Remote\" genmode, or run `cargo vendor -x` first.", &path))
+ }));
+ }
+
+ // Identify all possible dependencies
+ let PlannedDeps { mut build_deps, mut dev_deps, mut normal_deps } =
+ PlannedDeps::find_all_deps(&id, &package, &resolve, &self.settings.target, &self.platform_attrs);
+ build_deps.sort();
+ dev_deps.sort();
+ normal_deps.sort();
+
+ let mut targets = try!(identify_targets(&full_name, &package));
+ targets.sort();
+
+ let possible_crate_settings =
+ self.settings.crates
+ .get(id.name())
+ .and_then(|c| c.get(&id.version().to_string()));
+
+ let should_gen_buildrs =
+ possible_crate_settings.map(|s| s.gen_buildrs.clone()).unwrap_or(false);
+ let build_script_target = if should_gen_buildrs {
+ targets.iter().find(|t| t.kind.deref() == "custom-build").cloned()
+ } else {
+ None
+ };
+
+ let targets_sans_build_script =
+ targets.into_iter().filter(|t| t.kind.deref() != "custom-build").collect::>();
+
+ let additional_deps =
+ possible_crate_settings.map(|s| s.additional_deps.clone()).unwrap_or(Vec::new());
+
+ let additional_flags =
+ possible_crate_settings.map(|s| s.additional_flags.clone()).unwrap_or(Vec::new());
+
+ let extra_aliased_targets =
+ possible_crate_settings.map(|s| s.extra_aliased_targets.clone()).unwrap_or(Vec::new());
+
+ // Skip generated dependencies explicitly designated to be skipped (potentially due to
+ // being replaced or customized as part of additional_deps)
+ let non_skipped_normal_deps = if let Some(s) = possible_crate_settings {
+ normal_deps.into_iter()
+ .filter(|d| !s.skipped_deps.contains(&format!("{}-{}", d.name, d.version)))
+ .collect::>()
+ } else {
+ normal_deps
+ };
+
+ crate_contexts.push(CrateContext {
+ pkg_name: id.name().to_owned(),
+ pkg_version: id.version().to_string(),
+ features: features,
+ is_root_dependency: root_direct_deps.contains(&id),
+ metadeps: Vec::new() /* TODO(acmcarther) */,
+ dependencies: non_skipped_normal_deps,
+ build_dependencies: build_deps,
+ dev_dependencies: dev_deps,
+ path: path,
+ build_script_target: build_script_target,
+ targets: targets_sans_build_script,
+ platform_triple: self.settings.target.to_owned(),
+ additional_deps: additional_deps,
+ additional_flags: additional_flags,
+ extra_aliased_targets: extra_aliased_targets,
+ })
+ }
+
+ let workspace_context = WorkspaceContext {
+ workspace_path: self.settings.workspace_path.clone(),
+ platform_triple: self.settings.target.clone(),
+ gen_workspace_prefix: self.settings.gen_workspace_prefix.clone(),
+ };
+
+ crate_contexts.sort_by_key(|context| format!("{}-{}", context.pkg_name, context.pkg_version));
+
+ Ok(PlannedBuild{
+ workspace_context: workspace_context,
+ crate_contexts: crate_contexts
+ })
+ }
+}
+
+/** The set of all included dependencies for Cargo's dependency categories. */
+pub struct PlannedDeps {
+ pub build_deps: Vec,
+ pub dev_deps: Vec,
+ pub normal_deps: Vec,
+}
+
+impl PlannedDeps {
+ /**
+ * Identifies the full set of cargo dependencies for the provided package id using cargo's
+ * resolution details.
+ */
+ pub fn find_all_deps(id: &PackageId,
+ package: &CargoPackage,
+ resolve: &Resolve,
+ platform_triple: &str,
+ platform_attrs: &Vec) -> PlannedDeps {
+ let platform_deps = package
+ .dependencies()
+ .iter()
+ .filter(|dep| {
+ dep.platform()
+ .map(|p| p.matches(&platform_triple, Some(&platform_attrs)))
+ .unwrap_or(true)
+ })
+ .cloned()
+ .collect::>();
+ let build_deps = util::take_kinded_dep_names(&platform_deps, Kind::Build);
+ let dev_deps = util::take_kinded_dep_names(&platform_deps, Kind::Development);
+ let normal_deps = util::take_kinded_dep_names(&platform_deps, Kind::Normal);
+ let resolved_deps = resolve.deps(&id).into_iter()
+ .map(|dep| BuildDependency {
+ name: dep.name().to_owned(),
+ version: dep.version().to_string(),
+ })
+ .collect::>();
+
+ PlannedDeps {
+ normal_deps:
+ resolved_deps.iter().filter(|d| normal_deps.contains(&d.name)).cloned().collect(),
+ build_deps:
+ resolved_deps.iter().filter(|d| build_deps.contains(&d.name)).cloned().collect(),
+ dev_deps:
+ resolved_deps.into_iter().filter(|d| dev_deps.contains(&d.name)).collect(),
+ }
+ }
+}
+
+/** A synthesized Cargo dependency resolution. */
+pub struct ResolvedPlan<'a> {
+ pub root_name: String,
+ pub packages: PackageSet<'a>,
+ pub resolve: Resolve,
+}
+
+impl<'a> ResolvedPlan<'a> {
+ /**
+ * Performs Cargo's own build plan resolution, yielding the root crate, the set of packages, and
+ * the resolution graph.
+ */
+ pub fn resolve_from_files(cargo_config: &Config) -> CargoResult {
+ let lockfile = Path::new("Cargo.lock");
+ let manifest_path = lockfile.parent().unwrap().join("Cargo.toml");
+ let manifest = env::current_dir().unwrap().join(&manifest_path);
+ let ws = try!(Workspace::new(&manifest, cargo_config));
+ let specs = Packages::All.into_package_id_specs(&ws)?;
+ let root_name = specs.iter().next().unwrap().name().to_owned();
+
+ let (packages, resolve) = ops::resolve_ws_precisely(
+ &ws,
+ None,
+ &[],
+ false,
+ false,
+ &specs)?;
+
+ Ok(ResolvedPlan {
+ root_name: root_name,
+ packages: packages,
+ resolve: resolve,
+ })
+ }
+}
+
+/** Enumerates the set of all possibly relevant packages for the Cargo dependencies */
+fn find_all_package_ids(registry_id: SourceId, resolve: &Resolve) -> CargoResult> {
+ try!(fs::metadata("Cargo.lock").map_err(|_| {
+ CargoError::from("failed to find Cargo.lock. Please run `cargo generate-lockfile` first.")
+ }));
+
+ let mut package_ids = resolve.iter()
+ .filter(|id| *id.source_id() == registry_id)
+ .cloned()
+ .collect::>();
+ package_ids.sort_by_key(|id| id.name().to_owned());
+ Ok(package_ids)
+}
+
+
+/** Derives target objects from Cargo's target information. */
+fn identify_targets(full_name: &str, package: &CargoPackage) -> CargoResult> {
+ let partial_path = format!("{}/", full_name);
+ let partial_path_byte_length = partial_path.as_bytes().len();
+ let mut targets = Vec::new();
+
+ for target in package.targets().iter() {
+ let target_path_str = try!(target.src_path().to_str()
+ .ok_or(CargoError::from(format!("path for {}'s target {} wasn't unicode", &full_name, target.name()))))
+ .to_owned();
+ let crate_name_str_idx = try!(target_path_str.find(&partial_path)
+ .ok_or(CargoError::from(format!("path for {}'s target {} should have been in vendor directory", &full_name, target.name()))));
+ let local_path_bytes = target_path_str.bytes()
+ .skip(crate_name_str_idx + partial_path_byte_length)
+ .collect::>();
+ let local_path_str = String::from_utf8(local_path_bytes).unwrap();
+ for kind in util::kind_to_kinds(target.kind()) {
+ targets.push(BuildTarget {
+ name: target.name().to_owned(),
+ path: local_path_str.clone(),
+ kind: kind,
+ });
+ }
+ }
+
+ Ok(targets)
+}
diff --git a/src/rendering.rs b/src/rendering.rs
new file mode 100644
index 000000000..5211542fa
--- /dev/null
+++ b/src/rendering.rs
@@ -0,0 +1,18 @@
+use cargo::util::CargoResult;
+use planning::PlannedBuild;
+
+#[derive(Debug, Clone)]
+pub struct FileOutputs {
+ pub path: String,
+ pub contents: String
+}
+
+#[derive(Debug, Clone)]
+pub struct RenderDetails {
+ pub path_prefix: String
+}
+
+pub trait BuildRenderer {
+ fn render_planned_build(&mut self, render_details: &RenderDetails, planned_build: &PlannedBuild) -> CargoResult>;
+ fn render_remote_planned_build(&mut self, render_details: &RenderDetails, planned_build: &PlannedBuild) -> CargoResult>;
+}
diff --git a/src/settings.rs b/src/settings.rs
new file mode 100644
index 000000000..712f81ab6
--- /dev/null
+++ b/src/settings.rs
@@ -0,0 +1,123 @@
+use std::collections::HashMap;
+
+#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
+pub enum GenMode {
+ /** Generate Vendored-style dependencies.
+ *
+ * This mode assumes that files are vendored (into vendor/), and generates BUILD files
+ * accordingly
+ */
+ Vendored,
+
+ /**
+ * Generate Remote-style dependencies.
+ *
+ * This mode assumes that files are not locally vendored, and generates a workspace-level
+ * function that can bring them in.
+ */
+ Remote,
+}
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct CargoToml {
+ /** The raze settings (the only part of the Cargo.toml we care about. */
+ pub raze: RazeSettings,
+}
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct RazeSettings {
+ /** The path to the Cargo.toml working directory. */
+ pub workspace_path: String,
+
+ /** The platform target to generate BUILD rules for.
+ *
+ * This comes in the form of a "triple", such as "x86_64-unknown-linux-gnu"
+ */
+ #[serde(default = "default_target")]
+ pub target: String,
+
+ /** Any crate-specific configuration. See CrateSetings for details. */
+ #[serde(default)]
+ pub crates: HashMap>,
+
+ /**
+ * Prefix for generated Bazel workspaces (from workspace_rules)
+ *
+ * This is only useful with remote genmode. It prefixes the names of the workspaces for
+ * dependencies (@PREFIX_crateName_crateVersion) as well as the name of the repository function
+ * generated in crates.bzl (PREFIX_fetch_remote_crates()).
+ *
+ * TODO(acmcarther): Does this have a non-bazel analogue?
+ */
+ #[serde(default = "default_gen_workspace_prefix")]
+ pub gen_workspace_prefix: String,
+
+ /** How to generate the dependencies. See GenMode for details. */
+ #[serde(default = "default_genmode")]
+ pub genmode: GenMode,
+}
+
+fn default_target() -> String {
+ "x86_64-unknown-linux-gnu".to_owned()
+}
+
+fn default_gen_workspace_prefix() -> String {
+ "raze".to_owned()
+}
+
+fn default_genmode() -> GenMode {
+ GenMode::Vendored
+}
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct CrateSettings {
+ /**
+ * Dependencies to be added to a crate.
+ *
+ * Importantly, the format of dependency references depends on the genmode.
+ * Remote: @{gen_workspace_prefix}__{dep_name}__{dep_version_sanitized}/:{dep_name}
+ * Vendored: //{workspace_path}/vendor/{dep_name}-{dep_version}:{dep_name}
+ *
+ * In addition, the added deps must be accessible from a remote workspace under Remote GenMode.
+ * Usually, this means they _also_ need to be remote, but a "local" build path prefixed with
+ * "@", in the form "@//something_local" may work.
+ */
+ #[serde(default)]
+ pub additional_deps: Vec,
+
+ /**
+ * Dependencies to be removed from a crate, in the form "//etc".
+ *
+ * Importantly, the format of dependency references depends on the gen mode.
+ * Remote: @{gen_workspace_prefix}__{dep_name}__{dep_version_sanitized}/:{dep_name}
+ * Vendored: //{workspace_path}/vendor/{dep_name}-{dep_version}:{dep_name}
+ */
+ #[serde(default)]
+ pub skipped_deps: Vec,
+
+ /**
+ * Library targets that should be aliased in the root BUILD file.
+ *
+ * This is useful to facilitate using binary utility crates, such as bindgen, as part of genrules.
+ */
+ #[serde(default)]
+ pub extra_aliased_targets: Vec,
+
+ /** Flags to be added to the crate compilation process, in the form "--flag". */
+ #[serde(default)]
+ pub additional_flags: Vec,
+
+ /**
+ * Whether or not to generate the build script that goes with this crate.
+ *
+ * Many build scripts will not function, as they will still be built hermetically. However, build
+ * scripts that merely generate files into OUT_DIR may be fully functional.
+ */
+ #[serde(default = "default_gen_buildrs")]
+ pub gen_buildrs: bool,
+
+}
+
+fn default_gen_buildrs() -> bool {
+ false
+}
diff --git a/src/templates/crate.BUILD.template b/src/templates/crate.BUILD.template
new file mode 100644
index 000000000..c5670e84e
--- /dev/null
+++ b/src/templates/crate.BUILD.template
@@ -0,0 +1,34 @@
+"""
+cargo-raze crate build file.
+
+DO NOT EDIT! Replaced on runs of cargo-raze
+"""
+package(default_visibility = ["{{workspace.workspace_path}}:__subpackages__"])
+
+load(
+ "@io_bazel_rules_rust//rust:rust.bzl",
+ "rust_library",
+ "rust_binary",
+ "rust_test",
+ "rust_bench_test",
+)
+
+{%- set crate_name_sanitized = crate.pkg_name | replace(from="-", to="_") %}
+{%- if crate.build_script_target %}
+{%- include "templates/partials/build_script.template" %}
+{%- endif %}
+{%- for target in crate.targets %}
+{%- if target.kind == "lib" %}
+{%- include "templates/partials/rust_library.template" %}
+{%- elif target.kind == "bin" %}
+{%- include "templates/partials/rust_binary.template" %}
+{%- elif target.kind == "proc-macro" %}
+{%- include "templates/partials/rust_library.template" %}
+{%- elif target.kind == "dylib" %}
+{%- include "templates/partials/rust_library.template" %}
+{%- elif target.kind == "rlib" %}
+{%- include "templates/partials/rust_library.template" %}
+{%- else %}
+# Unsupported target "{{ target.name }}" with type "{{ target.kind }}" omitted
+{%- endif %}
+{%- endfor %}
diff --git a/src/templates/partials/build_script.template b/src/templates/partials/build_script.template
new file mode 100644
index 000000000..34950fd47
--- /dev/null
+++ b/src/templates/partials/build_script.template
@@ -0,0 +1,46 @@
+rust_binary(
+ name = "{{ crate_name_sanitized }}_build_script",
+ srcs = glob(["**/*.rs"]),
+ {%- if crate.build_script_target.path %}
+ crate_root = "{{ crate.build_script_target.path }}",
+ {%- else %}
+ crate_root = "build.rs",
+ {%- endif %}
+ data = glob([
+ "*"
+ ]),
+ deps = [
+ {%- for dependency in crate.build_dependencies %}
+ "{{workspace.workspace_path}}/vendor/{{dependency.name}}-{{dependency.version}}:{{dependency.name | replace(from="-", to="_") }}",
+ {%- endfor %}
+ ],
+ rustc_flags = [
+ "--cap-lints allow",
+ "--target={{crate.platform_triple}}",
+ ],
+ crate_features = [
+ {%- for feature in crate.features %}
+ "{{feature}}",
+ {%- endfor %}
+ ],
+ visibility = ["//visibility:private"],
+)
+
+genrule(
+ name = "{{ crate_name_sanitized }}_build_script_executor",
+ srcs = glob(["*", "**/*.rs"]),
+ outs = ["{{ crate_name_sanitized }}_out_dir_outputs.tar.gz"],
+ tools = [":{{ crate_name_sanitized }}_build_script"],
+ local = 1,
+ cmd = "mkdir {{ crate_name_sanitized}}_out_dir_outputs/;"
+ + " (export CARGO_MANIFEST_DIR=\"$$PWD/{{ workspace.workspace_path | replace(from="//", to="") }}/vendor/{{ crate.pkg_name }}-{{ crate.pkg_version }}\";"
+ + " export TARGET='{{ crate.platform_triple }}';"
+ + " export RUST_BACKTRACE=1;"
+ {%- for feature in crate.features %}
+ + " export CARGO_FEATURE_{{ feature | upper | replace(from="-", to="_") }}=1;"
+ {%- endfor %}
+ + " export OUT_DIR=$$PWD/{{ crate_name_sanitized }}_out_dir_outputs;"
+ + " export BINARY_PATH=\"$$PWD/$(location :{{ crate_name_sanitized }}_build_script)\";"
+ + " export OUT_TAR=$$PWD/$@;"
+ + " cd $$(dirname $(location :Cargo.toml)) && $$BINARY_PATH && tar -czf $$OUT_TAR -C $$OUT_DIR .)"
+)
diff --git a/src/templates/partials/remote_build_script.template b/src/templates/partials/remote_build_script.template
new file mode 100644
index 000000000..a38fa9d98
--- /dev/null
+++ b/src/templates/partials/remote_build_script.template
@@ -0,0 +1,46 @@
+rust_binary(
+ name = "{{ crate_name_sanitized }}_build_script",
+ srcs = glob(["**/*.rs"]),
+ {%- if crate.build_script_target.path %}
+ crate_root = "{{ crate.build_script_target.path }}",
+ {%- else %}
+ crate_root = "build.rs",
+ {%- endif %}
+ data = glob([
+ "*"
+ ]),
+ deps = [
+ {%- for dependency in crate.build_dependencies %}
+ "@{{workspace.gen_workspace_prefix}}__{{dependency.name | slugify | replace(from="-", to="_")}}__{{dependency.version | slugify | replace(from="-", to="_")}}//:{{dependency.name | replace(from="-", to="_") }}",
+ {%- endfor %}
+ ],
+ rustc_flags = [
+ "--cap-lints allow",
+ "--target={{crate.platform_triple}}",
+ ],
+ crate_features = [
+ {%- for feature in crate.features %}
+ "{{feature}}",
+ {%- endfor %}
+ ],
+ visibility = ["//visibility:private"],
+)
+
+genrule(
+ name = "{{ crate_name_sanitized }}_build_script_executor",
+ srcs = glob(["*", "**/*.rs"]),
+ outs = ["{{ crate_name_sanitized }}_out_dir_outputs.tar.gz"],
+ tools = [":{{ crate_name_sanitized }}_build_script"],
+ local = 1,
+ cmd = "mkdir {{ crate_name_sanitized}}_out_dir_outputs/;"
+ + " (export CARGO_MANIFEST_DIR=\"$$PWD/$$(dirname $(location :Cargo.toml))\";"
+ + " export TARGET='{{ crate.platform_triple }}';"
+ + " export RUST_BACKTRACE=1;"
+ {%- for feature in crate.features %}
+ + " export CARGO_FEATURE_{{ feature | upper | replace(from="-", to="_") }}=1;"
+ {%- endfor %}
+ + " export OUT_DIR=$$PWD/{{ crate_name_sanitized }}_out_dir_outputs;"
+ + " export BINARY_PATH=\"$$PWD/$(location :{{ crate_name_sanitized }}_build_script)\";"
+ + " export OUT_TAR=$$PWD/$@;"
+ + " cd $$(dirname $(location :Cargo.toml)) && $$BINARY_PATH && tar -czf $$OUT_TAR -C $$OUT_DIR .)"
+)
diff --git a/src/templates/partials/remote_rust_binary.template b/src/templates/partials/remote_rust_binary.template
new file mode 100644
index 000000000..b0b744789
--- /dev/null
+++ b/src/templates/partials/remote_rust_binary.template
@@ -0,0 +1,33 @@
+{%- set target_name_sanitized = target.name | replace(from="-", to="_") %}
+rust_binary(
+ # Prefix bin name to disambiguate from (probable) collision with lib name
+ # N.B.: The exact form of this is subject to change.
+ name = "cargo_bin_{{ target_name_sanitized }}",
+ crate_root = "{{ target.path }}",
+ srcs = glob(["**/*.rs"]),
+ deps = [
+ # Binaries get an implicit dependency on their lib
+ ":{{crate.pkg_name | replace(from="-", to="_") }}",
+ {%- for dependency in crate.dependencies %}
+ "@{{workspace.gen_workspace_prefix}}__{{dependency.name | slugify | replace(from="-", to="_")}}__{{dependency.version | slugify | replace(from="-", to="_")}}//:{{dependency.name | replace(from="-", to="_") }}",
+ {%- endfor %}
+ {%- for dependency in crate.additional_deps %}
+ "{{dependency}}",
+ {%- endfor %}
+ ],
+ rustc_flags = [
+ "--cap-lints allow",
+ "--target={{crate.platform_triple}}",
+ {%- for flag in crate.additional_flags %}
+ "{{flag}}",
+ {%- endfor %}
+ ],
+ {%- if crate.build_script_target %}
+ out_dir_tar = ":{{ crate.pkg_name | replace(from="-", to="_")}}_build_script_executor",
+ {%- endif %}
+ crate_features = [
+ {%- for feature in crate.features %}
+ "{{feature}}",
+ {%- endfor %}
+ ],
+)
diff --git a/src/templates/partials/remote_rust_library.template b/src/templates/partials/remote_rust_library.template
new file mode 100644
index 000000000..62867579b
--- /dev/null
+++ b/src/templates/partials/remote_rust_library.template
@@ -0,0 +1,37 @@
+{%- set target_name_sanitized = target.name | replace(from="-", to="_") %}
+{%- if target_name_sanitized != crate_name_sanitized %}
+alias(
+ name = "{{ crate_name_sanitized }}",
+ actual = ":{{ target_name_sanitized }}",
+)
+{%- endif %}
+
+rust_library(
+ name = "{{ target_name_sanitized }}",
+ crate_root = "{{ target.path }}",
+ crate_type = "{{ target.kind }}",
+ srcs = glob(["**/*.rs"]),
+ deps = [
+ {%- for dependency in crate.dependencies %}
+ "@{{workspace.gen_workspace_prefix}}__{{dependency.name | slugify | replace(from="-", to="_")}}__{{dependency.version | slugify | replace(from="-", to="_")}}//:{{dependency.name | replace(from="-", to="_") }}",
+ {%- endfor %}
+ {%- for dependency in crate.additional_deps %}
+ "{{dependency}}",
+ {%- endfor %}
+ ],
+ rustc_flags = [
+ "--cap-lints allow",
+ "--target={{crate.platform_triple}}",
+ {%- for flag in crate.additional_flags %}
+ "{{flag}}",
+ {%- endfor %}
+ ],
+ {%- if crate.build_script_target %}
+ out_dir_tar = ":{{ crate.pkg_name | replace(from="-", to="_")}}_build_script_executor",
+ {%- endif %}
+ crate_features = [
+ {%- for feature in crate.features %}
+ "{{feature}}",
+ {%- endfor %}
+ ],
+)
diff --git a/src/templates/partials/rust_binary.template b/src/templates/partials/rust_binary.template
new file mode 100644
index 000000000..e5d153c42
--- /dev/null
+++ b/src/templates/partials/rust_binary.template
@@ -0,0 +1,33 @@
+{%- set target_name_sanitized = target.name | replace(from="-", to="_") %}
+rust_binary(
+ # Prefix bin name to disambiguate from (probable) collision with lib name
+ # N.B.: The exact form of this is subject to change.
+ name = "cargo_bin_{{ target_name_sanitized }}",
+ crate_root = "{{ target.path }}",
+ srcs = glob(["**/*.rs"]),
+ deps = [
+ # Binaries get an implicit dependency on their lib
+ ":{{crate.pkg_name | replace(from="-", to="_") }}",
+ {%- for dependency in crate.dependencies %}
+ "{{workspace.workspace_path}}/vendor/{{dependency.name}}-{{dependency.version}}:{{dependency.name | replace(from="-", to="_") }}",
+ {%- endfor %}
+ {%- for dependency in crate.additional_deps %}
+ "{{dependency}}",
+ {%- endfor %}
+ ],
+ rustc_flags = [
+ "--cap-lints allow",
+ "--target={{crate.platform_triple}}",
+ {%- for flag in crate.additional_flags %}
+ "{{flag}}",
+ {%- endfor %}
+ ],
+ {%- if crate.build_script_target %}
+ out_dir_tar = ":{{ crate.pkg_name | replace(from="-", to="_")}}_build_script_executor",
+ {%- endif %}
+ crate_features = [
+ {%- for feature in crate.features %}
+ "{{feature}}",
+ {%- endfor %}
+ ],
+)
diff --git a/src/templates/partials/rust_library.template b/src/templates/partials/rust_library.template
new file mode 100644
index 000000000..5898267f7
--- /dev/null
+++ b/src/templates/partials/rust_library.template
@@ -0,0 +1,37 @@
+{%- set target_name_sanitized = target.name | replace(from="-", to="_") %}
+{%- if target_name_sanitized != crate_name_sanitized %}
+alias(
+ name = "{{ crate_name_sanitized }}",
+ actual = ":{{ target_name_sanitized }}",
+)
+{%- endif %}
+
+rust_library(
+ name = "{{ target_name_sanitized }}",
+ crate_root = "{{ target.path }}",
+ crate_type = "{{ target.kind }}",
+ srcs = glob(["**/*.rs"]),
+ deps = [
+ {%- for dependency in crate.dependencies %}
+ "{{workspace.workspace_path}}/vendor/{{dependency.name}}-{{dependency.version}}:{{dependency.name | replace(from="-", to="_") }}",
+ {%- endfor %}
+ {%- for dependency in crate.additional_deps %}
+ "{{dependency}}",
+ {%- endfor %}
+ ],
+ rustc_flags = [
+ "--cap-lints allow",
+ "--target={{crate.platform_triple}}",
+ {%- for flag in crate.additional_flags %}
+ "{{flag}}",
+ {%- endfor %}
+ ],
+ {%- if crate.build_script_target %}
+ out_dir_tar = ":{{ crate.pkg_name | replace(from="-", to="_")}}_build_script_executor",
+ {%- endif %}
+ crate_features = [
+ {%- for feature in crate.features %}
+ "{{feature}}",
+ {%- endfor %}
+ ],
+)
diff --git a/src/templates/remote_crate.BUILD.template b/src/templates/remote_crate.BUILD.template
new file mode 100644
index 000000000..fe54cd177
--- /dev/null
+++ b/src/templates/remote_crate.BUILD.template
@@ -0,0 +1,33 @@
+"""
+cargo-raze crate build file.
+
+DO NOT EDIT! Replaced on runs of cargo-raze
+"""
+package(default_visibility = ["//visibility:public"])
+
+load(
+ "@io_bazel_rules_rust//rust:rust.bzl",
+ "rust_library",
+ "rust_binary",
+ "rust_test",
+ "rust_bench_test",
+)
+{% set crate_name_sanitized = crate.pkg_name | replace(from="-", to="_") %}
+{%- if crate.build_script_target %}
+{%- include "templates/partials/remote_build_script.template" %}
+{%- endif %}
+{%- for target in crate.targets %}
+{%- if target.kind == "lib" %}
+{%- include "templates/partials/remote_rust_library.template" %}
+{%- elif target.kind == "bin" %}
+{%- include "templates/partials/remote_rust_binary.template" %}
+{%- elif target.kind == "proc-macro" %}
+{%- include "templates/partials/remote_rust_library.template" %}
+{%- elif target.kind == "dylib" %}
+{%- include "templates/partials/remote_rust_library.template" %}
+{%- elif target.kind == "rlib" %}
+{%- include "templates/partials/remote_rust_library.template" %}
+{%- else %}
+# Unsupported target "{{ target.name }}" with type "{{ target.kind }}" omitted
+{%- endif %}
+{%- endfor %}
diff --git a/src/templates/remote_crates.bzl.template b/src/templates/remote_crates.bzl.template
new file mode 100644
index 000000000..96b6e0dbb
--- /dev/null
+++ b/src/templates/remote_crates.bzl.template
@@ -0,0 +1,16 @@
+"""
+cargo-raze crate workspace functions
+
+DO NOT EDIT! Replaced on runs of cargo-raze
+"""
+
+def {{workspace.gen_workspace_prefix}}_fetch_remote_crates():
+{% for crate in crates %}
+ native.new_http_archive(
+ name = "{{workspace.gen_workspace_prefix}}__{{crate.pkg_name | slugify | replace(from="-", to="_")}}__{{crate.pkg_version | slugify | replace(from="-", to="_")}}",
+ url = "https://crates-io.s3-us-west-1.amazonaws.com/crates/{{crate.pkg_name}}/{{crate.pkg_name}}-{{crate.pkg_version}}.crate",
+ type = "tar.gz",
+ strip_prefix = "{{crate.pkg_name}}-{{crate.pkg_version}}",
+ build_file = "{{workspace.workspace_path}}:{{crate.pkg_name}}-{{crate.pkg_version}}.BUILD"
+ )
+{% endfor %}
diff --git a/src/templates/remote_workspace.BUILD.template b/src/templates/remote_workspace.BUILD.template
new file mode 100644
index 000000000..144fa9a7a
--- /dev/null
+++ b/src/templates/remote_workspace.BUILD.template
@@ -0,0 +1,23 @@
+"""
+cargo-raze workspace build file.
+
+DO NOT EDIT! Replaced on runs of cargo-raze
+"""
+package(default_visibility = ["//visibility:public"])
+{% for crate in crates %}
+{%- if crate.is_root_dependency %}
+{%- set crate_name_sanitized = crate.pkg_name | replace(from="-", to="_") %}
+alias(
+ name = "{{crate_name_sanitized}}",
+ actual = "@{{workspace.gen_workspace_prefix}}__{{crate.pkg_name | slugify | replace(from="-", to="_")}}__{{crate.pkg_version | slugify | replace(from="-", to="_")}}//:{{crate_name_sanitized}}",
+)
+{%- endif %}
+{%- for aliased_target in crate.extra_aliased_targets %}
+alias(
+ # Extra aliased target, from raze configuration
+ # N.B.: The exact form of this is subject to change.
+ name = "{{aliased_target}}",
+ actual = "@{{workspace.gen_workspace_prefix}}__{{crate.pkg_name | slugify | replace(from="-", to="_")}}__{{crate.pkg_version | slugify | replace(from="-", to="_")}}//:{{aliased_target}}",
+)
+{%- endfor %}
+{%- endfor %}
diff --git a/src/templates/workspace.BUILD.template b/src/templates/workspace.BUILD.template
new file mode 100644
index 000000000..1b5229e75
--- /dev/null
+++ b/src/templates/workspace.BUILD.template
@@ -0,0 +1,24 @@
+"""
+cargo-raze workspace build file.
+
+DO NOT EDIT! Replaced on runs of cargo-raze
+"""
+package(default_visibility = ["//visibility:public"])
+
+{%- for crate in crates %}
+{%- if crate.is_root_dependency %}
+{%- set crate_name_sanitized = crate.pkg_name | replace(from="-", to="_") %}
+alias(
+ name = "{{crate_name_sanitized}}",
+ actual = "{{workspace.workspace_path}}/vendor/{{crate.pkg_name}}-{{crate.pkg_version}}:{{crate_name_sanitized}}",
+)
+{%- endif %}
+{%- for aliased_target in crate.extra_aliased_targets %}
+alias(
+ # Extra aliased target, from raze configuration
+ # N.B.: The exact form of this is subject to change.
+ name = "{{aliased_target}}",
+ actual = "{{workspace.workspace_path}}/vendor/{{crate.pkg_name}}-{{crate.pkg_version}}:{{aliased_target}}",
+)
+{%- endfor %}
+{%- endfor %}
diff --git a/src/util.rs b/src/util.rs
new file mode 100644
index 000000000..9884f637c
--- /dev/null
+++ b/src/util.rs
@@ -0,0 +1,70 @@
+use cargo::CargoError;
+use cargo::core::Dependency;
+use cargo::core::TargetKind;
+use cargo::core::dependency::Kind;
+use cargo::util::CargoResult;
+use cargo::util::Cfg;
+use std::collections::HashSet;
+use std::process::Command;
+use std::str::FromStr;
+use std::str;
+
+/** Extracts the dependencies that are of the provided kind. */
+pub fn take_kinded_dep_names(platform_deps: &Vec, kind: Kind) -> HashSet {
+ platform_deps
+ .iter()
+ .filter(|d| d.kind() == kind)
+ .map(|dep| dep.name().to_owned())
+ .collect()
+}
+
+/**
+ * Extracts consistently named Strings for the provided TargetKind.
+ *
+ * TODO(acmcarther): Remove this shim borrowed from Cargo when Cargo is upgraded
+ */
+pub fn kind_to_kinds(kind: &TargetKind) -> Vec {
+ match kind {
+ &TargetKind::Lib(ref kinds) => kinds.iter().map(|k| k.crate_type().to_owned()).collect(),
+ &TargetKind::Bin => vec!["bin".to_owned()],
+ &TargetKind::ExampleBin | &TargetKind::ExampleLib(_) => vec!["example".to_owned()],
+ &TargetKind::Test => vec!["test".to_owned()],
+ &TargetKind::CustomBuild => vec!["custom-build".to_owned()],
+ &TargetKind::Bench => vec!["bench".to_owned()],
+ }
+}
+
+/**
+ * Gets the proper system attributes for the provided platform triple using rustc.
+ */
+pub fn fetch_attrs(target: &str) -> CargoResult> {
+ let args = vec![
+ format!("--target={}", target),
+ "--print=cfg".to_owned(),
+ ];
+
+
+ let output = try!(Command::new("rustc")
+ .args(&args)
+ .output()
+ .map_err(|_| CargoError::from(format!("could not run rustc to fetch attrs for target {}", target))));
+
+ if !output.status.success() {
+ panic!(format!("getting target attrs for {} failed with status: '{}' \n\
+ stdout: {}\n\
+ stderr: {}",
+ target,
+ output.status,
+ String::from_utf8(output.stdout).unwrap_or("[unparseable bytes]".to_owned()),
+ String::from_utf8(output.stderr).unwrap_or("[unparseable bytes]".to_owned())))
+ }
+
+ let attr_str = String::from_utf8(output.stdout)
+ .expect("successful run of rustc's output to be utf8");
+
+ Ok(attr_str.lines()
+ .map(Cfg::from_str)
+ .map(|cfg| cfg.expect("attrs from rustc should be parsable into Cargo Cfg"))
+ .collect())
+}
+