diff --git a/.ci_helper.sh b/.ci_helper.sh
deleted file mode 100755
index feaddfc..0000000
--- a/.ci_helper.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-set -e
-
-PROJECT_NAME="hatch";
-
-cd $PROJECT_NAME;
-
-cargo build --verbose --all
-cargo test --verbose --all
diff --git a/.ci_helpers/appveyor_helper.bat b/.ci_helpers/appveyor_helper.bat
new file mode 100644
index 0000000..df54af1
--- /dev/null
+++ b/.ci_helpers/appveyor_helper.bat
@@ -0,0 +1,4 @@
+cd "hatch"
+
+cargo build --verbose --all
+cargo test --verbose --all
diff --git a/.coveralls.yml b/.coveralls.yml
new file mode 100644
index 0000000..e69de29
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9f11b75
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.idea/
diff --git a/.travis.yml b/.travis.yml
index e611baf..ed95e5d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,45 @@
-lanugage: rust
+sudo: required
+
+language: rust
+
+addons:
+ apt:
+ packages:
+ - libssl-dev
+
cache: cargo
+
+rust:
+ - stable
+ - nightly
+
+# load travis-cargo
+before_script:
+ - export PATH=$HOME/.cargo/bin:$PATH
+ - cargo install cargo-update || echo "cargo-update already installed"
+ - cargo install-update -a # update outdated cached binaries
+
+os:
+ - linux
+ - osx
+
script:
- - ./.ci_helper.sh
+ - |
+ cd hatch &&
+ cargo clean &&
+ cargo build &&
+ cargo test
+
+after_success:
+ - |
+ if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then
+ bash <(curl https://raw.githubusercontent.com/xd009642/tarpaulin/master/travis-install.sh)
+ cargo tarpaulin --ciserver travis-ci --coveralls $TRAVIS_JOB_ID;
+ fi
+
branches:
# This is where pull requests from "bors r+" are built.
- staging
# This is where pull requests from "bors try" are built.
- trying
+ - dev
diff --git a/README.md b/README.md
index 3438bd3..c62d991 100644
--- a/README.md
+++ b/README.md
@@ -3,12 +3,35 @@
Hatch
The project manager for CachedNerds/Toolbox et;al
+
+
+
+
+# [Workflow Standards](https://github.com/CachedNerds/Hatch/blob/master/WORKFLOW.md)
+
# Usage
# Technologies
# Contributing
+Please follow the [Style Guide](STYLE.md) when contributing.
+
# Code of conduct
# License
diff --git a/STYLE.md b/STYLE.md
new file mode 100644
index 0000000..39dafec
--- /dev/null
+++ b/STYLE.md
@@ -0,0 +1,94 @@
+Rust Style Guide
+
+*Please write good Rust.*
+
+## Table of Contents
+
+1. [Unsafe](#unsafe)
+2. [Whitespace](#whitespace)
+3. [Dereferences](#dereferences)
+4. [Use Statements](#use_statements)
+
+
+## Unsafe
+
+No use of the `unsafe` keyword is allowed. This guideline is statically enforced.
+
+## Whitespace
+
+All curly brace blocks will have at least one line return between the opening brace and the closing brace. The opening
+curly brace of keyword blocks (e.g. `impl`) will be placed on the same line as the keyword.
+
+##### Bad
+```rust
+impl Project { pub fn new() -> Project { ... } }
+```
+
+##### Good
+```rust
+impl Project {
+ pub fn new() -> Project {
+ ...
+ }
+}
+```
+
+All `else` and `else if` blocks will begin on the same line as the previous closing curly brace.
+
+##### Bad
+```rust
+if arg.is_present("bin") { ... }
+else if arg.is_present("static") { ... }
+else { ... }
+```
+
+##### Good
+```rust
+if arg.is_present("bin") {
+ ...
+} else if arg.is_present("static") {
+ ...
+} else {
+ ...
+}
+```
+
+## Dereferences
+
+When `y` is a reference, the asterisk operator used to _dereference_ `y` should
+contain no whitespace between the operator and the reference.
+
+##### Bad
+
+```rust
+match * y {
+ ...
+}
+```
+
+##### Good
+
+```rust
+match *y {
+ ...
+}
+```
+
+When `*y` is a reference the same styling as above should be used.
+
+## Use Statements
+
+When importing names from a module, only use the bracket notation when importing multiple names.
+
+##### Bad
+
+```rust
+use project::{ Project };
+```
+
+##### Good
+
+```rust
+use project::Project;
+use Foo::{ Bar, Baz };
+```
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..c1a99f5
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,69 @@
+# Appveyor configuration template for Rust using rustup for Rust installation
+# https://github.com/starkat99/appveyor-rust
+
+## Operating System (VM environment) ##
+
+# Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets.
+os: Visual Studio 2015
+
+## Build Matrix ##
+
+# This configuration will setup a build for each channel & target combination (12 windows
+# combinations in all).
+#
+# There are 3 channels: stable, beta, and nightly.
+#
+# Alternatively, the full version may be specified for the channel to build using that specific
+# version (e.g. channel: 1.5.0)
+#
+# The values for target are the set of windows Rust build targets. Each value is of the form
+#
+# ARCH-pc-windows-TOOLCHAIN
+#
+# Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker
+# toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for
+# a description of the toolchain differences.
+# See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of
+# toolchains and host triples.
+#
+# Comment out channel/target combos you do not wish to build in CI.
+#
+# You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands
+# and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly
+# channels to enable unstable features when building for nightly. Or you could add additional
+# matrix entries to test different combinations of features.
+environment:
+ matrix:
+
+### MSVC Toolchains ###
+
+ # Stable 64-bit MSVC
+ - channel: stable
+ target: x86_64-pc-windows-msvc
+
+## Install Script ##
+
+# This is the most important part of the Appveyor configuration. This installs the version of Rust
+# specified by the 'channel' and 'target' environment variables from the build matrix. This uses
+# rustup to install Rust.
+#
+# For simple configurations, instead of using the build matrix, you can simply set the
+# default-toolchain and default-host manually here.
+install:
+ - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
+ - rustup-init -yv --default-toolchain %channel% --default-host %target%
+ - set PATH=%PATH%;%USERPROFILE%\.cargo\bin
+ - rustc -vV
+ - cargo -vV
+
+## Build Script ##
+
+# 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents
+# the "directory does not contain a project or solution file" error.
+build: false
+
+# Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs
+#directly or perform other testing commands. Rust will automatically be placed in the PATH
+# environment variable.
+test_script:
+ - .ci_helpers/appveyor_helper.bat
diff --git a/hatch/Cargo.lock b/hatch/Cargo.lock
index 317da18..1a89bac 100644
--- a/hatch/Cargo.lock
+++ b/hatch/Cargo.lock
@@ -1,63 +1,616 @@
-[root]
+[[package]]
+name = "adler32"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "aho-corasick"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "atty"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "base64"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "safemem 0.2.0 (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 = "bitflags"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "build_const"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "byteorder"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bytes"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clap"
+version = "2.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crc"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "curl-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.23 (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.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dtoa"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "failure"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "fuchsia-zircon"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fuchsia-zircon-sys"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "futures"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "futures-cpupool"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "git2"
+version = "0.6.11"
+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.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "hatch"
version = "0.1.0"
dependencies = [
- "clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "os_info 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "reqwest 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "httparse"
+version = "1.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "hyper"
+version = "0.11.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.11.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "idna"
+version = "0.1.4"
+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.4 (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 = "iovec"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "itoa"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "language-tags"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "lazy_static"
+version = "0.2.11"
+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 = "lazycell"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libflate"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libgit2-sys"
+version = "0.6.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (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.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.23 (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.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.23 (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.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (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.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "log"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (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 = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mime_guess"
+version = "2.0.0-alpha.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (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.31 (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 = "native-tls"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "net2"
+version = "0.2.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (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.35 (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-traits"
+version = "0.1.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num_cpus"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "openssl"
+version = "0.9.23"
+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.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "ansi_term"
-version = "0.9.0"
+name = "openssl-probe"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "atty"
-version = "0.2.3"
+name = "openssl-sys"
+version = "0.9.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (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 = "os_info"
+version = "0.7.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.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "bitflags"
-version = "0.9.1"
+name = "percent-encoding"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "clap"
-version = "2.26.2"
+name = "phf"
+version = "0.7.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "kernel32-sys"
-version = "0.2.2"
+name = "phf_codegen"
+version = "0.7.21"
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)",
+ "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "libc"
-version = "0.2.32"
+name = "phf_generator"
+version = "0.7.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.7.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicase 1.4.2 (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 = "quote"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rand"
+version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "redox_syscall"
-version = "0.1.31"
+version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -65,22 +618,191 @@ name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.5 (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.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "relay"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.11.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libflate 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime_guess 2.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "safemem"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "schannel"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.3 (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 = "security-framework"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_json"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "serde_urlencoded"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "siphasher"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "slab"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "slab"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "smallvec"
+version = "0.2.1"
+source = "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 = "term_size"
-version = "0.3.0"
+name = "syn"
+version = "0.11.11"
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.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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 = "synstructure"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "take"
+version = "0.1.0"
+source = "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.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -88,54 +810,365 @@ name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "thread_local"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.0.0 (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.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-core"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-io"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-proto"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-service"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-tls"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicase"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicase"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.4"
+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-width"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "unicode-xid"
+version = "0.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "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.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "idna 0.1.4 (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.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "user32-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 = "utf8-ranges"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "uuid"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand 0.3.20 (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 = "vec_map"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "version_check"
+version = "0.1.3"
+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"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.3.2 (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 = "winapi-i686-pc-windows-gnu"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.3.2"
+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)",
+]
+
+[[package]]
+name = "yaml-rust"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[metadata]
-"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
-"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
+"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
+"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
+"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
+"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
+"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"
+"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
+"checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
-"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
+"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
+"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9"
+"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
+"checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9"
+"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"
+"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
+"checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
+"checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
+"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
+"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d"
+"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
+"checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961"
+"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
+"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
+"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
+"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+"checksum futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0bab5b5e94f5c31fc764ba5dd9ad16568aae5d4825538c01d6bca680c9bf94a7"
+"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
+"checksum git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5b4bb7cd2a44e6e5ee3a26ba6a9ca10d4ce2771cdc3839bbc54b47b7d1be84"
+"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37"
+"checksum hyper 0.11.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4d6105c5eeb03068b10ff34475a0d166964f98e7b9777cc34b342a225af9b87c"
+"checksum hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c81fa95203e2a6087242c38691a0210f23e9f3f8f944350bd676522132e2985"
+"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
+"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
+"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148"
-"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509"
+"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
+"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
+"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
+"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
+"checksum libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)" = "96264e9b293e95d25bfcbbf8a88ffd1aedc85b754eba8b7d78012f638ba220eb"
+"checksum libflate 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1a429b86418868c7ea91ee50e9170683f47fd9d94f5375438ec86ec3adb74e8e"
+"checksum libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6eeae66e7b1c995de45cb4e65c5ab438a96a7b4077e448645d4048dc753ad357"
+"checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75"
+"checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16"
+"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
+"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
+"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
+"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
+"checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd"
+"checksum mime_guess 2.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "013572795763289e14710c7b279461295f2673b2b338200c235082cd7ca9e495"
+"checksum mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "75f72a93f046f1517e3cfddc0a096eb756a2ba727d36edc8227dee769a50a9b0"
+"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0"
+"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
+"checksum num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9936036cc70fe4a8b2d338ab665900323290efb03983c86cbe235ae800ad8017"
+"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
+"checksum openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854"
+"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
+"checksum openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "2200ffec628e3f14c39fc0131a301db214f1a7d584e36507ee8700b0c7fb7a46"
+"checksum os_info 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "476978c9c7ae859d53a97fbbbdb7e7097b823c43c6abc8f33bf262249f41f617"
+"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
+"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
+"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
+"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
+"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
+"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
+"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
+"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
+"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
+"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
+"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
+"checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5"
+"checksum reqwest 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "449c45f593ce9af9417c91e22f274fb8cea013bcf3d37ec1b5fb534b623bc708"
+"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
+"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
+"checksum schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "acece75e0f987c48863a6c792ec8b7d6c4177d4a027f8ccc72f849794f437016"
+"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
+"checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332"
+"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead"
+"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
+"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb"
+"checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480"
+"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
+"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
+"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d"
+"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
-"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
+"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 synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
+"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5"
+"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
-"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
+"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
+"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
+"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
+"checksum tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "52b4e32d8edbf29501aabb3570f027c6ceb00ccef6538f4bddba0200503e74e8"
+"checksum tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "514aae203178929dbf03318ad7c683126672d4d96eccb77b29603d33c9e25743"
+"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389"
+"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
+"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913"
+"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
+"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
+"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
+"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
+"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
+"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
+"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"
+"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
+"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
+"checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22"
+"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
+"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
+"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 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b09fb3b6f248ea4cd42c9a65113a847d612e17505d6ebd1f7357ad68a8bf8693"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+"checksum winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec6667f60c23eca65c561e63a13d81b44234c2e38a6b6c959025ee907ec614cc"
+"checksum winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98f12c52b2630cd05d2c3ffd8e008f7f48252c042b4871c72aed9dc733b96668"
+"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
+"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
diff --git a/hatch/Cargo.toml b/hatch/Cargo.toml
index 251da4c..ae44237 100644
--- a/hatch/Cargo.toml
+++ b/hatch/Cargo.toml
@@ -5,3 +5,8 @@ authors = ["technetos "]
[dependencies]
clap = "2"
+yaml-rust = "0.3"
+git2 = "0.6"
+failure = "0.1.1"
+os_info = "0.7.0"
+reqwest = "0.8.4"
diff --git a/hatch/src/asset.rs b/hatch/src/asset.rs
deleted file mode 100644
index bfda86a..0000000
--- a/hatch/src/asset.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use dtl::asset as asset_imp;
-use dtl::asset::{ AssetKind };
-
-#[derive(Debug)]
-pub struct Asset(asset_imp::AssetBuilder);
-
-impl Asset {
- pub fn new() -> Asset {
- Asset(asset_imp::AssetBuilder::new())
- }
-
- pub fn assets(&mut self) -> &Vec {
- self.0.assets()
- }
-}
diff --git a/hatch/src/assets/builder.rs b/hatch/src/assets/builder.rs
new file mode 100644
index 0000000..78fe6c8
--- /dev/null
+++ b/hatch/src/assets/builder.rs
@@ -0,0 +1,160 @@
+use assets::{ TupKind, PlatformKind, ProjectAsset };
+use assets::config::Config;
+use assets::tuprules::Tuprules;
+use assets::test_tupfile::Tupfile as TestTupfile;
+use assets::tupfile::Tupfile;
+use assets::platform::{ Linux, MacOS, Windows };
+use assets::tupfile_ini::TupfileIni;
+use assets::catch_header::CatchHeader;
+use assets::catch_definition::CatchDefinition;
+use hatch_error::{ HatchResult, ResultExt, NullError };
+use project::Project;
+use platform::os;
+use reqwest;
+
+static CATCH_HEADER_URL: &str = "https://github.com/catchorg/Catch2/releases/download/v2.1.1/catch.hpp";
+
+pub struct Builder {
+ assets: Vec,
+}
+
+impl Builder {
+ pub fn new() -> Builder {
+ Builder { assets: Vec::new() }
+ }
+
+ pub fn from(project: &Project) -> Builder {
+ let mut builder = Builder::new();
+
+ builder.project(&TupKind::Config, project);
+ builder.project(&TupKind::TestTupfile, project);
+ builder.project(&TupKind::Tuprules, project);
+ builder.project(&TupKind::Tupfile, project);
+ builder.project(&TupKind::TupfileIni, project);
+
+ let platform_type = os::platform_type();
+ builder.platform(&platform_type, project);
+
+ if let Ok(catch_header) = builder.catch_header(project) {
+ builder.add_asset(catch_header);
+ }
+
+ let catch_definition = builder.catch_definition(project);
+ builder.add_asset(catch_definition);
+
+ builder
+ }
+
+ pub fn assets(&mut self) -> &Vec {
+ &self.assets.as_ref()
+ }
+
+ pub fn add_asset(&mut self, asset: ProjectAsset) {
+ self.assets.push(asset);
+ }
+
+ pub fn project(&mut self, asset_kind: &TupKind, project: &Project) {
+ let asset = match *asset_kind {
+ TupKind::Config => self.config(project),
+ TupKind::TestTupfile => self.test_tupfile(project),
+ TupKind::Tuprules => self.tuprules(project),
+ TupKind::Tupfile => self.tupfile(project),
+ TupKind::TupfileIni => self.tupfile_ini(project),
+ };
+
+ self.assets.push(asset);
+ }
+
+ pub fn platform(&mut self, asset_kind: &PlatformKind, project: &Project) {
+ let asset = match *asset_kind {
+ PlatformKind::Linux => self.linux(project),
+ PlatformKind::MacOS => self.macos(project),
+ PlatformKind::Windows => self.windows(project)
+ };
+
+ self.assets.push(asset);
+ }
+
+ pub fn config(&self, project: &Project) -> ProjectAsset {
+ let project_path = project.path();
+ let contents = Config::new(project.name(), project.config().kind()).to_string();
+
+ ProjectAsset::new(project_path.to_path_buf(), Config::name(), contents)
+ }
+
+ pub fn test_tupfile(&self, project: &Project) -> ProjectAsset {
+ let asset_path = project.path().join("test");
+ let contents = TestTupfile::new().to_string();
+
+ ProjectAsset::new(asset_path, TestTupfile::name(), contents)
+ }
+
+ pub fn tuprules(&self, project: &Project) -> ProjectAsset {
+ let project_path = project.path();
+ let config = project.config();
+ let contents = Tuprules::new(config).to_string();
+
+ ProjectAsset::new(project_path.to_path_buf(), Tuprules::name(), contents)
+ }
+
+ pub fn tupfile(&self, project: &Project) -> ProjectAsset {
+ let project_path = project.path();
+ let contents = Tupfile::new(project.config().kind()).to_string();
+
+ ProjectAsset::new(project_path.to_path_buf(), Tupfile::name(), contents)
+ }
+
+ pub fn tupfile_ini(&self, project: &Project) -> ProjectAsset {
+ let project_path = project.path();
+ let contents = TupfileIni::new().to_string();
+
+ ProjectAsset::new(project_path.to_path_buf(), TupfileIni::name(), contents)
+ }
+
+ pub fn linux(&self, project: &Project) -> ProjectAsset {
+ let project_path = project.path();
+ let contents = Linux::new().to_string();
+
+ ProjectAsset::new(project_path.to_path_buf(), Linux::name(), contents)
+ }
+
+ pub fn macos(&self, project: &Project) -> ProjectAsset {
+ let project_path = project.path();
+ let contents = MacOS::new().to_string();
+
+ ProjectAsset::new(project_path.to_path_buf(), MacOS::name(), contents)
+ }
+
+ pub fn windows(&self, project: &Project) -> ProjectAsset {
+ let project_path = project.path();
+ let contents = Windows::new().to_string();
+
+ ProjectAsset::new(project_path.to_path_buf(), Windows::name(), contents)
+ }
+
+ pub fn catch_header(&self, project: &Project) -> HatchResult {
+ let test_src_path = project.path().join("test/src");
+ let file_name = CatchHeader::name();
+ if !test_src_path.join(file_name).exists() {
+ let res = (|| -> HatchResult {
+ let mut resp = reqwest::get(CATCH_HEADER_URL)?;
+ let content = resp.text()?;
+
+ Ok(ProjectAsset::new(test_src_path, CatchHeader::name(), content))
+ })().with_context(|e| {
+ format!("failed to generate catch.hpp : {}", e)
+ })?;
+
+ Ok(res)
+ } else {
+ Err(NullError)?
+ }
+ }
+
+ pub fn catch_definition(&self, project: &Project) -> ProjectAsset {
+ let test_src_path = project.path().join("test/src");
+ let contents = CatchDefinition::new().to_string();
+
+ ProjectAsset::new(test_src_path, CatchDefinition::name(), contents)
+ }
+}
diff --git a/hatch/src/assets/catch_definition.rs b/hatch/src/assets/catch_definition.rs
new file mode 100644
index 0000000..bcce0bb
--- /dev/null
+++ b/hatch/src/assets/catch_definition.rs
@@ -0,0 +1,17 @@
+pub struct CatchDefinition;
+
+impl CatchDefinition {
+ pub fn new() -> CatchDefinition {
+ CatchDefinition
+ }
+
+ pub fn name() -> String {
+ String::from("catch.cpp")
+ }
+}
+
+impl ToString for CatchDefinition {
+ fn to_string(&self) -> String {
+ String::from("#define CATCH_CONFIG_MAIN\n#include \"catch.hpp\"")
+ }
+}
diff --git a/hatch/src/assets/catch_header.rs b/hatch/src/assets/catch_header.rs
new file mode 100644
index 0000000..788dda1
--- /dev/null
+++ b/hatch/src/assets/catch_header.rs
@@ -0,0 +1,11 @@
+pub struct CatchHeader;
+
+impl CatchHeader {
+ pub fn new() -> CatchHeader {
+ CatchHeader
+ }
+
+ pub fn name() -> String {
+ String::from("catch.hpp")
+ }
+}
diff --git a/hatch/src/assets/config.rs b/hatch/src/assets/config.rs
new file mode 100644
index 0000000..ecad99c
--- /dev/null
+++ b/hatch/src/assets/config.rs
@@ -0,0 +1,36 @@
+use project::{ LibraryKind, ProjectKind };
+
+pub struct Config {
+ project: String,
+ lib_type: String,
+}
+
+impl Config {
+ pub fn new(name: &str, project_kind: &ProjectKind) -> Config {
+ Config { project: Config::project(name), lib_type: Config::lib_type(project_kind) }
+ }
+
+ pub fn name() -> String {
+ String::from("config.tup")
+ }
+
+ pub fn project(name: &str) -> String {
+ format!("PROJECT = {}", name)
+ }
+
+ pub fn lib_type(project_kind: &ProjectKind) -> String {
+ let kind = match *project_kind {
+ ProjectKind::Binary => "binary",
+ ProjectKind::Library(LibraryKind::Static) => "static",
+ ProjectKind::Library(LibraryKind::Shared) => "shared"
+ };
+
+ format!("LIB_TYPE = {}", kind)
+ }
+}
+
+impl ToString for Config {
+ fn to_string(&self) -> String {
+ [self.project.as_str(), self.lib_type.as_str()].join("\n")
+ }
+}
diff --git a/hatch/src/assets/generator.rs b/hatch/src/assets/generator.rs
new file mode 100644
index 0000000..97e274e
--- /dev/null
+++ b/hatch/src/assets/generator.rs
@@ -0,0 +1,33 @@
+use assets::{ Asset, ProjectAsset };
+use hatch_error::{ HatchResult, ResultExt };
+use std::fs;
+use std::io::Write;
+
+pub fn generate_one(asset: &ProjectAsset) -> HatchResult<()> {
+ let path = asset.path();
+ fs::create_dir_all(&path).with_context(|e| {
+ format!("Failed to create directory: `{}` : {}", path.display(), e)
+ })?;
+
+ let file_path = path.join(asset.name());
+ let mut file = fs::File::create(&file_path).with_context(|e| {
+ format!("Failed to create file: `{}` : {}", file_path.display(), e)
+ })?;
+
+ let contents = asset.contents();
+ file.write_all(contents.as_bytes()).with_context(|e| {
+ format!("Failed to write contents to file: `{}` : {}", file_path.display(), e)
+ })?;
+
+ Ok(())
+}
+
+pub fn generate_all(assets: &Vec) -> HatchResult<()> {
+ for asset in assets {
+ generate_one(asset).with_context(|e| {
+ format!("Failed to generate asset: `{}` : {}", asset.path().display(), e)
+ })?;
+ }
+
+ Ok(())
+}
diff --git a/hatch/src/assets/mod.rs b/hatch/src/assets/mod.rs
new file mode 100644
index 0000000..f4c0a51
--- /dev/null
+++ b/hatch/src/assets/mod.rs
@@ -0,0 +1,79 @@
+pub mod builder;
+pub mod generator;
+pub mod config;
+pub mod tupfile;
+pub mod platform;
+pub mod tuprules;
+pub mod test_tupfile;
+pub mod tupfile_ini;
+pub mod catch_header;
+pub mod catch_definition;
+
+#[cfg(test)]
+mod tests;
+
+use std::fmt;
+use std::cmp;
+use std::path::{ Path, PathBuf };
+
+pub trait Asset {
+ fn path(&self) -> &Path;
+ fn name(&self) -> &str;
+ fn contents(&self) -> &str;
+}
+
+pub fn print_file_path(asset: T) where T: Asset {
+ println!("{}", asset.path().display());
+}
+
+pub fn print_file_name(asset: T) where T: Asset {
+ println!("{}", asset.name());
+}
+
+pub fn print_file_contents(asset: T) where T: Asset {
+ println!("{}", asset.contents());
+}
+
+#[derive(Debug)]
+pub enum TupKind { Tuprules, Config, Tupfile, TestTupfile, TupfileIni }
+
+#[derive(Debug)]
+pub enum PlatformKind { Linux, MacOS, Windows }
+
+pub struct ProjectAsset {
+ path: PathBuf,
+ name: String,
+ contents: String,
+}
+
+impl ProjectAsset {
+ pub fn new(path: PathBuf, name: String, contents: String) -> ProjectAsset {
+ ProjectAsset { path, name, contents }
+ }
+}
+
+impl Asset for ProjectAsset {
+ fn path(&self) -> &Path {
+ self.path.as_path()
+ }
+
+ fn name(&self) -> &str {
+ &self.name.as_str()
+ }
+
+ fn contents(&self) -> &str {
+ &self.contents.as_str()
+ }
+}
+
+impl fmt::Debug for ProjectAsset {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "path: {}, name: {}, contents: {}", self.path.display(), self.name, self.contents)
+ }
+}
+
+impl cmp::PartialEq for ProjectAsset {
+ fn eq(&self, other: &ProjectAsset) -> bool {
+ self.name == other.name && self.contents == other.contents
+ }
+}
diff --git a/hatch/src/assets/platform.rs b/hatch/src/assets/platform.rs
new file mode 100644
index 0000000..f8ad853
--- /dev/null
+++ b/hatch/src/assets/platform.rs
@@ -0,0 +1,96 @@
+pub struct Linux {
+ static_extension: String,
+ shared_extension: String,
+}
+
+impl Linux {
+ pub fn new() -> Linux {
+ Linux { static_extension: Linux::static_extension(), shared_extension: Linux::shared_extension() }
+ }
+
+ pub fn name() -> String {
+ String::from("linux.tup")
+ }
+
+ pub fn static_extension() -> String {
+ String::from("STATIC = a")
+ }
+
+ pub fn shared_extension() -> String {
+ String::from("SHARED = so")
+ }
+}
+
+impl ToString for Linux {
+ fn to_string(&self) -> String {
+ [self.static_extension.as_str(), self.shared_extension.as_str()].join("\n")
+ }
+}
+
+pub struct MacOS {
+ static_extension: String,
+ shared_extension: String,
+}
+
+impl MacOS {
+ pub fn new() -> MacOS {
+ MacOS { static_extension: MacOS::static_extension(), shared_extension: MacOS::shared_extension() }
+ }
+
+ pub fn name() -> String {
+ String::from("macosx.tup")
+ }
+
+ pub fn static_extension() -> String {
+ String::from("STATIC = a")
+ }
+
+ pub fn shared_extension() -> String {
+ String::from("SHARED = so")
+ }
+}
+
+impl ToString for MacOS {
+ fn to_string(&self) -> String {
+ [self.static_extension.as_str(), self.shared_extension.as_str()].join("\n")
+ }
+}
+
+pub struct Windows {
+ static_extension: String,
+ shared_extension: String,
+}
+
+impl Windows {
+ pub fn new() -> Windows {
+ Windows { static_extension: Windows::static_extension(), shared_extension: Windows::shared_extension() }
+ }
+
+ pub fn name() -> String {
+ String::from("win32.tup")
+ }
+
+ pub fn static_extension() -> String {
+ String::from("STATIC = lib")
+ }
+
+ pub fn shared_extension() -> String {
+ String::from("SHARED = dll")
+ }
+}
+
+impl ToString for Windows {
+ fn to_string(&self) -> String {
+ let clang_comment = "# Use clang for front-end";
+ let clang = "CC = clang++.exe";
+ let llvm_comment = "# Use llvm-lib for static libraries";
+ let archive_macro = "!archive = |> llvm-lib /MACHINE:X64 /OUT:%o %f |>";
+
+ [self.static_extension.as_str(),
+ self.shared_extension.as_str(),
+ clang_comment,
+ clang,
+ llvm_comment,
+ archive_macro].join("\n")
+ }
+}
diff --git a/hatch/src/assets/test_tupfile.rs b/hatch/src/assets/test_tupfile.rs
new file mode 100644
index 0000000..bb744b4
--- /dev/null
+++ b/hatch/src/assets/test_tupfile.rs
@@ -0,0 +1,17 @@
+pub struct Tupfile;
+
+impl Tupfile {
+ pub fn new() -> Tupfile {
+ Tupfile
+ }
+
+ pub fn name() -> String {
+ String::from("Tupfile")
+ }
+}
+
+impl ToString for Tupfile {
+ fn to_string(&self) -> String {
+ String::from(".gitignore")
+ }
+}
diff --git a/hatch/src/assets/tests/builder.rs b/hatch/src/assets/tests/builder.rs
new file mode 100644
index 0000000..ece6f88
--- /dev/null
+++ b/hatch/src/assets/tests/builder.rs
@@ -0,0 +1,187 @@
+use assets::builder::Builder as AssetBuilder;
+use assets::{ Asset, ProjectAsset };
+use std::path::PathBuf;
+use assets::tests::fixtures;
+use project::{ ProjectKind, LibraryKind };
+
+#[test]
+fn add_asset() {
+ let mut asset_builder = AssetBuilder::new();
+ let asset = ProjectAsset::new(PathBuf::from("./"), String::from("test"), String::from("test"));
+ asset_builder.add_asset(asset);
+
+ let assets = asset_builder.assets();
+
+ assert_eq!(assets.len(), 1);
+
+ assert_eq!(assets[0].name(), "test");
+}
+
+#[test]
+fn build_config_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.config(&project);
+
+ let expected_contents = String::from("PROJECT = test\nLIB_TYPE = static");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("config.tup"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_test_tupfile_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.test_tupfile(&project);
+
+ let expected_contents = String::from(".gitignore");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./test/"), String::from("Tupfile"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_tuprules_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.tuprules(&project);
+
+ let expected_contents = String::from(
+".gitignore
+CC = g++
+ARCH = -m64
+CFLAGS += $(ARCH)
+CFLAGS += -c --std=c++1z
+LINKFLAGS += $(ARCH)
+LINKFLAGS += -v
+ifneq (@(TUP_PLATFORM),macosx)
+ LINKFLAGS += -static
+endif
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup
+ifeq ($(LIB_TYPE),static)
+ EXTENSION = $(STATIC)
+else
+ ifeq ($(LIB_TYPE),shared)
+ EXTENSION = $(SHARED)
+ endif
+endif
+PROJECT_LIB = $(PROJECT).$(EXTENSION)");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("Tuprules.tup"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_tupfile_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Shared));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.tupfile(&project);
+
+ let expected_contents = String::from(
+"include config.tup
+include_rules
+
+: foreach $(SOURCE_FILES) |> !compile |> $(SOURCE_TARGET)/%B.o
+
+: $(SOURCE_OBJ_FILES) |> !archive |> $(SOURCE_TARGET)/$(PROJECT_LIB) <$(PROJECT)>
+
+: foreach $(TEST_FILES) |> !compile |> $(TEST_TARGET)/%B.o
+
+: $(TEST_OBJ_FILES) $(SOURCE_TARGET)/$(PROJECT_LIB) |> !link |> $(TEST_TARGET)/$(PROJECT).test");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("Tupfile"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_tupfile_ini_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.tupfile_ini(&project);
+
+ let expected_contents = String::from("");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("Tupfile.ini"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_linux_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.linux(&project);
+
+ let expected_contents = String::from("STATIC = a\nSHARED = so");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("linux.tup"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_macos_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.macos(&project);
+
+ let expected_contents = String::from("STATIC = a\nSHARED = so");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("macosx.tup"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_windows_asset() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.windows(&project);
+
+ let expected_contents = String::from(
+"STATIC = lib
+SHARED = dll
+# Use clang for front-end
+CC = clang++.exe
+# Use llvm-lib for static libraries
+!archive = |> llvm-lib /MACHINE:X64 /OUT:%o %f |>");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("win32.tup"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
+
+#[test]
+fn build_catch_definition() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let asset_builder = AssetBuilder::new();
+ let actual_asset = asset_builder.catch_definition(&project);
+
+ let expected_contents = String::from("#define CATCH_CONFIG_MAIN\n#include \"catch.hpp\"");
+ let expected_asset = ProjectAsset::new(PathBuf::from("./"), String::from("catch.cpp"), expected_contents);
+
+ assert_eq!(actual_asset, expected_asset);
+}
diff --git a/hatch/src/assets/tests/catch_definition.rs b/hatch/src/assets/tests/catch_definition.rs
new file mode 100644
index 0000000..58afede
--- /dev/null
+++ b/hatch/src/assets/tests/catch_definition.rs
@@ -0,0 +1,6 @@
+use assets::catch_definition::CatchDefinition;
+
+#[test]
+fn build_catch_definition() {
+ assert_eq!("#define CATCH_CONFIG_MAIN\n#include \"catch.hpp\"", CatchDefinition::new().to_string());
+}
\ No newline at end of file
diff --git a/hatch/src/assets/tests/catch_header.rs b/hatch/src/assets/tests/catch_header.rs
new file mode 100644
index 0000000..413e42c
--- /dev/null
+++ b/hatch/src/assets/tests/catch_header.rs
@@ -0,0 +1,6 @@
+use assets::catch_header::CatchHeader;
+
+#[test]
+fn build_catch_header() {
+ assert_eq!("catch.hpp", CatchHeader::name());
+}
diff --git a/hatch/src/assets/tests/config.rs b/hatch/src/assets/tests/config.rs
new file mode 100644
index 0000000..b25cecd
--- /dev/null
+++ b/hatch/src/assets/tests/config.rs
@@ -0,0 +1,23 @@
+use assets::config::Config;
+use project::{ LibraryKind, ProjectKind };
+
+#[test]
+fn build_shared_config() {
+ let config = Config::new("Test", &ProjectKind::Library(LibraryKind::Shared));
+
+ assert_eq!("PROJECT = Test\nLIB_TYPE = shared", config.to_string());
+}
+
+#[test]
+fn build_static_config() {
+ let config = Config::new("Test", &ProjectKind::Library(LibraryKind::Static));
+
+ assert_eq!("PROJECT = Test\nLIB_TYPE = static", config.to_string());
+}
+
+#[test]
+fn build_binary_config() {
+ let config = Config::new("Test", &ProjectKind::Binary);
+
+ assert_eq!("PROJECT = Test\nLIB_TYPE = binary", config.to_string());
+}
diff --git a/hatch/src/assets/tests/fixtures.rs b/hatch/src/assets/tests/fixtures.rs
new file mode 100644
index 0000000..47313e8
--- /dev/null
+++ b/hatch/src/assets/tests/fixtures.rs
@@ -0,0 +1,21 @@
+use project::{ Project, ProjectKind };
+use project::build::{ Config, Target };
+use platform::arch::Arch;
+use std::path::PathBuf;
+
+pub fn project(kind: ProjectKind) -> Project {
+ let config = Config::new(kind,
+ String::from("g++"),
+ vec![String::from("-c"), String::from("--std=c++1z")],
+ vec![String::from("-v")],
+ Arch::X64,
+ Target::Release);
+
+ let project = Project::new(String::from("test"),
+ String::from("0.1.0"),
+ config,
+ Vec::new(),
+ PathBuf::from("./"));
+
+ project
+}
diff --git a/hatch/src/assets/tests/generator.rs b/hatch/src/assets/tests/generator.rs
new file mode 100644
index 0000000..1800d42
--- /dev/null
+++ b/hatch/src/assets/tests/generator.rs
@@ -0,0 +1,165 @@
+use assets::generator::*;
+use assets::ProjectAsset;
+use std::fs;
+use std::io::prelude::*;
+use std::path::PathBuf;
+
+#[test]
+fn generate_one_without_directories() {
+ let test_asset = ProjectAsset::new(PathBuf::from("./"), String::from("test.test"), String::from("test"));
+
+ if let Err(e) = generate_one(&test_asset) {
+ panic!(e);
+ }
+
+ match fs::File::open("./test.test") {
+ Ok(mut file) => {
+ let mut contents = String::new();
+ let result = file.read_to_string(&mut contents);
+ fs::remove_file("./test.test");
+
+ if let Err(e) = result {
+ panic!(e)
+ }
+
+ assert_eq!(contents, "test");
+ },
+ Err(e) => {
+ fs::remove_file("./test.test");
+ panic!(e)
+ }
+ }
+}
+
+#[test]
+fn generate_one_with_directories() {
+ let test_asset = ProjectAsset::new(PathBuf::from("./foo/"), String::from("test.test"), String::from("test"));
+
+ if let Err(e) = generate_one(&test_asset) {
+ panic!(e);
+ }
+
+ match fs::File::open("./foo/test.test") {
+ Ok(mut file) => {
+ let mut contents = String::new();
+ let result = file.read_to_string(&mut contents);
+ fs::remove_file("./foo/test.test");
+ fs::remove_dir("./foo/");
+
+ if let Err(e) = result {
+ panic!(e)
+ }
+ },
+ Err(e) => {
+ fs::remove_file("./foo/test.test");
+ fs::remove_dir("./foo/");
+ panic!(e)
+ }
+ }
+}
+
+#[test]
+fn generate_one_overwrites_file() {
+ let test_asset = ProjectAsset::new(PathBuf::from("./"), String::from("test2.test"), String::from("old"));
+
+ if let Err(e) = generate_one(&test_asset) {
+ panic!(e);
+ }
+
+ // verify that the old content is there
+ match fs::File::open("./test2.test") {
+ Ok(mut file) => {
+ let mut contents = String::new();
+ let result = file.read_to_string(&mut contents);
+ fs::remove_file("./test2.test");
+
+ if let Err(e) = result {
+ panic!(e)
+ }
+
+ assert_eq!(contents, "old");
+ },
+ Err(e) => {
+ fs::remove_file("./test2.test");
+ panic!(e)
+ }
+ }
+
+ let test_asset = ProjectAsset::new(PathBuf::from("./"), String::from("test2.test"), String::from("new"));
+
+ if let Err(e) = generate_one(&test_asset) {
+ fs::remove_file("./test2.test");
+ panic!(e);
+ }
+
+ // verify that the new content overwrites the old content
+ match fs::File::open("./test2.test") {
+ Ok(mut file) => {
+ let mut contents = String::new();
+ let result = file.read_to_string(&mut contents);
+ fs::remove_file("./test2.test");
+
+ if let Err(e) = result {
+ panic!(e)
+ }
+
+ assert_eq!(contents, "new");
+ },
+ Err(e) => {
+ fs::remove_file("./test2.test");
+ panic!(e)
+ }
+ }
+}
+
+#[test]
+fn generate_all_assets() {
+ let test_asset_one = ProjectAsset::new(PathBuf::from("./"), String::from("one.test"), String::from("one"));
+ let test_asset_two = ProjectAsset::new(PathBuf::from("./"), String::from("two.test"), String::from("two"));
+
+ let test_assets = vec![test_asset_one, test_asset_two];
+
+ if let Err(e) = generate_all(&test_assets) {
+ fs::remove_file("./one.test");
+ fs::remove_file("./two.test");
+ panic!(e);
+ }
+
+ match fs::File::open("./one.test") {
+ Ok(mut file) => {
+ let mut contents = String::new();
+ let result = file.read_to_string(&mut contents);
+ fs::remove_file("./one.test");
+
+ if let Err(e) = result {
+ fs::remove_file("./two.test");
+ panic!(e)
+ }
+
+ assert_eq!(contents, "one");
+ },
+ Err(e) => {
+ fs::remove_file("./one.test");
+ fs::remove_file("./two.test");
+ panic!(e)
+ }
+ }
+
+ match fs::File::open("./two.test") {
+ Ok(mut file) => {
+ let mut contents = String::new();
+ let result = file.read_to_string(&mut contents);
+ fs::remove_file("./two.test");
+
+ if let Err(e) = result {
+ panic!(e)
+ }
+
+ assert_eq!(contents, "two");
+ },
+ Err(e) => {
+ fs::remove_file("./two.test");
+ panic!(e)
+ }
+ }
+}
diff --git a/hatch/src/assets/tests/mod.rs b/hatch/src/assets/tests/mod.rs
new file mode 100644
index 0000000..8234966
--- /dev/null
+++ b/hatch/src/assets/tests/mod.rs
@@ -0,0 +1,21 @@
+mod builder;
+mod generator;
+mod config;
+mod platform;
+mod test_tupfile;
+mod tupfile;
+mod tuprules;
+mod catch_header;
+mod catch_definition;
+mod fixtures;
+
+use assets::ProjectAsset;
+use std::path::PathBuf;
+
+#[test]
+fn fmt_project_asset() {
+ let asset = ProjectAsset::new(PathBuf::from("./"), String::from("test"), String::from("test"));
+
+ let result = format!("{:?}", asset);
+ assert_eq!(result, "path: ./, name: test, contents: test");
+}
\ No newline at end of file
diff --git a/hatch/src/assets/tests/platform.rs b/hatch/src/assets/tests/platform.rs
new file mode 100644
index 0000000..21b580f
--- /dev/null
+++ b/hatch/src/assets/tests/platform.rs
@@ -0,0 +1,23 @@
+use assets::platform::{ Linux, MacOS, Windows };
+
+#[test]
+fn build_linux() {
+ assert_eq!("STATIC = a\nSHARED = so", Linux::new().to_string());
+}
+
+#[test]
+fn build_macos() {
+ assert_eq!("STATIC = a\nSHARED = so", MacOS::new().to_string());
+}
+
+#[test]
+fn build_windows() {
+ let windows_content = String::from(
+"STATIC = lib
+SHARED = dll
+# Use clang for front-end
+CC = clang++.exe
+# Use llvm-lib for static libraries
+!archive = |> llvm-lib /MACHINE:X64 /OUT:%o %f |>");
+ assert_eq!(windows_content, Windows::new().to_string());
+}
diff --git a/hatch/src/assets/tests/test_tupfile.rs b/hatch/src/assets/tests/test_tupfile.rs
new file mode 100644
index 0000000..334cc9b
--- /dev/null
+++ b/hatch/src/assets/tests/test_tupfile.rs
@@ -0,0 +1,6 @@
+use assets::test_tupfile::Tupfile;
+
+#[test]
+fn build_test_tupfile() {
+ assert_eq!(".gitignore", Tupfile::new().to_string());
+}
diff --git a/hatch/src/assets/tests/tupfile.rs b/hatch/src/assets/tests/tupfile.rs
new file mode 100644
index 0000000..0cf8b69
--- /dev/null
+++ b/hatch/src/assets/tests/tupfile.rs
@@ -0,0 +1,41 @@
+use assets::tupfile::Tupfile;
+use assets::tests::fixtures;
+use project::{ ProjectKind, LibraryKind };
+
+#[test]
+fn build_library_tupfile() {
+ let project = fixtures::project(ProjectKind::Library(LibraryKind::Static));
+
+ let contents = String::from(
+"include config.tup
+include_rules
+
+: foreach $(SOURCE_FILES) |> !compile |> $(SOURCE_TARGET)/%B.o
+
+: $(SOURCE_OBJ_FILES) |> !archive |> $(SOURCE_TARGET)/$(PROJECT_LIB) <$(PROJECT)>
+
+: foreach $(TEST_FILES) |> !compile |> $(TEST_TARGET)/%B.o
+
+: $(TEST_OBJ_FILES) $(SOURCE_TARGET)/$(PROJECT_LIB) |> !link |> $(TEST_TARGET)/$(PROJECT).test");
+
+ assert_eq!(contents, Tupfile::new(project.config().kind()).to_string());
+}
+
+#[test]
+fn build_binary_tupfile() {
+ let project = fixtures::project(ProjectKind::Binary);
+
+ let contents = String::from(
+"include config.tup
+include_rules
+
+: foreach $(SOURCE_FILES) |> !compile |> $(SOURCE_TARGET)/%B.o
+
+: $(SOURCE_OBJ_FILES) |> !link |> $(SOURCE_TARGET)/$(PROJECT)
+
+: foreach $(TEST_FILES) |> !compile |> $(TEST_TARGET)/%B.o
+
+: $(TEST_OBJ_FILES) |> !link |> $(TEST_TARGET)/$(PROJECT).test");
+
+ assert_eq!(contents, Tupfile::new(project.config().kind()).to_string());
+}
\ No newline at end of file
diff --git a/hatch/src/assets/tests/tuprules.rs b/hatch/src/assets/tests/tuprules.rs
new file mode 100644
index 0000000..176a8cd
--- /dev/null
+++ b/hatch/src/assets/tests/tuprules.rs
@@ -0,0 +1,388 @@
+use assets::tuprules::Tuprules;
+use project::{ ProjectKind, LibraryKind };
+use project::build::{ Target, Config };
+use platform::arch::Arch;
+
+/**
+ * These tests were created using All-Pairs testing.
+ *
+ * Note that I am not including the Compiler field as it is required and we are simply doing a
+ * string replace as opposed to an enumeration.
+ *
+ * the tests are following this table:
+ * (Kind, Arch, Target, Compiler Flags, Linker Flags)
+ * (Static, X64, Release, Present, Present)
+ * (Static, X86, Debug, None, None)
+ * (Shared, X64, Debug, None, None)
+ * (Shared, X86, Release, Present, Present)
+ * (Binary, X64, Release, None, None)
+ * (Binary, X86, Debug, Present, Present)
+ * (Binary, X64, Release, Present, None)
+ * (Binary, X86, Debug, None, Present)
+ */
+
+#[test]
+fn build_static_x64_release_with_flags_tuprules() {
+ let contents = String::from(
+".gitignore
+CC = g++
+ARCH = -m64
+CFLAGS += $(ARCH)
+CFLAGS += -c --std=c++1z
+LINKFLAGS += $(ARCH)
+LINKFLAGS += -v
+ifneq (@(TUP_PLATFORM),macosx)
+ LINKFLAGS += -static
+endif
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup
+ifeq ($(LIB_TYPE),static)
+ EXTENSION = $(STATIC)
+else
+ ifeq ($(LIB_TYPE),shared)
+ EXTENSION = $(SHARED)
+ endif
+endif
+PROJECT_LIB = $(PROJECT).$(EXTENSION)");
+
+ let config = Config::new(ProjectKind::Library(LibraryKind::Static),
+ String::from("g++"),
+ vec![String::from("-c"), String::from("--std=c++1z")],
+ vec![String::from("-v")],
+ Arch::X64,
+ Target::Release);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
+
+#[test]
+fn build_static_x86_debug_without_flags_tuprules() {
+ let contents = String::from(
+".gitignore
+CC = g++
+CFLAGS += -g
+ARCH = -m32
+CFLAGS += $(ARCH)
+LINKFLAGS += $(ARCH)
+ifneq (@(TUP_PLATFORM),macosx)
+ LINKFLAGS += -static
+endif
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup
+ifeq ($(LIB_TYPE),static)
+ EXTENSION = $(STATIC)
+else
+ ifeq ($(LIB_TYPE),shared)
+ EXTENSION = $(SHARED)
+ endif
+endif
+PROJECT_LIB = $(PROJECT).$(EXTENSION)");
+ let config = Config::new(ProjectKind::Library(LibraryKind::Static),
+ String::from("g++"),
+ Vec::new(),
+ Vec::new(),
+ Arch::X86,
+ Target::Debug);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
+
+#[test]
+fn build_shared_x64_debug_without_flags_tuprules() {
+ let contents = String::from(
+".gitignore
+CC = g++
+CFLAGS += -g
+ARCH = -m64
+CFLAGS += $(ARCH)
+LINKFLAGS += $(ARCH)
+ifneq (@(TUP_PLATFORM),macosx)
+ LINKFLAGS += -dynamic
+endif
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup
+ifeq ($(LIB_TYPE),static)
+ EXTENSION = $(STATIC)
+else
+ ifeq ($(LIB_TYPE),shared)
+ EXTENSION = $(SHARED)
+ endif
+endif
+PROJECT_LIB = $(PROJECT).$(EXTENSION)");
+
+ let config = Config::new(ProjectKind::Library(LibraryKind::Shared),
+ String::from("g++"),
+ Vec::new(),
+ Vec::new(),
+ Arch::X64,
+ Target::Debug);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
+
+#[test]
+fn build_shared_x86_release_with_flags_tuprules() {
+ let contents = String::from(
+".gitignore
+CC = g++
+ARCH = -m32
+CFLAGS += $(ARCH)
+CFLAGS += -c --std=c++1z
+LINKFLAGS += $(ARCH)
+LINKFLAGS += -v
+ifneq (@(TUP_PLATFORM),macosx)
+ LINKFLAGS += -dynamic
+endif
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup
+ifeq ($(LIB_TYPE),static)
+ EXTENSION = $(STATIC)
+else
+ ifeq ($(LIB_TYPE),shared)
+ EXTENSION = $(SHARED)
+ endif
+endif
+PROJECT_LIB = $(PROJECT).$(EXTENSION)");
+
+ let config = Config::new(ProjectKind::Library(LibraryKind::Shared),
+ String::from("g++"),
+ vec![String::from("-c"), String::from("--std=c++1z")],
+ vec![String::from("-v")],
+ Arch::X86,
+ Target::Release);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
+
+#[test]
+fn build_binary_x64_release_without_flags_tuprules() {
+ let contents = String::from(
+".gitignore
+CC = g++
+ARCH = -m64
+CFLAGS += $(ARCH)
+LINKFLAGS += $(ARCH)
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup");
+
+ let config = Config::new(ProjectKind::Binary,
+ String::from("g++"),
+ Vec::new(),
+ Vec::new(),
+ Arch::X64,
+ Target::Release);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
+
+#[test]
+fn build_binary_x86_debug_with_flags_tuprules() {
+ let contents = String::from(
+".gitignore
+CC = g++
+CFLAGS += -g
+ARCH = -m32
+CFLAGS += $(ARCH)
+CFLAGS += -c --std=c++1z
+LINKFLAGS += $(ARCH)
+LINKFLAGS += -v
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup");
+
+ let config = Config::new(ProjectKind::Binary, String::from("g++"),
+ vec![String::from("-c"), String::from("--std=c++1z")],
+ vec![String::from("-v")],
+ Arch::X86,
+ Target::Debug);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
+
+#[test]
+fn build_binary_x64_release_with_cflags_without_lflags_tuprules() {
+ let contents = String::from(
+ ".gitignore
+CC = g++
+ARCH = -m64
+CFLAGS += $(ARCH)
+CFLAGS += -c --std=c++1z
+LINKFLAGS += $(ARCH)
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup");
+
+ let config = Config::new(ProjectKind::Binary,
+ String::from("g++"),
+ vec![String::from("-c"), String::from("--std=c++1z")],
+ Vec::new(),
+ Arch::X64,
+ Target::Release);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
+
+#[test]
+fn build_binary_x86_debug_without_cflags_with_lflags_tuprules() {
+ let contents = String::from(
+ ".gitignore
+CC = g++
+CFLAGS += -g
+ARCH = -m32
+CFLAGS += $(ARCH)
+LINKFLAGS += $(ARCH)
+LINKFLAGS += -v
+SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup");
+
+ let config = Config::new(ProjectKind::Binary,
+ String::from("g++"),
+ Vec::new(),
+ vec![String::from("-v")],
+ Arch::X86,
+ Target::Debug);
+
+ let tuprules = Tuprules::new(&config);
+
+ assert_eq!(contents, tuprules.to_string());
+}
diff --git a/hatch/src/assets/tupfile.rs b/hatch/src/assets/tupfile.rs
new file mode 100644
index 0000000..83123b8
--- /dev/null
+++ b/hatch/src/assets/tupfile.rs
@@ -0,0 +1,56 @@
+use project::{ ProjectKind, LibraryKind };
+
+pub struct Tupfile {
+ kind: ProjectKind
+}
+
+impl Tupfile {
+ pub fn new(kind: &ProjectKind) -> Tupfile {
+ let copy_kind = match *kind {
+ ProjectKind::Binary => ProjectKind::Binary,
+ ProjectKind::Library(LibraryKind::Static) => ProjectKind::Library(LibraryKind::Static),
+ ProjectKind::Library(LibraryKind::Shared) => ProjectKind::Library(LibraryKind::Shared)
+ };
+
+ Tupfile { kind: copy_kind }
+ }
+
+ pub fn name() -> String {
+ String::from("Tupfile")
+ }
+}
+
+impl ToString for Tupfile {
+ fn to_string(&self) -> String {
+ let mut tokens = Vec::new();
+
+ let includes = String::from("include config.tup\ninclude_rules\n");
+ let compile_source = String::from(": foreach $(SOURCE_FILES) |> !compile |> $(SOURCE_TARGET)/%B.o\n");
+ let compile_tests = String::from(": foreach $(TEST_FILES) |> !compile |> $(TEST_TARGET)/%B.o\n");
+
+ tokens.push(includes);
+ tokens.push(compile_source);
+
+ match self.kind {
+ ProjectKind::Binary => {
+ tokens.push(String::from(": $(SOURCE_OBJ_FILES) |> !link |> $(SOURCE_TARGET)/$(PROJECT)\n"));
+ },
+ ProjectKind::Library(_) => {
+ tokens.push(String::from(": $(SOURCE_OBJ_FILES) |> !archive |> $(SOURCE_TARGET)/$(PROJECT_LIB) <$(PROJECT)>\n"));
+ }
+ }
+
+ tokens.push(compile_tests);
+
+ match self.kind {
+ ProjectKind::Binary => {
+ tokens.push(String::from(": $(TEST_OBJ_FILES) |> !link |> $(TEST_TARGET)/$(PROJECT).test"));
+ },
+ ProjectKind::Library(_) => {
+ tokens.push(String::from(": $(TEST_OBJ_FILES) $(SOURCE_TARGET)/$(PROJECT_LIB) |> !link |> $(TEST_TARGET)/$(PROJECT).test"));
+ }
+ }
+
+ tokens.iter().map(|token| token.as_str()).collect::>().join("\n")
+ }
+}
diff --git a/hatch/src/assets/tupfile_ini.rs b/hatch/src/assets/tupfile_ini.rs
new file mode 100644
index 0000000..ec4e8e3
--- /dev/null
+++ b/hatch/src/assets/tupfile_ini.rs
@@ -0,0 +1,17 @@
+pub struct TupfileIni;
+
+impl TupfileIni {
+ pub fn new() -> TupfileIni {
+ TupfileIni
+ }
+
+ pub fn name() -> String {
+ String::from("Tupfile.ini")
+ }
+}
+
+impl ToString for TupfileIni {
+ fn to_string(&self) -> String {
+ String::from("")
+ }
+}
diff --git a/hatch/src/assets/tuprules.rs b/hatch/src/assets/tuprules.rs
new file mode 100644
index 0000000..396ab3d
--- /dev/null
+++ b/hatch/src/assets/tuprules.rs
@@ -0,0 +1,146 @@
+use project::{ ProjectKind, LibraryKind };
+use project::build::{ Config, Target };
+use platform::arch::Arch;
+
+pub struct Tuprules {
+ kind: ProjectKind,
+ compiler: String,
+ compiler_flags: String,
+ linker_flags: String,
+ arch: Arch,
+ target: Target
+}
+
+impl Tuprules {
+ pub fn new(config: &Config) -> Tuprules {
+ let copy_kind = match *config.kind() {
+ ProjectKind::Binary => ProjectKind::Binary,
+ ProjectKind::Library(LibraryKind::Static) => ProjectKind::Library(LibraryKind::Static),
+ ProjectKind::Library(LibraryKind::Shared) => ProjectKind::Library(LibraryKind::Shared)
+ };
+
+ let copy_arch = match *config.arch() {
+ Arch::X64 => Arch::X64,
+ Arch::X86 => Arch::X86
+ };
+
+ let copy_target = match *config.target() {
+ Target::Debug => Target::Debug,
+ Target::Release => Target::Release
+ };
+
+ Tuprules {
+ kind: copy_kind,
+ compiler: String::from(config.compiler()),
+ compiler_flags: config.compiler_flags().join(" "),
+ linker_flags: config.linker_flags().join(" "),
+ arch: copy_arch,
+ target: copy_target
+ }
+ }
+
+ pub fn name() -> String {
+ String::from("Tuprules.tup")
+ }
+
+ fn arch_flag(arch: &Arch) -> String {
+ match *arch {
+ Arch::X64 => String::from("-m64"),
+ Arch::X86 => String::from("-m32"),
+ }
+ }
+
+ fn type_flag(lib_type: &LibraryKind) -> String {
+ match *lib_type {
+ LibraryKind::Static => String::from("-static"),
+ LibraryKind::Shared => String::from("-dynamic"),
+ }
+ }
+}
+
+impl ToString for Tuprules {
+ fn to_string(&self) -> String {
+ let mut tokens = Vec::new();
+ tokens.push(String::from(".gitignore"));
+
+ let compiler_token = format!("CC = {}", self.compiler);
+ tokens.push(compiler_token);
+
+ match self.target {
+ Target::Debug => {
+ let debug_token = String::from("CFLAGS += -g");
+ tokens.push(debug_token);
+ },
+ _ => {}
+ }
+
+ let arch_flag = Tuprules::arch_flag(&self.arch);
+ let arch_token = format!("ARCH = {}", arch_flag);
+ tokens.push(arch_token);
+
+ tokens.push(String::from("CFLAGS += $(ARCH)"));
+
+ if !self.compiler_flags.is_empty() {
+ let compiler_flags = format!("CFLAGS += {}", self.compiler_flags);
+ tokens.push(compiler_flags);
+ }
+
+ tokens.push(String::from("LINKFLAGS += $(ARCH)"));
+
+ if !self.linker_flags.is_empty() {
+ let linker_flags = format!("LINKFLAGS += {}", self.linker_flags);
+ tokens.push(linker_flags);
+ }
+
+ match self.kind {
+ ProjectKind::Library(ref lib_kind) => {
+ let link_flags_type = format!(
+"ifneq (@(TUP_PLATFORM),macosx)
+ LINKFLAGS += {}
+endif", Tuprules::type_flag(lib_kind));
+
+ tokens.push(link_flags_type);
+ },
+ ProjectKind::Binary => {
+
+ }
+ }
+
+ tokens.push(String::from(
+"SOURCE = src
+TARGET = target
+SOURCE_TARGET = $(TARGET)
+SOURCE_FILES = $(SOURCE)/*.cpp
+SOURCE_OBJ_FILES = $(SOURCE_TARGET)/*.o
+
+TEST = test
+TEST_TARGET = $(TEST)/$(TARGET)
+TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
+TEST_OBJ_FILES = $(TEST_TARGET)/*.o
+
+# macros
+!compile = |> $(CC) $(CFLAGS) %f -o %o |>
+!archive = |> ar crs %o %f |>
+!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
+
+# includes the STATIC and SHARED variables for the target platform
+include @(TUP_PLATFORM).tup"));
+
+ match self.kind {
+ ProjectKind::Library(ref _lib_kind) => {
+ tokens.push(String::from(
+"ifeq ($(LIB_TYPE),static)
+ EXTENSION = $(STATIC)
+else
+ ifeq ($(LIB_TYPE),shared)
+ EXTENSION = $(SHARED)
+ endif
+endif
+PROJECT_LIB = $(PROJECT).$(EXTENSION)"));
+ },
+ _ => {}
+ }
+
+ tokens.iter().map(|token| token.as_str()).collect::>().join("\n")
+ }
+}
diff --git a/hatch/src/bin/hatch.rs b/hatch/src/bin/hatch.rs
index 6331855..8ab8fae 100644
--- a/hatch/src/bin/hatch.rs
+++ b/hatch/src/bin/hatch.rs
@@ -1,8 +1,42 @@
extern crate hatch;
-use hatch::manifest::Manifest;
-use hatch::project::Project;
+use std::collections::HashMap;
+
+use hatch::cli::Cli;
+use hatch::cli::commands::Command;
+use hatch::cli::commands::new::New;
+use hatch::cli::commands::update::Update;
+use hatch::cli::commands::build::Build;
+use hatch::cli::commands::test::Test;
+use hatch::cli::commands::run::Run;
fn main() {
- let manifest = Manifest::new();
+ // create the subcommand to command map
+ let mut subcommands: HashMap<&'static str, Box> = HashMap::new();
+
+ let new_command = Box::new(New::new());
+ subcommands.insert(new_command.subcommand_name(), new_command);
+
+ let update_command = Box::new(Update::new());
+ subcommands.insert(update_command.subcommand_name(), update_command);
+
+ let build_command = Box::new(Build::new());
+ subcommands.insert(build_command.subcommand_name(), build_command);
+
+ let test_command = Box::new(Test::new());
+ subcommands.insert(test_command.subcommand_name(), test_command);
+
+ let run_command = Box::new(Run::new());
+ subcommands.insert(run_command.subcommand_name(), run_command);
+
+ // initialize cli with the set of subcommand
+ let cli = Cli::new(subcommands.values().map(|v| v.cli_subcommand()).collect::>());
+
+ // execute selected subcommand
+ let (name, args) = cli.subcommand();
+ if let Some(cmd) = subcommands.get(name) {
+ if let Err(e) = cmd.execute(args.unwrap()) {
+ println!("{}", e);
+ }
+ }
}
diff --git a/hatch/src/cli.rs b/hatch/src/cli.rs
deleted file mode 100644
index 7bfe01c..0000000
--- a/hatch/src/cli.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use dtl::cli as cli_imp;
-use project::{ ProjectKind };
-
-pub struct Cli<'cli>(cli_imp::Cli<'cli>);
-
-impl<'cli>Cli<'cli> {
- pub fn new() -> Cli<'cli> {
- Cli(cli_imp::Cli::new())
- }
-
- pub fn kind(&self) -> ProjectKind {
- self.0.build_type()
- }
-
- pub fn name(&self) -> String {
- self.0.name()
- }
-
- pub fn path(&self) -> String {
- self.0.path()
- }
-}
diff --git a/hatch/src/cli/commands/build.rs b/hatch/src/cli/commands/build.rs
new file mode 100644
index 0000000..059a655
--- /dev/null
+++ b/hatch/src/cli/commands/build.rs
@@ -0,0 +1,76 @@
+use hatch_error::{ HatchResult, ResultExt, InvalidPathError };
+use clap::{ App, SubCommand, ArgMatches };
+use cli::commands::Command;
+use platform::os;
+use project::Project;
+use assets::PlatformKind;
+use task;
+use std::process;
+
+pub struct Build {
+ name: &'static str
+}
+
+impl<'build> Build {
+ pub fn new() -> Build {
+ Build {
+ name: "build"
+ }
+ }
+
+ pub fn execute(&self, project: &Project) -> HatchResult<()> {
+ if let Some(path) = project.path().to_str() {
+ let command = format!("cd {} && tup", path);
+ let mut shell: String;
+ let mut args: Vec;
+ match os::platform_type() {
+ PlatformKind::Windows => {
+ shell = String::from("cmd");
+ args = vec![String::from("/C"), command];
+ },
+ _ => {
+ shell = String::from("sh");
+ args = vec![String::from("-c"), command];
+ }
+ }
+
+ let mut child = process::Command::new(shell).args(args).spawn()?;
+ child.wait()?;
+
+ Ok(())
+ } else {
+ Err(InvalidPathError)?
+ }
+ }
+}
+
+impl<'command> Command<'command> for Build {
+ fn cli_subcommand(&self) -> App<'command, 'command> {
+ SubCommand::with_name(&self.name)
+ .about("Builds a project.")
+ .author("Josh Gould ")
+ }
+
+ fn subcommand_name(&self) -> &'static str {
+ self.name
+ }
+
+ fn execute(&self, args: &ArgMatches<'command>) -> HatchResult<()> {
+ let res = (|| -> HatchResult<()> {
+ let project_path = self.project_path(args);
+ let project = task::read_project(&project_path)?;
+
+ println!("Generating assets...\n");
+
+ task::generate_assets(&project)?;
+
+ println!("Building project...\n");
+
+ self.execute(&project)
+ })().with_context(|e| {
+ format!("Failed to build project : {}", e)
+ })?;
+
+ Ok(res)
+ }
+}
diff --git a/hatch/src/cli/commands/mod.rs b/hatch/src/cli/commands/mod.rs
new file mode 100644
index 0000000..5795044
--- /dev/null
+++ b/hatch/src/cli/commands/mod.rs
@@ -0,0 +1,48 @@
+pub mod new;
+pub mod update;
+pub mod build;
+pub mod test;
+pub mod run;
+
+use hatch_error::HatchResult;
+use clap::{ ArgMatches, App };
+use std::path::PathBuf;
+
+static ARGS: &str = "ARGS";
+static INCLUDE: &str = "INCLUDE";
+static VERSION: &str = "VERSION";
+static TYPE: &str = "TYPE";
+static BIN: &str = "bin";
+static STATIC: &str = "static";
+static SHARED: &str = "shared";
+static PROJECT_NAME: &str = "PROJECT_NAME";
+static PROJECT_NAMES: &str = "PROJECT_NAMES";
+static PROJECT_PATH: &str = "PROJECT_PATH";
+
+pub trait Command<'command> {
+ fn cli_subcommand(&self) -> App<'command, 'command>;
+
+ fn subcommand_name(&self) -> &'static str;
+
+ fn execute(&self, args: &ArgMatches<'command>) -> HatchResult<()>;
+
+ fn project_name(&self, args: &ArgMatches<'command>) -> Option {
+ value_t!(args, PROJECT_NAME, String).ok()
+ }
+
+ fn project_path(&self, args: &ArgMatches<'command>) -> PathBuf {
+ if args.is_present(PROJECT_PATH) {
+ PathBuf::from(value_t!(args, PROJECT_PATH, String).unwrap().as_str())
+ } else {
+ PathBuf::from("./")
+ }
+ }
+}
+
+fn parse_deps_from_cli<'func>(args: &ArgMatches<'func>) -> Vec {
+ if let Some(values) = args.values_of(INCLUDE) {
+ values.map(String::from).collect::>()
+ } else {
+ Vec::new()
+ }
+}
diff --git a/hatch/src/cli/commands/new.rs b/hatch/src/cli/commands/new.rs
new file mode 100644
index 0000000..63b1446
--- /dev/null
+++ b/hatch/src/cli/commands/new.rs
@@ -0,0 +1,201 @@
+use std::fs;
+use clap::{ App, SubCommand, Arg, ArgMatches };
+use cli::commands::{ Command, parse_deps_from_cli };
+use deps::clone_project_deps;
+use project::{ Project, ProjectKind, LibraryKind };
+use project::build::{ Target, Config };
+use platform::arch::Arch;
+use deps::dependency::Dependency;
+use locations::{ hatchfile_path, modules_path };
+use hatch_error::{ HatchResult, ResultExt };
+use task;
+
+// Must use qualified names to avoid conflict.
+use std::fmt::Write as FmtWrite;
+use std::io::Write as IoWrite;
+
+use cli::commands::{ INCLUDE, VERSION, TYPE, BIN, STATIC, SHARED, PROJECT_NAME };
+
+pub struct New {
+ name: &'static str,
+}
+
+impl<'new> New {
+ pub fn new() -> New {
+ New {
+ name: "new",
+ }
+ }
+
+ fn project_version(&self, args: &ArgMatches<'new>) -> String {
+ if args.is_present(VERSION) {
+ value_t!(args, VERSION, String).unwrap()
+ } else {
+ "0.0.1".to_owned()
+ }
+ }
+
+ fn project_kind(&self, args: &ArgMatches<'new>) -> ProjectKind {
+ if args.is_present(TYPE) {
+ let type_arg: String = value_t!(args, TYPE, String).unwrap();
+
+ // we cannot use the static variables BIN, STATIC, or SHARED directly because it is illegal in
+ // Rust to pattern match on a static variable
+ match type_arg.as_str() {
+ arg if arg == BIN => ProjectKind::Binary,
+ arg if arg == STATIC => ProjectKind::Library(LibraryKind::Static),
+ arg if arg == SHARED => ProjectKind::Library(LibraryKind::Shared),
+ _ => ProjectKind::Library(LibraryKind::Static)
+ }
+ } else {
+ ProjectKind::Library(LibraryKind::Static)
+ }
+ }
+
+ fn construct_deps_string(&self, project_deps: &Vec) -> String {
+ if project_deps.is_empty() {
+ String::new()
+ } else {
+ String::from("deps:\n") + project_deps.iter().map(|d| {
+ format!(" {}: {}\n", d.name(), d.url())
+ }).collect::().as_str()
+ }
+ }
+
+ fn construct_config(&self, kind: ProjectKind) -> Config {
+ let compiler: String = String::from("g++");
+ let compiler_flags: Vec = vec![String::from("-c")];
+ let linker_flags: Vec = vec![String::from("-v")];
+ let mut arch: Arch = Arch::X64;
+ if let Some(architecture) = Arch::architecture() {
+ arch = architecture;
+ }
+ let target: Target = Target::Debug;
+
+ Config::new(kind, compiler, compiler_flags, linker_flags, arch, target)
+ }
+
+ fn hatch_yml_contents(&self,
+ name: &str,
+ version: &str,
+ config: &Config,
+ includes: &str) -> String
+ {
+ let mut yaml_output = String::new();
+
+ let _ = write!(&mut yaml_output,
+"name: {}
+version: {}
+build:
+ kind: {}
+ compiler: {}
+ compiler_flags: {}
+ linker_flags: {}
+ arch: {}
+ target: {}
+{}",
+ &name,
+ &version,
+ config.kind(),
+ config.compiler(),
+ config.compiler_flags().join(" "),
+ config.linker_flags().join(" "),
+ config.arch(),
+ config.target(),
+ &includes);
+ yaml_output
+ }
+}
+
+impl<'command> Command<'command> for New {
+ fn cli_subcommand(&self) -> App<'command, 'command> {
+ SubCommand::with_name(&self.name)
+ .about("Creates a new project. (default = static library)")
+
+ .arg(Arg::with_name(PROJECT_NAME)
+ .help("Name of project")
+ .takes_value(true)
+ .required(true))
+
+ .arg(Arg::with_name(TYPE)
+ .help("Determines the type of the project")
+ .long("type").short("t")
+ .takes_value(true)
+ .possible_values(&[BIN, STATIC, SHARED])
+ .required(true))
+
+ .arg(Arg::with_name(VERSION)
+ .help("Set the project version")
+ .long("version").short("v").takes_value(true)
+ .required(false))
+
+ .arg(Arg::with_name(INCLUDE)
+ .help("List URLs to git repositories")
+ .long("include").short("i").multiple(true).number_of_values(1).takes_value(true)
+ .required(false))
+ }
+
+ fn subcommand_name(&self) -> &'static str {
+ self.name
+ }
+
+ fn execute(&self, args: &ArgMatches<'command>) -> HatchResult<()> {
+ let name = self.project_name(args).unwrap();
+ let version = self.project_version(args);
+ let kind = self.project_kind(args);
+
+ let dir_path = self.project_path(args).join(&name);
+ let hatch_file = hatchfile_path(&dir_path);
+
+ let deps_from_cli = parse_deps_from_cli(args);
+
+ let res = (|| -> HatchResult<()> {
+ println!("Creating directory structure...");
+
+ // create the hatch project file structure
+ fs::create_dir(&dir_path)?;
+ fs::create_dir(modules_path(&dir_path))?;
+ fs::create_dir(dir_path.join("src"))?;
+ fs::create_dir(dir_path.join("target"))?;
+ fs::create_dir_all(dir_path.join("test").join("src"))?;
+ fs::create_dir(dir_path.join("test").join("target"))?;
+
+ let project_deps = deps_from_cli.into_iter().map(|repo| {
+ Dependency::new(repo)
+ }).collect::>();
+
+ if !project_deps.is_empty() {
+ println!("Installing project dependencies...");
+ clone_project_deps(modules_path(&dir_path).as_path(), &project_deps)?;
+ }
+
+ let includes = self.construct_deps_string(&project_deps);
+ let config = self.construct_config(kind);
+ let yaml_output = self.hatch_yml_contents(&name,
+ &version,
+ config.as_ref(),
+ &includes);
+
+ println!("Creating Hatch.yml file...");
+ let mut file = fs::File::create(hatch_file)?;
+ file.write_all(yaml_output.as_bytes())?;
+
+ let project = Project::new(name,
+ version,
+ config,
+ project_deps,
+ dir_path.to_owned());
+
+ println!("Generating assets...");
+ task::generate_assets(&project)?;
+
+ println!("Finished");
+
+ Ok(())
+ })().with_context(|e| {
+ format!("Failed to create project at: `{}` : {}", dir_path.display(), e)
+ })?;
+
+ Ok(res)
+ }
+}
diff --git a/hatch/src/cli/commands/run.rs b/hatch/src/cli/commands/run.rs
new file mode 100644
index 0000000..93679a4
--- /dev/null
+++ b/hatch/src/cli/commands/run.rs
@@ -0,0 +1,83 @@
+use std::process::Command as ProcessCommand;
+use cli::commands::Command;
+use cli::commands::build::Build;
+use cli::commands::ARGS;
+use hatch_error::{ HatchResult, ResultExt, NullError };
+use task;
+use clap::{ App, SubCommand, Arg, ArgMatches };
+use project::ProjectKind;
+
+pub struct Run {
+ name: &'static str,
+}
+
+impl<'run> Run {
+ pub fn new() -> Run {
+ Run {
+ name: "run",
+ }
+ }
+}
+
+fn parse_run_arguments_from_cli<'command>(cli_args: &ArgMatches<'command>) -> Vec {
+ if let Some(arguments) = cli_args.values_of(ARGS) {
+ arguments.map(String::from).collect()
+ } else {
+ Vec::new()
+ }
+}
+
+impl<'command> Command<'command> for Run {
+ fn cli_subcommand(&self) -> App<'command, 'command> {
+ SubCommand::with_name(&self.name)
+ .about("Executes a project.")
+ .author("Danny Peck ")
+
+ .arg(Arg::with_name(ARGS)
+ .help("The arguments forwarded to the executable.")
+ .min_values(0).value_delimiter(" ")
+ .required(false))
+ }
+
+ fn subcommand_name(&self) -> &'static str {
+ self.name
+ }
+
+ fn execute(&self, args: &ArgMatches<'command>) -> HatchResult<()> {
+ let res = (|| -> HatchResult<()> {
+ let project_path = self.project_path(args);
+ let project = task::read_project(&project_path)?;
+
+ match *project.config().kind() {
+ ProjectKind::Binary => {
+ println!("Generating assets...\n");
+
+ task::generate_assets(&project)?;
+
+ println!("Building project...\n");
+
+ Build::new().execute(&project).with_context(|e| {
+ format!("Failed to build project : {}", e)
+ })?;
+
+ println!("Executing...\n");
+
+ let executable_path = format!("{}target/{}", project_path.display(), project.name());
+ let run_arguments = parse_run_arguments_from_cli(args);
+
+ let mut child = ProcessCommand::new(&executable_path).args(run_arguments).spawn()?;
+ child.wait()?;
+
+ Ok(())
+ },
+ _ => {
+ Err(NullError).context(format!("Project must be a Binary project."))?
+ }
+ }
+ })().with_context(|e| {
+ format!("Execution has failed : {}", e)
+ })?;
+
+ Ok(res)
+ }
+}
diff --git a/hatch/src/cli/commands/test.rs b/hatch/src/cli/commands/test.rs
new file mode 100644
index 0000000..d8d4ab6
--- /dev/null
+++ b/hatch/src/cli/commands/test.rs
@@ -0,0 +1,75 @@
+use std::process::Command as ProcessCommand;
+use cli::commands::Command;
+use cli::commands::build::Build;
+use cli::commands::ARGS;
+use hatch_error::{ HatchResult, ResultExt };
+use task;
+use clap::{ App, SubCommand, Arg, ArgMatches };
+
+pub struct Test {
+ name: &'static str,
+}
+
+impl<'test> Test {
+ pub fn new() -> Test {
+ Test {
+ name: "test",
+ }
+ }
+}
+
+fn parse_test_arguments_from_cli<'command>(cli_args: &ArgMatches<'command>) -> Vec {
+ if let Some(arguments) = cli_args.values_of(ARGS) {
+ arguments.map(String::from).collect()
+ } else {
+ Vec::new()
+ }
+}
+
+impl<'command> Command<'command> for Test {
+ fn cli_subcommand(&self) -> App<'command, 'command> {
+ SubCommand::with_name(&self.name)
+ .about("Tests a project.")
+ .author("Danny Peck ")
+
+ .arg(Arg::with_name(ARGS)
+ .help("The arguments forwarded to the test executable.")
+ .min_values(0).value_delimiter(" ")
+ .required(false))
+ }
+
+ fn subcommand_name(&self) -> &'static str {
+ self.name
+ }
+
+ fn execute(&self, args: &ArgMatches<'command>) -> HatchResult<()> {
+ let res = (|| -> HatchResult<()> {
+ let project_path = self.project_path(args);
+ let project = task::read_project(&project_path)?;
+
+ println!("Generating assets...\n");
+
+ task::generate_assets(&project)?;
+
+ println!("Building project...\n");
+
+ Build::new().execute(&project).with_context(|e| {
+ format!("Failed to build project : {}", e)
+ })?;
+
+ println!("Executing tests...\n");
+
+ let test_executable_path = format!("{}test/target/{}.test", project_path.display(), project.name());
+ let test_arguments = parse_test_arguments_from_cli(args);
+
+ let mut child = ProcessCommand::new(&test_executable_path).args(test_arguments).spawn()?;
+ child.wait()?;
+
+ Ok(())
+ })().with_context(|e| {
+ format!("Test execution has failed : {}", e)
+ })?;
+
+ Ok(res)
+ }
+}
diff --git a/hatch/src/cli/commands/update.rs b/hatch/src/cli/commands/update.rs
new file mode 100644
index 0000000..ea60727
--- /dev/null
+++ b/hatch/src/cli/commands/update.rs
@@ -0,0 +1,44 @@
+use hatch_error::HatchResult;
+use clap::{ App, SubCommand, Arg, ArgMatches };
+use cli::commands::Command;
+use task;
+
+use cli::commands::PROJECT_NAMES;
+
+pub struct Update {
+ name: &'static str
+}
+
+impl<'update> Update {
+ pub fn new() -> Update {
+ Update {
+ name: "update"
+ }
+ }
+}
+
+impl<'command> Command<'command> for Update {
+ fn cli_subcommand(&self) -> App<'command, 'command> {
+ SubCommand::with_name(&self.name)
+ .about("Updates project dependencies.")
+ .version("0.1.0")
+ .author("Josh Gould ")
+
+ .arg(Arg::with_name(PROJECT_NAMES)
+ .help("The projects to be updated.")
+ .min_values(0).value_delimiter(" ")
+ .required(false))
+ }
+
+ fn subcommand_name(&self) -> &'static str {
+ self.name
+ }
+
+ fn execute(&self, args: &ArgMatches<'command>) -> HatchResult<()> {
+ let project = task::read_project(&self.project_path(args))?;
+
+ task::generate_assets(&project)?;
+
+ Ok(())
+ }
+}
diff --git a/hatch/src/cli/mod.rs b/hatch/src/cli/mod.rs
new file mode 100644
index 0000000..a8a6664
--- /dev/null
+++ b/hatch/src/cli/mod.rs
@@ -0,0 +1,31 @@
+pub mod commands;
+
+#[cfg(test)]
+mod tests;
+
+use clap::{ App, AppSettings, ArgMatches, Arg };
+
+pub struct Cli<'cli>(ArgMatches<'cli>);
+
+impl<'cli> Cli<'cli> {
+ pub fn new(subcommands: I) -> Cli<'cli>
+ where I: IntoIterator- > {
+ Cli(App::new("hatch")
+ .setting(AppSettings::SubcommandRequiredElseHelp)
+ .setting(AppSettings::DisableVersion)
+ .subcommands(subcommands.into_iter().map(|s| {
+
+ s.arg(Arg::with_name("PROJECT_PATH")
+ .help("Path to the project. (default = ./)")
+ .long("path").short("p")
+ .required(false)
+ .takes_value(true))
+
+ }).collect::>())
+ .get_matches())
+ }
+
+ pub fn subcommand(&self) -> (&str, Option<&ArgMatches<'cli>>) {
+ self.0.subcommand()
+ }
+}
diff --git a/hatch/src/cli/tests/build.rs b/hatch/src/cli/tests/build.rs
new file mode 100644
index 0000000..ed316b3
--- /dev/null
+++ b/hatch/src/cli/tests/build.rs
@@ -0,0 +1,10 @@
+use cli::commands::build::Build as Build;
+use cli::commands::Command;
+
+#[test]
+fn create_build_command() {
+ let command = Build::new();
+ let actual_name = command.subcommand_name().to_owned();
+ let expected_name = String::from("build");
+ assert_eq!(actual_name, expected_name);
+}
diff --git a/hatch/src/cli/tests/mod.rs b/hatch/src/cli/tests/mod.rs
new file mode 100644
index 0000000..af0168a
--- /dev/null
+++ b/hatch/src/cli/tests/mod.rs
@@ -0,0 +1 @@
+mod build;
diff --git a/hatch/src/deps/dependency.rs b/hatch/src/deps/dependency.rs
new file mode 100644
index 0000000..1c2b0dc
--- /dev/null
+++ b/hatch/src/deps/dependency.rs
@@ -0,0 +1,42 @@
+use std::path::PathBuf;
+use std::ffi::OsStr;
+use std::fmt;
+
+#[derive(Debug)]
+pub struct Dependency {
+ url: String,
+ name: String,
+}
+
+impl Dependency {
+ pub fn new(url: String) -> Dependency {
+ Dependency {
+ name: Dependency::without_dot_git(Dependency::extract_name(url.clone())),
+ url,
+ }
+ }
+
+ fn without_dot_git(name: String) -> String {
+ name[..].replace(".git", "")
+ }
+
+ fn extract_name(url: String) -> String {
+ let url_path = PathBuf::from(url);
+ let last_element = url_path.iter().last().unwrap();
+ last_element.to_string_lossy().into()
+ }
+
+ pub fn name(&self) -> &str {
+ self.name.as_ref()
+ }
+
+ pub fn url(&self) -> &str {
+ self.url.as_ref()
+ }
+}
+
+impl fmt::Display for Dependency {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}: {}", self.name, self.url)
+ }
+}
diff --git a/hatch/src/deps/mod.rs b/hatch/src/deps/mod.rs
new file mode 100644
index 0000000..9e32fb7
--- /dev/null
+++ b/hatch/src/deps/mod.rs
@@ -0,0 +1,95 @@
+#[cfg(test)]
+mod tests;
+
+pub mod dependency;
+
+use hatch_error::{ HatchResult, HatchError };
+use git2::Repository;
+use std::collections::HashSet;
+use std::fs;
+use std::path::{ PathBuf, Path };
+use task;
+use self::dependency::Dependency;
+use locations::hatchfile_path;
+
+pub fn clone_dep(url: &str, path: &Path) {
+ Repository::clone(url, path);
+}
+
+fn walk(path: &Path,
+ callback: &mut FnMut(&Path) -> HatchResult) -> HatchResult<()>
+{
+ if !callback(path)? {
+ return Ok(())
+ }
+
+ let dirs = fs::read_dir(path)?;
+
+ for dir in dirs {
+ let dir = dir?;
+ if dir.file_type()?.is_dir() {
+ walk(&dir.path(), callback)?;
+ }
+ }
+ Ok(())
+}
+
+pub fn clone_project_deps(path: &Path,
+ user_defined_deps: &Vec) -> HatchResult<()>
+{
+ let mut visited: HashSet = HashSet::new();
+ let mut errored: Vec = Vec::new();
+
+ // All dependencies are cloned into here
+ let registry = &path;
+
+ // Clone the dependencies specified on the command line
+ user_defined_deps.iter().for_each(|dep| {
+ clone_dep(&dep.url(), &path.join(&dep.name()));
+ });
+
+ // Clone the dependencies dependencies
+ walk(path, &mut |dir| {
+ // ignore hidden directories and ..
+ let name = dir.file_name().and_then(|s| s.to_str());
+ if name.map(|s| s.starts_with('.')) == Some(true) {
+ return Ok(false)
+ }
+
+ // Grab the path to the Hatch.yml starting at `dir`
+ let hatchfile = hatchfile_path(dir);
+
+ if hatchfile.exists() {
+ clone_nested_project_deps(®istry, &dir, &mut errored, &mut visited);
+ }
+ Ok(true)
+ })?;
+
+ if !errored.is_empty() {
+ errored.into_iter().for_each(|e| {
+ println!("ERROR: {}", e)
+ });
+ }
+
+ Ok(())
+}
+
+fn clone_nested_project_deps(registry: &Path,
+ path: &Path,
+ errored: &mut Vec,
+ visited: &mut HashSet)
+{
+ match task::read_project(path) {
+ Err(e) => {
+ errored.push(e);
+ },
+ Ok(current_project) => {
+ if !visited.contains(¤t_project.name().to_owned()) {
+ current_project.deps().iter().for_each(|dep| {
+ clone_dep(&dep.url(), ®istry.join(dep.name()).as_path());
+ });
+ let _ = visited.insert(current_project.name().to_owned());
+ }
+ }
+ }
+}
diff --git a/hatch/src/deps/tests/clone_one_dep.rs b/hatch/src/deps/tests/clone_one_dep.rs
new file mode 100644
index 0000000..cbef7f5
--- /dev/null
+++ b/hatch/src/deps/tests/clone_one_dep.rs
@@ -0,0 +1,7 @@
+use deps;
+use project::Dependency;
+
+#[test]
+fn clone_one_dep() {
+ let registry = Path::new("TestProject/hatch_modules");
+}
diff --git a/hatch/src/deps/tests/dependency.rs b/hatch/src/deps/tests/dependency.rs
new file mode 100644
index 0000000..68c57ff
--- /dev/null
+++ b/hatch/src/deps/tests/dependency.rs
@@ -0,0 +1,23 @@
+use deps::dependency::Dependency;
+
+#[test]
+fn dependency_name() {
+ let dep =
+ Dependency::new("https://github.com/CachedNerds/TestProject.git".to_owned());
+
+ let expected_name = "TestProject";
+ let actual_name = dep.name();
+
+ assert_eq!(expected_name, actual_name);
+}
+
+#[test]
+fn dependency_url() {
+ let dep =
+ Dependency::new("https://github.com/CachedNerds/TestProject.git".to_owned());
+
+ let expected_url = "https://github.com/CachedNerds/TestProject.git";
+ let actual_url = dep.url();
+
+ assert_eq!(expected_url, actual_url);
+}
diff --git a/hatch/src/deps/tests/mod.rs b/hatch/src/deps/tests/mod.rs
new file mode 100644
index 0000000..bb1df77
--- /dev/null
+++ b/hatch/src/deps/tests/mod.rs
@@ -0,0 +1 @@
+mod dependency;
diff --git a/hatch/src/dtl/asset.rs b/hatch/src/dtl/asset.rs
deleted file mode 100644
index b6ffad1..0000000
--- a/hatch/src/dtl/asset.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use project::Project;
-use dtl::tup::{ Assets };
-
-use dtl::tup::build_system::BuildAssets;
-use dtl::tup::project::ProjectAssets;
-use dtl::tup::platform::PlatformAssets;
-use dtl::tup::test::TestAssets;
-
-pub fn print_file_path(asset: T) where T: Assets {
- println!("{}", asset.path());
-}
-
-pub fn print_file_contents(asset: T) where T: Assets {
- println!("{}", asset.path());
-}
-
-#[derive(Debug)]
-pub enum TupKind { Tuprules, ProjectConfig, ProjectTupfile, ProjectTestTupfile }
-
-#[derive(Debug)]
-pub enum PlatformKind { Linux, Darwin, Win32 }
-
-#[derive(Debug)]
-pub enum AssetKind { Os(PlatformKind), Tup(TupKind) }
-
-#[derive(Debug)]
-pub struct AssetBuilder {
- assets: Vec,
-}
-
-impl AssetBuilder {
- pub fn new() -> AssetBuilder {
- AssetBuilder {
- assets: Vec::new(),
- }
- }
-
- pub fn assets(&mut self) -> &Vec {
- &self.assets.as_ref()
- }
-
- pub fn paths() -> &'static str {
- "/C++/libs\n/C++/Toolbox\n/test"
- }
-
- fn generate_tupkind_assets(&self, asset: &TupKind, project: &Project) {
- match asset {
- Tuprules => print_file_path(BuildAssets::tuprules(&project)),
- ProjectConfig => print_file_path(ProjectAssets::config(&project)),
- ProjectTupfile => print_file_path(ProjectAssets::tupfile(&project)),
- ProjectTestTupfile => print_file_path(TestAssets::tupfile(&project)),
- }
- }
-
- fn generate_platformkind_assets(&self, asset: &PlatformKind, project: &Project) {
- match asset {
- Linux => print_file_path(PlatformAssets::linux(project.path())),
- Darwin => print_file_path(PlatformAssets::darwin(project.path())),
- Win32 => print_file_path(PlatformAssets::win32(project.path())),
- }
- }
-}
diff --git a/hatch/src/dtl/cli.rs b/hatch/src/dtl/cli.rs
deleted file mode 100644
index aec1258..0000000
--- a/hatch/src/dtl/cli.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use project::{ ProjectKind, LibraryKind };
-use clap::{ App, SubCommand, Arg, AppSettings, ArgMatches };
-
-pub struct Cli<'cli>(ArgMatches<'cli>);
-
-impl<'cli> Cli<'cli> {
- pub fn new() -> Cli<'cli> {
-
- let new_command = SubCommand::with_name("new")
- .about("Creates a new project. (default = shared library)")
-
- .arg(Arg::with_name("TOOLBOX_PATH")
- .help("Path to toolbox. (default = ./)")
- .long("path").short("p").required(false).takes_value(true))
-
- .arg(Arg::with_name("PROJECT_NAME")
- .help("Name of project")
- .required(true).takes_value(true))
-
- .arg(Arg::with_name("bin")
- .help("Generate a stand alone executable")
- .long("bin").short("b").required(false))
-
- .arg(Arg::with_name("static")
- .help("Generate a static library")
- .long("static").short("s").conflicts_with("bin").required(false));
-
- Cli(App::new("hatch")
- .setting(AppSettings::SubcommandRequiredElseHelp)
- .subcommand(new_command)
- .get_matches())
- }
-
- pub fn build_type(&self) -> ProjectKind {
- let arg = self.0.subcommand_matches("new").unwrap();
-
- if arg.is_present("bin") {
- ProjectKind::Binary
- } else if arg.is_present("static") {
- ProjectKind::Library(LibraryKind::Static)
- } else {
- ProjectKind::Library(LibraryKind::Shared)
- }
- }
-
- pub fn name(&self) -> String {
- let arg = self.0.subcommand_matches("new").unwrap();
- let name = value_t!(arg, "PROJECT_NAME", String).unwrap();
- name
- }
-
- pub fn path(&self) -> String {
- let arg = self.0.subcommand_matches("new").unwrap();
- let mut path = String::new();
-
- if arg.is_present("TOOLBOX_PATH") {
- path.push_str(value_t!(arg, "TOOLBOX_PATH", String).unwrap().as_str());
- } else {
- path.push_str("./");
- }
-
- match path.as_str().chars().last().unwrap() {
- '/' => path,
- _ => {
- path.push_str("/");
- path
- }
- }
- }
-}
diff --git a/hatch/src/dtl/mod.rs b/hatch/src/dtl/mod.rs
deleted file mode 100644
index 16d86d8..0000000
--- a/hatch/src/dtl/mod.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-pub mod project;
-pub mod asset;
-pub mod cli;
-pub mod tup;
diff --git a/hatch/src/dtl/project.rs b/hatch/src/dtl/project.rs
deleted file mode 100644
index 1ce80d6..0000000
--- a/hatch/src/dtl/project.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use project::ProjectKind;
-use cli::Cli;
-
-pub struct Project {
- name: String,
- kind: ProjectKind,
- path: String,
-}
-
-impl Project {
- pub fn new() -> Project {
- let cli = Cli::new();
- Project { name: cli.name(), kind: cli.kind(), path: cli.path() }
- }
-
- pub fn name(&self) -> &str {
- self.name.as_ref()
- }
-
- pub fn kind(&self) -> &ProjectKind {
- self.kind.as_ref()
- }
-
- pub fn path(&self) -> &str {
- self.path.as_ref()
- }
-}
diff --git a/hatch/src/dtl/tup/build_system.rs b/hatch/src/dtl/tup/build_system.rs
deleted file mode 100644
index 6a5a989..0000000
--- a/hatch/src/dtl/tup/build_system.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use dtl::tup::{ Assets };
-use project::{ Project };
-
-pub struct BuildAssets {
- file_path: String,
- file_contents: String,
-}
-
-impl Assets for BuildAssets {
- fn path(&self) -> &str {
- &self.file_path.as_str()
- }
-
- fn contents(&self) -> &str {
- &self.file_contents.as_str()
- }
-}
-
-impl BuildAssets {
- pub fn tuprules(project: &Project) -> BuildAssets {
- let file_path = project.path().to_string() + "/Tuprules.tup";
- let file_contents =
-".gitignore
-CC = g++
-# Uncomment to build with debug symbols
-#CFLAGS += -g
-ARCH = -m64
-#ARCH = -m32
-CFLAGS += $(ARCH)
-CFLAGS += -std=c++1z
-CFLAGS += -c
-CFLAGS += -I ../../
-LINKFLAGS += $(ARCH)
-LINKFLAGS += -static
-LINKFLAGS += -v
-SOURCE = src
-SOURCE_OUT = build
-SOURCE_FILES = $(SOURCE)/*.cpp
-SOURCE_OBJ_FILES = $(SOURCE_OUT)/*.o
-TEST = test
-TEST_OUT = $(TEST)/build
-TEST_FILES = $(TEST)/$(SOURCE)/*.cpp
-TEST_OBJ_FILES = $(TEST_OUT)/*.o
-# macros
-!compile = |> $(CC) $(CFLAGS) %f -o %o |>
-!archive = |> ar crs %o %f |>
-!link = |> $(CC) $(LINKFLAGS) %f -o %o |>
-# includes the STATIC and SHARED variables for the target platform
-include @(TUP_PLATFORM).tup
-ifeq ($(LIB_TYPE),static)
- EXTENSION = $(STATIC)
-else
- ifeq ($(LIB_TYPE),shared)
- EXTENSION = $(SHARED)
- else
- ifeq ($(LIB_TYPE),both)
- EXTENSION = both
- endif
- endif
-endif
-PROJECT_LIB = $(PROJECT).$(EXTENSION)".to_string();
- BuildAssets { file_path, file_contents }
- }
-}
diff --git a/hatch/src/dtl/tup/mod.rs b/hatch/src/dtl/tup/mod.rs
deleted file mode 100644
index 2d3e71a..0000000
--- a/hatch/src/dtl/tup/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod build_system;
-pub mod project;
-pub mod platform;
-pub mod test;
-
-pub trait Assets {
- fn contents(&self) -> &str;
- fn path(&self) -> &str;
-}
diff --git a/hatch/src/dtl/tup/platform.rs b/hatch/src/dtl/tup/platform.rs
deleted file mode 100644
index 14873a7..0000000
--- a/hatch/src/dtl/tup/platform.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use dtl::tup::{ Assets };
-
-pub struct PlatformAssets {
- file_path: String,
- file_contents: String,
-}
-
-impl Assets for PlatformAssets {
- fn path(&self) -> &str {
- &self.file_path.as_str()
- }
-
- fn contents(&self) -> &str {
- &self.file_contents.as_str()
- }
-}
-
-impl PlatformAssets {
- // Expects path to be /xxxx/xxxx/Toolbox
- pub fn linux(path: &str) -> PlatformAssets {
- let file_path = path.to_string() + "/linux.tup";
- let file_contents =
-"STATIC = a
-SHARED = so".to_string();
- PlatformAssets { file_path, file_contents }
- }
-
- // Expects path to be /xxxx/xxxx/Toolbox
- pub fn darwin(path: &str) -> PlatformAssets {
- let file_path = path.to_string() + "/macosx.tup";
- let file_contents =
-"STATIC = a
-SHARED = so".to_string();
- PlatformAssets { file_path, file_contents }
- }
-
- // Expects path to be /xxxx/xxxx/Toolbox
- pub fn win32(path: &str) -> PlatformAssets {
- let file_path = path.to_string() + "/win32.tup";
- let file_contents =
-"STATIC = lib
-SHARED = dll
-# Use clang for front-end
-CC = clang++.exe
-# Use llvm-lib for static libraries
-!archive = |> llvm-lib /MACHINE:X64 /OUT:%o %f |>".to_string();
- PlatformAssets { file_path, file_contents }
- }
-}
diff --git a/hatch/src/dtl/tup/project.rs b/hatch/src/dtl/tup/project.rs
deleted file mode 100644
index 4a5f2eb..0000000
--- a/hatch/src/dtl/tup/project.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use dtl::tup::{ Assets };
-use project::{ ProjectKind, Project };
-
-pub struct ProjectAssets {
- file_path: String,
- file_contents: String,
-}
-
-impl Assets for ProjectAssets {
- fn path(&self) -> &str {
- &self.file_path.as_str()
- }
-
- fn contents(&self) -> &str {
- &self.file_contents.as_str()
- }
-}
-
-impl ProjectAssets {
- pub fn config(project: &Project) -> ProjectAssets {
- let file_path = project.path().to_string() + "/" + project.name() + "/config.tup";
-
- let file_contents = match project.kind() {
- &ProjectKind::Library(ref shared_lib) => format!( // {{{
-"PROJECT = {}
-LIB_TYPE = shared", // }}}
- project.name()).to_string(),
-
- &ProjectKind::Library(ref static_lib) => format!( // {{{
-"PROJECT = {}
-LIB_TYPE = static", // }}}
- project.name()).to_string(),
-
- &ProjectKind::Binary => format!( // {{{
-"PROJECT = {}", // }}}
- project.name()).to_string(),
- };
-
- ProjectAssets { file_path, file_contents }
- }
-
- pub fn tupfile(project: &Project) -> ProjectAssets {
- let file_path = project.path().to_string() + "/" + project.name() + "/Tupfile";
- let file_contents = // {{{
-"# order matters
-include config.tup
-include_rules
-# override build variables
-# VARIABLE = new_value
-# define custom build variables
-# Compile Source
-: foreach $(SOURCE_FILES) |> !compile |> $(SOURCE_OUT)/%B.o
-# Archive Source
-: $(SOURCE_OBJ_FILES) |> !archive |> $(SOURCE_OUT)/$(PROJECT_LIB) ../<$(PROJECT)>
-# Compile Tests
-: foreach $(TEST_FILES) |> !compile |> $(TEST_OUT)/%B.o
-# Create Link Executable
-: $(TEST_OBJ_FILES) $(SOURCE_OUT)/$(PROJECT_LIB) |> !link |> $(TEST_OUT)/$(PROJECT).test".to_string(); // }}}
-
- ProjectAssets { file_path, file_contents }
- }
-}
diff --git a/hatch/src/dtl/tup/test.rs b/hatch/src/dtl/tup/test.rs
deleted file mode 100644
index 0a7e36f..0000000
--- a/hatch/src/dtl/tup/test.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use project::{ Project };
-use dtl::tup::{ Assets };
-
-pub struct TestAssets {
- file_path: String,
- file_contents: String,
-}
-
-impl Assets for TestAssets {
- fn path(&self) -> &str {
- &self.file_path.as_str()
- }
-
- fn contents(&self) -> &str {
- &self.file_contents.as_str()
- }
-}
-
-impl TestAssets {
- pub fn tupfile(project: &Project) -> TestAssets {
- let file_path = project.path().to_string() + "/" + project.name() + "/test/Tupfile";
- let file_contents =
-".gitignore".to_string();
-
- TestAssets { file_path, file_contents }
- }
-}
diff --git a/hatch/src/hatch_error/mod.rs b/hatch/src/hatch_error/mod.rs
new file mode 100644
index 0000000..8bdcd97
--- /dev/null
+++ b/hatch/src/hatch_error/mod.rs
@@ -0,0 +1,28 @@
+pub use failure::ResultExt;
+pub use failure::Error as HatchError;
+
+pub type HatchResult = Result;
+
+#[derive(Fail, Debug)]
+#[fail(display = "No content in Hatch.yml")]
+pub struct EmptyConfigError;
+
+#[derive(Fail, Debug)]
+#[fail(display = "No build field found in Hatch.yml")]
+pub struct MissingBuildError;
+
+#[derive(Fail, Debug)]
+#[fail(display = "No name field found in Hatch.yml")]
+pub struct MissingNameError;
+
+#[derive(Fail, Debug)]
+#[fail(display = "No version field found in Hatch.yml")]
+pub struct MissingVersionError;
+
+#[derive(Fail, Debug)]
+#[fail(display = "Invalid path")]
+pub struct InvalidPathError;
+
+#[derive(Fail, Debug)]
+#[fail(display = "")]
+pub struct NullError;
diff --git a/hatch/src/lib.rs b/hatch/src/lib.rs
index ec6961e..825a492 100644
--- a/hatch/src/lib.rs
+++ b/hatch/src/lib.rs
@@ -1,13 +1,24 @@
#![forbid(unsafe_code)]
+
#[macro_use]
pub extern crate clap;
+pub extern crate yaml_rust;
+pub extern crate git2;
+#[macro_use]
+pub extern crate failure;
+pub extern crate os_info;
+pub extern crate reqwest;
pub mod project;
pub mod cli;
-pub mod asset;
-pub mod manifest;
-mod dtl;
+pub mod hatch_error;
+pub mod yaml;
+pub mod assets;
+pub mod task;
+pub mod deps;
+pub mod platform;
+pub mod locations;
#[cfg(test)]
mod tests {
diff --git a/hatch/src/locations/mod.rs b/hatch/src/locations/mod.rs
new file mode 100644
index 0000000..d3529b8
--- /dev/null
+++ b/hatch/src/locations/mod.rs
@@ -0,0 +1,10 @@
+use std::path::{ Path, PathBuf };
+
+pub fn modules_path(base: &Path) -> PathBuf {
+ base.join("hatch_modules")
+}
+
+pub fn hatchfile_path(base: &Path) -> PathBuf {
+ base.join("Hatch.yml")
+}
+
diff --git a/hatch/src/locations/tests/hatchfile_path.rs b/hatch/src/locations/tests/hatchfile_path.rs
new file mode 100644
index 0000000..980550b
--- /dev/null
+++ b/hatch/src/locations/tests/hatchfile_path.rs
@@ -0,0 +1,12 @@
+use deps;
+use std::path::{ Path, PathBuf };
+
+#[test]
+fn hatchfile_path() {
+ let path = Path::new("TestProject");
+
+ let expected_path = PathBuf::from("TestProject").join("Hatch.yml");
+ let actual_path = deps::hatchfile_path(path);
+
+ assert_eq!(expected_path, actual_path);
+}
diff --git a/hatch/src/locations/tests/mod.rs b/hatch/src/locations/tests/mod.rs
new file mode 100644
index 0000000..5046955
--- /dev/null
+++ b/hatch/src/locations/tests/mod.rs
@@ -0,0 +1,2 @@
+mod hatchfile_path;
+mod modules_path;
diff --git a/hatch/src/locations/tests/modules_path.rs b/hatch/src/locations/tests/modules_path.rs
new file mode 100644
index 0000000..47c5da9
--- /dev/null
+++ b/hatch/src/locations/tests/modules_path.rs
@@ -0,0 +1,12 @@
+use deps;
+use std::path::{ Path, PathBuf };
+
+#[test]
+fn modules_path() {
+ let path = Path::new("TestProject");
+
+ let expected_path = PathBuf::from("TestProject").join("hatch_modules");
+ let actual_path = deps::modules_path(path);
+
+ assert_eq!(expected_path, actual_path);
+}
diff --git a/hatch/src/manifest.rs b/hatch/src/manifest.rs
deleted file mode 100644
index 252e5ec..0000000
--- a/hatch/src/manifest.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use asset::Asset;
-use project::Project;
-
-pub struct Manifest {
- project: Project,
- assets: Asset,
-}
-
-impl Manifest {
- pub fn new() -> Manifest {
- Manifest {
- project: Project::new(),
- assets: Asset::new(),
- }
- }
-}
diff --git a/hatch/src/platform/arch.rs b/hatch/src/platform/arch.rs
new file mode 100644
index 0000000..fdf7d5a
--- /dev/null
+++ b/hatch/src/platform/arch.rs
@@ -0,0 +1,30 @@
+use std::mem::size_of;
+use std::fmt;
+
+#[derive(Debug)]
+pub enum Arch { X64, X86 }
+
+impl AsRef for Arch {
+ fn as_ref(&self) -> &Arch {
+ &self
+ }
+}
+
+impl fmt::Display for Arch {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Arch::X64 => write!(f, "x64"),
+ Arch::X86 => write!(f, "x86"),
+ }
+ }
+}
+
+impl Arch {
+ pub fn architecture() -> Option {
+ match size_of::<&char>() {
+ 32 => Some(Arch::X86),
+ 64 => Some(Arch::X64),
+ _ => None
+ }
+ }
+}
diff --git a/hatch/src/platform/mod.rs b/hatch/src/platform/mod.rs
new file mode 100644
index 0000000..dfa15f5
--- /dev/null
+++ b/hatch/src/platform/mod.rs
@@ -0,0 +1,2 @@
+pub mod arch;
+pub mod os;
diff --git a/hatch/src/platform/os.rs b/hatch/src/platform/os.rs
new file mode 100644
index 0000000..470626d
--- /dev/null
+++ b/hatch/src/platform/os.rs
@@ -0,0 +1,11 @@
+use assets::PlatformKind;
+use os_info;
+use os_info::Type::{ Macos, Windows };
+
+pub fn platform_type() -> PlatformKind {
+ match *os_info::get().os_type() {
+ Macos => PlatformKind::MacOS,
+ Windows => PlatformKind::Windows,
+ _ => PlatformKind::Linux
+ }
+}
diff --git a/hatch/src/project.rs b/hatch/src/project.rs
deleted file mode 100644
index 49e45ca..0000000
--- a/hatch/src/project.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use dtl::project as project_imp;
-
-pub struct Project (project_imp::Project);
-
-impl Project {
- pub fn new() -> Project {
- Project(project_imp::Project::new())
- }
-
- pub fn name(&self) -> &str {
- self.0.name()
- }
-
- pub fn kind(&self) -> &ProjectKind {
- self.0.kind()
- }
-
- pub fn path(&self) -> &str {
- self.0.path()
- }
-}
-
-pub enum LibraryKind { Shared, Static }
-
-pub enum ProjectKind { Binary, Library(LibraryKind) }
-
-impl AsRef for ProjectKind {
- fn as_ref(&self) -> &ProjectKind {
- &self
- }
-}
diff --git a/hatch/src/project/build.rs b/hatch/src/project/build.rs
new file mode 100644
index 0000000..22f3edc
--- /dev/null
+++ b/hatch/src/project/build.rs
@@ -0,0 +1,81 @@
+use std::fmt;
+use project::ProjectKind;
+use platform::arch::Arch;
+
+#[derive(Debug)]
+pub struct Config {
+ kind: ProjectKind,
+ compiler: String,
+ compiler_flags: Vec,
+ linker_flags: Vec,
+ arch: Arch,
+ target: Target
+}
+
+impl Config {
+ pub fn new(kind: ProjectKind,
+ compiler: String,
+ compiler_flags: Vec,
+ linker_flags: Vec,
+ arch: Arch,
+ target: Target) -> Config
+ {
+ Config {
+ kind,
+ compiler,
+ compiler_flags,
+ linker_flags,
+ arch,
+ target
+ }
+ }
+
+ pub fn kind(&self) -> &ProjectKind {
+ self.kind.as_ref()
+ }
+
+ pub fn compiler(&self) -> &str {
+ self.compiler.as_ref()
+ }
+
+ pub fn compiler_flags(&self) -> &Vec {
+ self.compiler_flags.as_ref()
+ }
+
+ pub fn linker_flags(&self) -> &Vec {
+ self.linker_flags.as_ref()
+ }
+
+ pub fn arch(&self) -> &Arch {
+ self.arch.as_ref()
+ }
+
+ pub fn target(&self) -> &Target {
+ self.target.as_ref()
+ }
+}
+
+impl AsRef for Config {
+ fn as_ref(&self) -> &Config {
+ &self
+ }
+}
+
+#[derive(Debug)]
+pub enum Target { Debug, Release }
+
+impl AsRef for Target {
+ fn as_ref(&self) -> &Target {
+ &self
+ }
+}
+
+impl fmt::Display for Target {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Target::Debug => write!(f, "debug"),
+ Target::Release => write!(f, "release"),
+ }
+ }
+}
+
diff --git a/hatch/src/project/mod.rs b/hatch/src/project/mod.rs
new file mode 100644
index 0000000..bed6fd2
--- /dev/null
+++ b/hatch/src/project/mod.rs
@@ -0,0 +1,74 @@
+pub mod build;
+
+use std::fmt;
+use std::path::PathBuf;
+use self::build::Config;
+use deps::dependency::Dependency;
+
+#[derive(Debug)]
+pub struct Project {
+ name: String,
+ version: String,
+ config: Config,
+ deps: Vec,
+ path: PathBuf
+}
+
+impl Project {
+ pub fn new(name: String,
+ version: String,
+ config: Config,
+ deps: Vec,
+ path: PathBuf) -> Project
+ {
+ Project {
+ name,
+ version,
+ config,
+ deps,
+ path
+ }
+ }
+
+ pub fn name(&self) -> &str {
+ self.name.as_ref()
+ }
+
+ pub fn version(&self) -> &str {
+ self.version.as_ref()
+ }
+
+ pub fn config(&self) -> &Config {
+ self.config.as_ref()
+ }
+
+ pub fn deps(&self) -> &Vec {
+ self.deps.as_ref()
+ }
+
+ pub fn path(&self) -> &PathBuf {
+ &self.path
+ }
+}
+
+#[derive(Debug)]
+pub enum LibraryKind { Shared, Static }
+
+#[derive(Debug)]
+pub enum ProjectKind { Binary, Library(LibraryKind) }
+
+impl AsRef for ProjectKind {
+ fn as_ref(&self) -> &ProjectKind {
+ &self
+ }
+}
+
+impl fmt::Display for ProjectKind {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ProjectKind::Library(LibraryKind::Shared) => write!(f, "shared-lib"),
+ ProjectKind::Library(LibraryKind::Static) => write!(f, "static-lib"),
+ ProjectKind::Binary => write!(f, "binary"),
+ }
+ }
+}
diff --git a/hatch/src/task/mod.rs b/hatch/src/task/mod.rs
new file mode 100644
index 0000000..c1dec3e
--- /dev/null
+++ b/hatch/src/task/mod.rs
@@ -0,0 +1,25 @@
+#[cfg(test)]
+pub mod tests;
+
+use project::Project;
+use assets::builder::Builder as AssetBuilder;
+use std::path::Path;
+use hatch_error::{ HatchResult, ResultExt };
+use assets::generator;
+use yaml;
+
+pub fn read_project(path: &Path) -> HatchResult {
+ let project = yaml::parse(path, String::from("Hatch.yml")).with_context(|e| {
+ format!("failed to read project at `{}` : {}", path.display(), e)
+ })?;
+
+ Ok(project)
+}
+
+pub fn generate_assets(project: &Project) -> HatchResult<()> {
+ generator::generate_all(AssetBuilder::from(project).assets()).with_context(|e| {
+ format!("asset generation failed : `{}`", e)
+ })?;
+
+ Ok(())
+}
diff --git a/hatch/src/task/tests.rs b/hatch/src/task/tests.rs
new file mode 100644
index 0000000..924c531
--- /dev/null
+++ b/hatch/src/task/tests.rs
@@ -0,0 +1,58 @@
+use task;
+use project::{ Project, ProjectKind };
+use project::build::{ Target, Config };
+use platform::arch::Arch;
+use platform::os;
+use assets::PlatformKind;
+use std::fs;
+use std::path::{ Path, PathBuf };
+
+fn assets_exist(path: &Path) -> bool {
+ let file_path = match os::platform_type() {
+ PlatformKind::MacOS => path.join("macosx.tup"),
+ PlatformKind::Windows => path.join("win32.tup"),
+ PlatformKind::Linux => path.join("linux.tup")
+ };
+
+ path.join("Tupfile").exists() &&
+ path.join("config.tup").exists() &&
+ path.join("Tuprules.tup").exists() &&
+ path.join("Tupfile.ini").exists() &&
+ path.join("test").join("Tupfile").exists() &&
+ path.join("test/src").join("catch.hpp").exists() &&
+ path.join("test/src").join("catch.cpp").exists() &&
+ file_path.exists()
+}
+
+fn remove_assets(path: &Path) {
+ fs::remove_dir_all(&path);
+}
+
+#[test]
+fn generate_assets_success() {
+ let path = PathBuf::from("./temp/");
+ fs::create_dir_all(&path);
+
+ let config = Config::new(ProjectKind::Binary,
+ String::from("g++"),
+ vec![String::from("-c"), String::from("--std=c++1z")],
+ vec![String::from("-v")],
+ Arch::X64,
+ Target::Release);
+
+ let project = Project::new(String::from("test"),
+ String::from("0.1.0"),
+ config,
+ Vec::new(),
+ PathBuf::from(&path));
+
+ if let Err(e) = task::generate_assets(&project) {
+ remove_assets(&path);
+ panic!(e)
+ }
+
+ let exists = assets_exist(&path);
+ remove_assets(&path);
+
+ assert!(exists);
+}
diff --git a/hatch/src/yaml.rs b/hatch/src/yaml.rs
new file mode 100644
index 0000000..d6d5bd4
--- /dev/null
+++ b/hatch/src/yaml.rs
@@ -0,0 +1,159 @@
+use std::fs;
+use std::io::Read;
+use std::path::{ Path, PathBuf };
+use yaml_rust::{ Yaml, YamlLoader };
+use project::{ Project, LibraryKind, ProjectKind };
+use project::build::{ Target, Config };
+use deps::dependency::Dependency;
+use platform::arch::Arch;
+
+use hatch_error::{
+ HatchResult,
+ ResultExt,
+ MissingNameError,
+ MissingBuildError,
+ MissingVersionError,
+ EmptyConfigError,
+};
+
+pub fn parse(path: &Path, name: String) -> HatchResult {
+ let yml_vec = from_file(path.join(name).as_path())?;
+
+ if yml_vec.is_empty() {
+ return Err(EmptyConfigError)?;
+ }
+
+ let name: String;
+ let version: String;
+ let mut kind: ProjectKind = ProjectKind::Library(LibraryKind::Static);
+ let mut compiler: String = String::from("g++");
+ let mut compiler_flags: Vec = vec![String::from("-c")];
+ let mut linker_flags: Vec = vec![String::from("-v")];
+ let mut arch: Arch = Arch::X64;
+ if let Some(architecture) = Arch::architecture() {
+ arch = architecture;
+ }
+ let mut target: Target = Target::Debug;
+ let deps: Vec;
+
+ if let Some(n) = yml_vec[0]["name"].as_str() {
+ name = n.to_owned();
+ } else {
+ return Err(MissingNameError)?;
+ }
+
+ if let Some(v) = yml_vec[0]["version"].as_str() {
+ version = v.to_owned();
+ } else {
+ return Err(MissingVersionError)?;
+ }
+
+ if let Some(configurations) = yml_vec[0]["build"].as_hash() {
+ let items = configurations
+ .iter()
+ .map(|(k, v)| {
+ (k.as_str(), v.as_str())
+ })
+ .filter(|&(k, v)| {
+ k.is_some() && v.is_some()
+ })
+ .map(|(k, v)| {
+ (k.unwrap(), v.unwrap())
+ }).collect::>();
+
+ for (key, value) in items {
+ match key {
+ "kind" => {
+ kind = match value {
+ "static-lib" => ProjectKind::Library(LibraryKind::Static),
+ "shared-lib" => ProjectKind::Library(LibraryKind::Shared),
+ _ => ProjectKind::Binary
+ }
+ },
+ "compiler" => {
+ compiler = String::from(value);
+ },
+ "compiler_flags" => {
+ compiler_flags =
+ String::from(value)
+ .split_whitespace()
+ .map(String::from)
+ .collect();
+ },
+ "linker_flags" => {
+ linker_flags =
+ String::from(value)
+ .split_whitespace()
+ .map(String::from)
+ .collect();
+ },
+ "arch" => {
+ match value {
+ "x64" => {
+ arch =Arch::X64
+ },
+ "x86" => {
+ arch = Arch::X86
+ },
+ _ => {
+ // use default
+ }
+ }
+ },
+ "target" => {
+ match value {
+ "debug" => {
+ target = Target::Debug
+ },
+ "release" => {
+ target = Target::Release
+ },
+ _ => {
+ // use default
+ }
+ }
+ },
+ _ => {}
+ }
+ }
+ } else {
+ return Err(MissingBuildError)?;
+ }
+
+ if let Some(d) = yml_vec[0]["deps"].as_hash() {
+ deps = d
+ .iter()
+ .filter_map(|(_k, v)| v.as_str())
+ .map(|v| Dependency::new(v.to_owned()))
+ .collect();
+ } else {
+ deps = Vec::new();
+ }
+
+ let config = Config::new(kind, compiler, compiler_flags, linker_flags, arch, target);
+ Ok(Project::new(name, version, config, deps, PathBuf::from(path)))
+}
+
+fn from_file(file_name: &Path) -> HatchResult> {
+ let mut file = fs::File::open(&file_name).with_context(|_| {
+ format!("failed to open file: `{}`", &file_name.display())
+ })?;
+
+ let mut contents = String::new();
+ file.read_to_string(&mut contents).with_context(|_| {
+ format!("failed to read contents of: `{}`", file_name.display())
+ })?;
+
+ let res = YamlLoader::load_from_str(&contents).compat().with_context(|e| {
+ format!("Parsing error: `{}`", e)
+ })?;
+
+ Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn it_works() {
+ }
+}