diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..e77a34b --- /dev/null +++ b/.cargo/config @@ -0,0 +1,3 @@ +[target.x86_64-apple-darwin] +linker = "x86_64-apple-darwin17-clang" +ar = "x86_64-apple-darwin17 -ar" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bb8d25 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +.idea diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..334fb2f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,615 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "chrono" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "deunicode" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dtoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "error-chain" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "humansize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "j2_render" +version = "0.0.1" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.20 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "linked-hash-map" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pest" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_generator" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_meta 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_meta" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_yaml" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha-1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "deunicode 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "smallvec" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tera" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ucd-trie" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unic-char-property" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unic-char-range" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unic-common" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unic-segment" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-ucd-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-char-property 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unic-ucd-version 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unic-ucd-version" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-common 0.7.0 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (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 = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "yaml-rust" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" +"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" +"checksum deunicode 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" +"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" +"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" +"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum pest 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "933085deae3f32071f135d799d75667b63c8dc1f4537159756e3d4ceab41868c" +"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646" +"checksum pest_meta 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f249ea6de7c7b7aba92b4ff4376a994c6dbd98fd2166c89d5c4947397ecb574d" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" +"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" +"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" +"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum tera 0.11.20 (registry+https://github.com/rust-lang/crates.io-index)" = "4b505279e19d8f7d24b1a9dc58327c9c36174b1a2c7ebdeac70792d017cb64f3" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" +"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2" +"checksum unic-char-property 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce36d3f7ce754afdbccccf8ff0dd0134e50fb44aaae579f96218856e9e5dbd1e" +"checksum unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab85fab42ad1b26cafc03bf891f69cb4d6e15f491030e89a0122197baa8ae8" +"checksum unic-common 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8d4a7ade929ef7d971e16ced21a8cd56a63869aa6032dfb8cb083cf7d077bf" +"checksum unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ca47cbb09fb5fcd066b5867d11dc528302fa465277882797d6a836e1ee6f9e" +"checksum unic-ucd-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48f1a08ce0409a9e391b88d1930118eec48af12742fc538bcec55f775865776e" +"checksum unic-ucd-version 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1f5e6c6c53c2d0ece4a5964bc55fcff8602153063cb4fab20958ff32998ff6" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4f6409c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "j2_render" +version = "0.0.1" +authors = ["Sergio Medina Toledo "] +description = "CLI to render jinja 2 templates, can use files or env vars as context" +edition = "2018" +readme = "README.md" +license = "MIT" + +[dependencies] +tera = "0.11.20" +serde = "1.0.99" +toml = "0.5.3" +serde_json = "1.0.40" +serde_yaml = "0.8.9" +glob = "0.3.0" +base64 = "0.10.1" + +[[bin]] +name = "j2_render" +path = "src/main.rs" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c9de1c8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Weiguang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3ed65fb --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# j2_render diff --git a/examples/ctx.json b/examples/ctx.json new file mode 100644 index 0000000..caf5bd9 --- /dev/null +++ b/examples/ctx.json @@ -0,0 +1,7 @@ +{ + "my_string": "hi i'm a string", + "my_number": 1, + "my_float": 1.2, + "my_array": [ "this is", "a list of", "three strings"], + "my_obj": {"a": "a", "b": "b"} +} \ No newline at end of file diff --git a/examples/ctx.yaml b/examples/ctx.yaml new file mode 100644 index 0000000..0e6922d --- /dev/null +++ b/examples/ctx.yaml @@ -0,0 +1 @@ +my_string: this is my string from yaml \ No newline at end of file diff --git a/examples/template.j2 b/examples/template.j2 new file mode 100644 index 0000000..905aa0b --- /dev/null +++ b/examples/template.j2 @@ -0,0 +1,18 @@ +this is my string: {{my_string}} +this is my number: {{my_number}} +this is my float: {{my_float}} + +{% for element in my_array %} + {{loop.index}}. {{element}} +{% endfor %} + +{% for key, value in my_obj %} + {{key}}. {{value}} +{% endfor %} + +{{ bash(command='ls -la | tr -s " "') }} + +1. {{ my_string | sed(expression="s|this||g") | bash(command="wc")}} +2. {{ my_string | bash(command='sed -e "s|this||g" | wc')}} + +{{bash(command="echo $var1 $var2", var1="hola", var2="mundo")}} diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..4d9350b --- /dev/null +++ b/release.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Subshell to not pollute env vars +( +echo "Building target for platform x86_64-apple-darwin" + +# Add osxcross toolchain to path +export PATH="/opt/osxcross/bin:${PATH}" + +# Use Clang for C/C++ builds +export CC=o64-clang +export CXX=o64-clang++ +export LD_LIBRARY_PATH="/opt/osxcross/lib" + +cargo build --release --target x86_64-apple-darwin + +) + +echo "Building target for platform x86_64-unknown-linux-musl" +cargo build --target x86_64-unknown-linux-musl --release \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7530651 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +max_width = 120 diff --git a/src/filters.rs b/src/filters.rs new file mode 100644 index 0000000..b32a9c1 --- /dev/null +++ b/src/filters.rs @@ -0,0 +1,182 @@ +//tera +//--stdin -i json,yaml,hcl,tfvars,template +//--env -e load env vars in ctx +//--ctx -c file_path [format] multiple files allowed +//--template -t file_path + +use crate::inners::exec_cmd; +use base64; +use glob::glob; +use std::collections::HashMap; +use std::fs; +use std::path::Path; +use std::process::Command; +use tera::{Error, Result, Value}; + +pub fn bash(piped_arg: Value, args: HashMap) -> Result { + let data = if let Value::String(data) = piped_arg { + data + } else { + return Err("bash: Invalid type, expected string".into()); + }; + + let command = if let Some(Value::String(command)) = args.get("command") { + command + } else { + return Err("bash: Invalid type for arg command, expected string".into()); + }; + + let mut bash_cmd = Command::new("bash"); + + bash_cmd + .env("__data", data) + .arg("-c") + .arg(format!("echo \"$__data\" | {}", command)); + + return exec_cmd(&mut bash_cmd, command, &args); +} + +pub fn sed(piped_arg: Value, args: HashMap) -> Result { + let data = if let Value::String(data) = piped_arg { + data + } else { + return Err("sed: Invalid type, expected string".into()); + }; + + let expr = if let Some(Value::String(expr)) = args.get("expression") { + expr + } else { + return Err("sed: Invalid type for arg command, expected string".into()); + }; + + let mut bash_cmd = Command::new("bash"); + let command = format!("sed -e \"{}\"", expr); + bash_cmd + .env("__data", data) + .arg("-c") + .arg(format!("echo \"$__data\" | {}", command)); + + return exec_cmd(&mut bash_cmd, &command, &args); +} + +pub fn file_glob(piped_arg: Value, _: HashMap) -> Result { + let mut files_matched = vec![]; + + if let Value::String(path) = piped_arg { + let paths = match glob(&path) { + Ok(paths) => paths, + Err(e) => return Err(format!("file_glob: error in glob : {:?}", e).into()), + }; + for entry in paths { + match entry { + Ok(path) => files_matched.push(Value::String(format!("{}", path.display()))), + Err(e) => println!("{:?}", e), + } + } + return Ok(Value::Array(files_matched)); + } else { + return Err("file_glob: Invalid type, expected string".into()); + } +} + +pub fn read_file(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(path) = piped_arg { + match fs::read_to_string(path) { + Ok(contents) => return Ok(Value::String(contents)), + Err(e) => return Err(format!("read_file: error reading file : {:?}", e).into()), + } + } else { + return Err("read_file: Invalid type, expected string".into()); + } +} + +pub fn file_name(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(path) = piped_arg { + let path = Path::new(&path); + let file_name = match path.file_name() { + Some(file_name) => file_name, + None => return Err(format!("file_name: error extracting filename : path is root, no filename").into()), + }; + + match file_name.to_str() { + Some(file_name) => return Ok(Value::String(file_name.to_string())), + None => return Err(format!("file_name: error decoding filename").into()), + } + } else { + return Err("file_name: Invalid type, expected string".into()); + } +} + +pub fn file_dir(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(path) = piped_arg { + let path = Path::new(&path); + let file_name = match path.parent() { + Some(file_name) => file_name, + None => return Err(format!("file_dir: error extracting filename : path is root, no filename").into()), + }; + + match file_name.to_str() { + Some(file_name) => return Ok(Value::String(file_name.to_string())), + None => return Err(format!("file_dir: error decoding filename").into()), + } + } else { + return Err("file_dir: Invalid type, expected string".into()); + } +} + +pub fn strip_line_breaks(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(lines) = piped_arg { + return Ok(Value::String(lines.replace("\n", ""))); + } else { + return Err("strip_line_breaks: Invalid type, expected string".into()); + } +} + +pub fn remove_extension(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(filename) = piped_arg { + let mut parts: Vec<_> = filename.split(".").collect(); + parts.pop(); + let filename = parts.join("."); + return Ok(Value::String(filename)); + } else { + return Err("remove_extension: Invalid type, expected string".into()); + } +} + +pub fn b64encode(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(data) = piped_arg { + let encoded_data = base64::encode(&data); + return Ok(Value::String(encoded_data)); + } else { + return Err("b64encode: Invalid type, expected string".into()); + } +} + +pub fn b64decode(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(data) = piped_arg { + return base64::decode(&data) + .map_err(|e| format!("b64decode: decoding error : {}", e).into()) + .and_then(|decoded_data| { + String::from_utf8(decoded_data) + .map(|decode_data| Value::String(decode_data)) + .map_err(|e| format!("b64decode: utf8 decoding error : {}", e).into()) + }); + } else { + return Err("b64decode: Invalid type, expected string".into()); + } +} + +pub fn str(piped_arg: Value, _: HashMap) -> Result { + return Ok(Value::String(piped_arg.to_string())); +} + +pub fn from_json(piped_arg: Value, _: HashMap) -> Result { + if let Value::String(data) = piped_arg { + let value = data + .parse::() + .expect(&format!("from_json: error parsing json : {}", data)); + return Ok(value); + } else { + return Err("from_json: Invalid type, expected string".into()); + } +} diff --git a/src/functions.rs b/src/functions.rs new file mode 100644 index 0000000..7afdac8 --- /dev/null +++ b/src/functions.rs @@ -0,0 +1,51 @@ +use crate::inners::exec_cmd; +use std::collections::HashMap; +use std::process::Command; +use tera::{Error, Result, Value}; + +pub fn bash(args: HashMap) -> Result { + let command = if let Some(Value::String(command)) = args.get("command") { + command + } else { + return Err("bash: Invalid type for arg command, expected string".into()); + }; + + let mut bash_cmd = Command::new("bash"); + bash_cmd.arg("-c").arg(command); + + return exec_cmd(&mut bash_cmd, command, &args); +} + +pub fn tab_all_lines(args: HashMap) -> Result { + if let Some(Value::String(lines)) = args.get("lines") { + if let Some(Value::Number(num_spaces)) = args.get("num_spaces") { + let num_spaces = num_spaces.as_u64().ok_or(Error::from( + "tab_all_lines: Error number of spaces is not unsigned integer", + ))? as usize; + let spaces = " ".repeat(num_spaces); + let lines: Vec<_> = lines.split("\n").map(|line| spaces.clone() + line).collect(); + return Ok(Value::String(lines.join("\n"))); + } else { + return Err("tab_all_lines: Invalid type for arg num_spaces, expected number".into()); + } + } else { + return Err("tab_all_lines: Invalid type for arg lines, expected string".into()); + } +} + +pub fn str(args: HashMap) -> Result { + return Ok(Value::String( + args.get("value").expect("str: expected value argument").to_string(), + )); +} + +pub fn from_json(args: HashMap) -> Result { + let value = args + .get("value") + .expect("from_json: expected value argument") + .to_string(); + let value = value + .parse::() + .expect(&format!("from_json: error parsing json : {}", value)); + return Ok(value); +} diff --git a/src/inners.rs b/src/inners.rs new file mode 100644 index 0000000..a3f1ac1 --- /dev/null +++ b/src/inners.rs @@ -0,0 +1,25 @@ +use std::collections::HashMap; +use std::process::Command; +use tera::{Result, Value}; + +pub fn exec_cmd(command: &mut Command, cmd_str: &String, env: &HashMap) -> Result { + for (k, v) in env.iter() { + let value = if let Value::String(data) = v { + data + } else { + return Err("Invalid type for args, expected string".into()); + }; + command.env(k, value); + } + let out = command + .output() + .expect(&format!("Error executing command : {}", cmd_str)); + + let stdout = String::from_utf8(out.stdout).expect(&format!("bash: Error reading stdout of command {}", cmd_str)); + let stderr = String::from_utf8(out.stderr).expect(&format!("bash: Error reading stderr of command {}", cmd_str)); + if stderr != "" { + eprintln!("command {} stderr : {}", cmd_str, stderr); + } + + return Ok(Value::String(stdout)); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e8369e3 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,170 @@ +#![feature(or_patterns)] + +use serde_json; +use serde_yaml; +use std::ffi::OsStr; +use std::io::Write; +use std::process::exit; +use std::{ + collections::HashMap, + env, fs, + io::{self, Read}, + path::Path, +}; +use tera::{Context, Tera}; + +mod filters; +mod functions; +mod inners; +mod testers; + +pub fn help() { + println!( + " +renderman [opts] + --stdin -i [json,yaml,hcl,tfvars,template] read from stdin context or template + --out [file_path] output file for rendered template, default stdout + --env -e load env vars in ctx + --ctx -c [file_path] context files to be loaded in context, multiple files allowed, default empty + --template -t [file_path] template to be rendered, default empty + --help shows this help + " + ) +} + +pub fn parse_args() -> (String, Option, Context) { + let mut args = env::args().collect::>(); + args.reverse(); + + let mut template = String::new(); + let mut context = Context::new(); + let mut out = None; + + args.pop(); // binary name + + while let Some(arg) = args.pop() { + match arg.as_str() { + "--out" | "-o" => { + let filepath = args + .pop() + .expect("error specified --out/-o flag but not file path provided"); + out = Some(filepath); + } + "--stdin" | "-i" => { + let format = args + .pop() + .expect("error specified --stdin/-i flag but not format provided"); + let mut data = String::new(); + io::stdin().read_to_string(&mut data).expect("Error readinf from stdin"); + if format == "template" { + template = data + } else { + populate_ctx(&mut context, format, data); + } + } + "--env" | "-e" => { + let env_vars = env::vars().collect::>(); + for (k, v) in env_vars.iter() { + context.insert(k, v); + } + } + "--ctx" | "-c" => { + let path = args + .pop() + .expect("error specified --ctx/-c flag but not context file path provided"); + let extension = Path::new(&path) + .extension() + .and_then(OsStr::to_str) + .expect("Error no extension found in ctx file"); + let data = fs::read_to_string(&path).expect(&format!("Error reading context file {}", path)); + + populate_ctx(&mut context, extension.to_string(), data); + } + "--template" | "-t" => { + let path = args + .pop() + .expect("error specified --template/-t flag but not template path provided"); + template = fs::read_to_string(path).expect("Error reading template") + } + "--help" | "help" | "-h" => { + help(); + exit(0); + } + _ => panic!("Error argument {} not recognized", arg), + } + } + return (template, out, context); +} + +pub fn populate_ctx(context: &mut Context, format: String, data: String) { + match format.as_ref() { + "yaml" | "yml" => { + let value: serde_yaml::Value = serde_yaml::from_str(&data).expect("Error parsing yaml"); + let object = value.as_mapping().expect("Error expected object in root of yaml file"); + for (k, v) in object.iter() { + let k = k.as_str().expect("Error decoding key of yaml, key is not a string"); + context.insert(k, v); + } + } + "json" => { + let value = data.parse::().expect("Error parsing json"); + let object = value.as_object().expect("Error expected object in root of json file"); + for (k, v) in object.iter() { + context.insert(k, v); + } + } + "toml" | "tml" => { + let value = data.parse::().expect("Error parsing toml"); + let object = value.as_table().expect("Error expected object in root of toml file"); + for (k, v) in object.iter() { + context.insert(k, v); + } + } + "hcl" | "tfvars" | "tf" => panic!("Format not already supported"), + _ => panic!("Format {} not recognized", format), + } +} + +pub fn main() -> std::result::Result<(), String> { + let (template, out, context) = parse_args(); + + let mut tera = Tera::default(); + tera.add_raw_template("template", &template) + .expect("Error loading template in engine"); + + tera.register_filter("bash", filters::bash); + tera.register_filter("sed", filters::sed); + tera.register_filter("glob", filters::file_glob); + tera.register_filter("read_file", filters::read_file); + tera.register_filter("file_name", filters::file_name); + tera.register_filter("file_dir", filters::file_dir); + tera.register_filter("strip_line_breaks", filters::strip_line_breaks); + tera.register_filter("remove_extension", filters::remove_extension); + tera.register_filter("b64decode", filters::b64decode); + tera.register_filter("b64encode", filters::b64encode); + tera.register_filter("str", filters::str); + tera.register_filter("to_json", filters::str); + tera.register_filter("from_json", filters::from_json); + + tera.register_function("tab_all_lines", Box::new(functions::tab_all_lines)); + tera.register_function("bash", Box::new(functions::bash)); + tera.register_function("str", Box::new(functions::str)); + tera.register_function("to_json", Box::new(functions::str)); + tera.register_function("from_json", Box::new(functions::from_json)); + + tera.register_tester("file", testers::is_file); + tera.register_tester("directory", testers::is_directory); + + let rendered = tera.render("template", &context).expect("Error rendering template"); + + if let Some(filepath) = out { + let mut file = fs::File::create(&filepath).expect("Error creating output file"); + file.write_all(rendered.as_ref()).expect("Error writing to output file"); + } else { + io::stdout() + .write_all(rendered.as_ref()) + .expect("Error writing to stdout"); + } + + Ok(()) +} diff --git a/src/testers.rs b/src/testers.rs new file mode 100644 index 0000000..0b29db3 --- /dev/null +++ b/src/testers.rs @@ -0,0 +1,20 @@ +use std::path::Path; +use tera::{Result, Value}; + +pub fn is_file(value: Option, _: Vec) -> Result { + if let Some(Value::String(path)) = value { + let path = Path::new(&path); + return Ok(path.is_file()); + } else { + return Err("is_file: Invalid type, expected string".into()); + } +} + +pub fn is_directory(value: Option, _: Vec) -> Result { + if let Some(Value::String(path)) = value { + let path = Path::new(&path); + return Ok(path.is_dir()); + } else { + return Err("is_directory: Invalid type, expected string".into()); + } +}