diff --git a/Cargo.lock b/Cargo.lock index 42da972..fb1e821 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,7 +64,7 @@ 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)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -96,6 +96,16 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bzip2" version = "0.3.3" @@ -110,7 +120,7 @@ name = "bzip2-sys" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -125,8 +135,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.41" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cfg-if" @@ -171,7 +185,7 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -179,6 +193,46 @@ name = "constant_time_eq" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cookie" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cookie_store" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "publicsuffix 1.5.3 (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)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crc32fast" version = "1.2.0" @@ -187,6 +241,36 @@ dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.6.6" @@ -221,9 +305,31 @@ name = "dtoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "encoding_rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (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.37 (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 = "espanso" -version = "0.1.2" +version = "0.2.0" dependencies = [ "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -231,16 +337,19 @@ dependencies = [ "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.20 (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)", "simplelog 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -275,6 +384,24 @@ dependencies = [ "miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fnv" +version = "1.0.6" +source = "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 = "fs2" version = "0.4.3" @@ -289,6 +416,34 @@ name = "fuchsia-cprng" 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.1.0 (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.29" +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.29 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "getrandom" version = "0.1.12" @@ -299,11 +454,162 @@ dependencies = [ "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "git2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (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.49 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "h2" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http-body" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.12.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-tls" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (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 = "idna" +version = "0.2.0" +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 = "indexmap" +version = "1.2.0" +source = "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.62 (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.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "jobserver" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -314,11 +620,57 @@ name = "libc" version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libgit2-sys" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libssh2-sys 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libz-sys" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.7 (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 = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.8" @@ -336,11 +688,38 @@ dependencies = [ "log 0.4.8 (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 = "memoffset" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mime" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "mime_guess" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miniz_oxide" version = "0.3.2" @@ -349,6 +728,61 @@ dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio" +version = "0.6.19" +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)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (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.33 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "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.33 (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.2.3" +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)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.24 (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.49 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nodrop" version = "0.1.13" @@ -371,6 +805,88 @@ dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num_cpus" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl" +version = "0.10.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl-sys" +version = "0.9.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "owning_ref" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (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 = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pkg-config" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "podio" version = "0.1.6" @@ -397,6 +913,18 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "publicsuffix" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.6.13" @@ -413,6 +941,24 @@ dependencies = [ "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.7.0" @@ -425,6 +971,15 @@ dependencies = [ "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_chacha" version = "0.2.1" @@ -455,6 +1010,14 @@ dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -463,6 +1026,24 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_os" version = "0.1.3" @@ -476,6 +1057,23 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -524,6 +1122,39 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "reqwest" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (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_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rust-argon2" version = "0.5.1" @@ -539,11 +1170,78 @@ name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (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 = "same-file" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "schannel" +version = "0.1.16" +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)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "security-framework" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.99" @@ -572,6 +1270,17 @@ dependencies = [ "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_urlencoded" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_yaml" version = "0.8.9" @@ -593,6 +1302,29 @@ dependencies = [ "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "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 = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "string" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.8.0" @@ -677,6 +1409,166 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-buf" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "try-lock" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "try_from" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicase" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (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-width" version = "0.1.6" @@ -692,11 +1584,69 @@ name = "unicode-xid" version = "0.2.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 = "url" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vcpkg" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "want" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wasi" version = "0.7.0" @@ -707,6 +1657,11 @@ name = "widestring" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.8" @@ -716,16 +1671,46 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (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.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (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 = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (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.4.3" @@ -760,65 +1745,141 @@ dependencies = [ "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" "checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" +"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" +"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" +"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" +"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)" = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9" +"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaffba6388640136149e18ed080b77a78611c1e1d6de75aedcdf78df5d4682" +"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"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 fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"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.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum git2 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39f27186fbb5ec67ece9a56990292bc5aed3c3fc51b9b07b0b52446b1dfb4a82" +"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" +"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" +"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" +"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +"checksum hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" +"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" +"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "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 libgit2-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a30f8637eb59616ee3b8a00f6adff781ee4ddd8343a615b8238de756060cc1b3" +"checksum libssh2-sys 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8914d10b159fc288f2b6f253c94bd0c15a777fd5a297691141d89674b87e66fd" +"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" +"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef" +"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 memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" +"checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf" +"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" "checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10" +"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "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 num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15" +"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +"checksum openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fad9e54bd23bd4cbbe48fdc08a1b8091707ac869ef8508edea2fec77dcc884" +"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" "checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" +"checksum publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0f6d896143a583047512e59ac54a215cb203c29cc941917343edea3be8df9c78" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" +"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" +"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" "checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" "checksum simplelog 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe8c881061cce7ee205784634eda7a61922925e7cc2833188467d3a560e027" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" @@ -828,14 +1889,41 @@ dependencies = [ "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "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 tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" +"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" +"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" +"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac" +"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" +"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" +"checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19" +"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" +"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" +"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" +"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-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" "checksum zip 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3c21bb410afa2bd823a047f5bda3adb62f51074ac7e06263b2c97ecdd47e9fc6" diff --git a/Cargo.toml b/Cargo.toml index 96badaa..297d585 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "espanso" -version = "0.1.2" +version = "0.2.0" authors = ["Federico Terzi "] license = "GPL-3.0" description = "Cross-platform Text Expander written in Rust" @@ -25,12 +25,13 @@ log-panics = {version = "2.0.0", features = ["with-backtrace"]} backtrace = "0.3.37" chrono = "0.4.9" lazy_static = "1.4.0" +walkdir = "2.2.9" +reqwest = "0.9.20" +git2 = {version = "0.10.1", features = ["https"]} +tempfile = "3.1.0" [target.'cfg(unix)'.dependencies] libc = "0.2.62" -[dev-dependencies] -tempfile = "3.1.0" - [build-dependencies] cmake = "0.1.31" \ No newline at end of file diff --git a/src/config/mod.rs b/src/config/mod.rs index 4b7f686..9ae30fd 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -26,20 +26,24 @@ use std::fs::{File, create_dir_all}; use std::io::Read; use serde::{Serialize, Deserialize}; use crate::event::KeyModifier; -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; use log::{error}; use std::fmt; use std::error::Error; +use walkdir::WalkDir; pub(crate) mod runtime; // TODO: add documentation link -const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("../res/config.yaml"); +const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("../res/config.yml"); -const DEFAULT_CONFIG_FILE_NAME : &str = "default.yaml"; +const DEFAULT_CONFIG_FILE_NAME : &str = "default.yml"; +const USER_CONFIGS_FOLDER_NAME: &str = "user"; +const PACKAGES_FOLDER_NAME : &str = "packages"; // Default values for primitives fn default_name() -> String{ "default".to_owned() } +fn default_parent() -> String{ "self".to_owned() } fn default_filter_title() -> String{ "".to_owned() } fn default_filter_class() -> String{ "".to_owned() } fn default_filter_exec() -> String{ "".to_owned() } @@ -50,7 +54,7 @@ fn default_use_system_agent() -> bool { true } fn default_config_caching_interval() -> i32 { 800 } fn default_toggle_interval() -> u32 { 230 } fn default_backspace_limit() -> i32 { 3 } -fn default_exclude_parent_matches() -> bool {false} +fn default_exclude_default_matches() -> bool {false} fn default_matches() -> Vec { Vec::new() } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -58,6 +62,9 @@ pub struct Configs { #[serde(default = "default_name")] pub name: String, + #[serde(default = "default_parent")] + pub parent: String, + #[serde(default = "default_filter_title")] pub filter_title: String, @@ -94,8 +101,8 @@ pub struct Configs { #[serde(default)] pub backend: BackendType, - #[serde(default = "default_exclude_parent_matches")] - pub exclude_parent_matches: bool, + #[serde(default = "default_exclude_default_matches")] + pub exclude_default_matches: bool, #[serde(default = "default_matches")] pub matches: Vec @@ -110,7 +117,7 @@ macro_rules! validate_field { if field_name.starts_with("self.") { field_name = &field_name[5..]; // Remove the 'self.' prefix } - error!("Validation error, parameter '{}' is reserved and can be only used in the default.yaml config file", field_name); + error!("Validation error, parameter '{}' is reserved and can be only used in the default.yml config file", field_name); $result = false; } }; @@ -119,10 +126,10 @@ macro_rules! validate_field { impl Configs { /* * Validate the Config instance. - * It makes sure that app-specific config instances do not define + * It makes sure that user defined config instances do not define * attributes reserved to the default config. */ - fn validate_specific_config(&self) -> bool { + fn validate_user_defined_config(&self) -> bool { let mut result = true; validate_field!(result, self.config_caching_interval, default_config_caching_interval()); @@ -171,6 +178,32 @@ impl Configs { Err(ConfigLoadError::FileNotFound) } } + + fn merge_config(&mut self, new_config: Configs) { + let mut merged_matches = new_config.matches; + let mut trigger_set = HashSet::new(); + merged_matches.iter().for_each(|m| { + trigger_set.insert(m.trigger.clone()); + }); + let parent_matches : Vec = self.matches.iter().filter(|&m| { + !trigger_set.contains(&m.trigger) + }).map(|m| m.clone()).collect(); + + merged_matches.extend(parent_matches); + self.matches = merged_matches; + } + + fn merge_default(&mut self, default: &Configs) { + let mut trigger_set = HashSet::new(); + self.matches.iter().for_each(|m| { + trigger_set.insert(m.trigger.clone()); + }); + let default_matches : Vec = default.matches.iter().filter(|&m| { + !trigger_set.contains(&m.trigger) + }).map(|m| m.clone()).collect(); + + self.matches.extend(default_matches); + } } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -185,70 +218,86 @@ impl ConfigSet { return Err(ConfigLoadError::InvalidConfigDirectory) } + // Load default configuration let default_file = dir_path.join(DEFAULT_CONFIG_FILE_NAME); let default = Configs::load_config(default_file.as_path())?; - let mut specific = Vec::new(); + // Analyze which config files has to be loaded - // Used to make sure no duplicates are present - let mut name_set = HashSet::new(); + let mut target_files = Vec::new(); - let dir_entry = fs::read_dir(dir_path); - if dir_entry.is_err() { - return Err(ConfigLoadError::UnableToReadFile) + let specific_dir = dir_path.join(USER_CONFIGS_FOLDER_NAME); + if specific_dir.exists() { + let dir_entry = WalkDir::new(specific_dir); + target_files.extend(dir_entry); } - let dir_entry = dir_entry.unwrap(); - for entry in dir_entry { - let entry = entry; + let package_dir = dir_path.join(PACKAGES_FOLDER_NAME); + if package_dir.exists() { + let dir_entry = WalkDir::new(package_dir); + target_files.extend(dir_entry); + } + + // Load the user defined config files + + let mut name_set = HashSet::new(); + let mut children_map: HashMap> = HashMap::new(); + let mut root_configs = Vec::new(); + root_configs.push(default); + + for entry in target_files { if let Ok(entry) = entry { let path = entry.path(); - // Skip the default one, already loaded - if path.file_name().unwrap_or("".as_ref()) == "default.yaml" { - continue; - } - // Skip non-yaml config files - if path.extension().unwrap_or_default().to_str().unwrap_or_default() != "yaml" { + if path.extension().unwrap_or_default().to_str().unwrap_or_default() != "yml" { continue; } - let mut config = Configs::load_config(path.as_path())?; + let mut config = Configs::load_config(&path)?; - if !config.validate_specific_config() { + // Make sure the config does not contain reserved fields + if !config.validate_user_defined_config() { return Err(ConfigLoadError::InvalidParameter(path.to_owned())) } + // No name specified, defaulting to the path name if config.name == "default" { - return Err(ConfigLoadError::MissingName(path.to_owned())); + config.name = path.to_str().unwrap_or_default().to_owned(); } if name_set.contains(&config.name) { return Err(ConfigLoadError::NameDuplicate(path.to_owned())); } - // Compute new match set, merging the parent's matches. - // Note: if an app-specific redefines a trigger already present in the - // default config, the latter gets overwritten. - if !config.exclude_parent_matches { - let mut merged_matches = config.matches.clone(); - let mut trigger_set = HashSet::new(); - merged_matches.iter().for_each(|m| { - trigger_set.insert(m.trigger.clone()); - }); - let parent_matches : Vec = default.matches.iter().filter(|&m| { - !trigger_set.contains(&m.trigger) - }).map(|m| m.clone()).collect(); - - merged_matches.extend(parent_matches); - config.matches = merged_matches; - } - - // TODO: check if it contains at least a filter, and warn the user about the problem - name_set.insert(config.name.clone()); - specific.push(config); + + if config.parent == "self" { // No parent, root config + root_configs.push(config); + }else{ // Children config + let children_vec = children_map.entry(config.parent.clone()).or_default(); + children_vec.push(config); + } + }else{ + eprintln!("Warning: Unable to read config file: {}", entry.unwrap_err()) + } + } + + // Merge the children config files + let mut configs = Vec::new(); + for root_config in root_configs { + let config = ConfigSet::reduce_configs(root_config, &children_map); + configs.push(config); + } + + // Separate default from specific + let default= configs.get(0).unwrap().clone(); + let mut specific = (&configs[1..]).to_vec().clone(); + + // Add default matches to specific configs when needed + for config in specific.iter_mut() { + if !config.exclude_default_matches { + config.merge_default(&default); } } @@ -258,31 +307,70 @@ impl ConfigSet { }) } - pub fn load_default() -> Result { - let res = dirs::home_dir(); - if let Some(home_dir) = res { - let espanso_dir = home_dir.join(".espanso"); - - // Create the espanso dir if id doesn't exist - let res = create_dir_all(espanso_dir.as_path()); - - if let Ok(_) = res { - let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME); - - // If config file does not exist, create one from template - if !default_file.exists() { - let result = fs::write(&default_file, DEFAULT_CONFIG_FILE_CONTENT); - if result.is_err() { - return Err(ConfigLoadError::UnableToCreateDefaultConfig) - } - } - - return ConfigSet::load(espanso_dir.as_path()) + fn reduce_configs(target: Configs, children_map: &HashMap>) -> Configs { + if children_map.contains_key(&target.name) { + let mut target = target; + for children in children_map.get(&target.name).unwrap() { + let children = Self::reduce_configs(children.clone(), children_map); + target.merge_config(children); } + target + }else{ + target + } + } + + pub fn load_default() -> Result { + let espanso_dir = ConfigSet::get_default_config_dir(); + + // Create the espanso dir if id doesn't exist + let res = create_dir_all(espanso_dir.as_path()); + + if let Ok(_) = res { + let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME); + + // If config file does not exist, create one from template + if !default_file.exists() { + let result = fs::write(&default_file, DEFAULT_CONFIG_FILE_CONTENT); + if result.is_err() { + return Err(ConfigLoadError::UnableToCreateDefaultConfig) + } + } + + // Create auxiliary directories + + let user_config_dir = espanso_dir.join(USER_CONFIGS_FOLDER_NAME); + if !user_config_dir.exists() { + let res = create_dir_all(user_config_dir.as_path()); + if res.is_err() { + return Err(ConfigLoadError::UnableToCreateDefaultConfig) + } + } + + let packages_dir = espanso_dir.join(PACKAGES_FOLDER_NAME); + if !packages_dir.exists() { + let res = create_dir_all(packages_dir.as_path()); + if res.is_err() { + return Err(ConfigLoadError::UnableToCreateDefaultConfig) + } + } + + return ConfigSet::load(espanso_dir.as_path()) } return Err(ConfigLoadError::UnableToCreateDefaultConfig) } + + pub fn get_default_config_dir() -> PathBuf { + let home_dir = dirs::home_dir().expect("Unable to get home directory"); + let espanso_dir = home_dir.join(".espanso"); + espanso_dir + } + + pub fn get_default_packages_dir() -> PathBuf { + let espanso_dir = ConfigSet::get_default_config_dir(); + espanso_dir.join(PACKAGES_FOLDER_NAME) + } } pub trait ConfigManager<'a> { @@ -299,7 +387,6 @@ pub enum ConfigLoadError { InvalidYAML(PathBuf, String), InvalidConfigDirectory, InvalidParameter(PathBuf), - MissingName(PathBuf), NameDuplicate(PathBuf), UnableToCreateDefaultConfig, } @@ -311,8 +398,7 @@ impl fmt::Display for ConfigLoadError { ConfigLoadError::UnableToReadFile => write!(f, "Unable to read config file"), ConfigLoadError::InvalidYAML(path, e) => write!(f, "Error parsing YAML file '{}', invalid syntax: {}", path.to_str().unwrap_or_default(), e), ConfigLoadError::InvalidConfigDirectory => write!(f, "Invalid config directory"), - ConfigLoadError::InvalidParameter(path) => write!(f, "Invalid parameter in '{}', use of reserved parameters in app-specific configs is not permitted", path.to_str().unwrap_or_default()), - ConfigLoadError::MissingName(path) => write!(f, "The 'name' field is required in app-specific configurations, but it's missing in '{}'", path.to_str().unwrap_or_default()), + ConfigLoadError::InvalidParameter(path) => write!(f, "Invalid parameter in '{}', use of reserved parameters in used defined configs is not permitted", path.to_str().unwrap_or_default()), ConfigLoadError::NameDuplicate(path) => write!(f, "Found duplicate 'name' in '{}', please use different names", path.to_str().unwrap_or_default()), ConfigLoadError::UnableToCreateDefaultConfig => write!(f, "Could not generate default config file"), } @@ -326,8 +412,7 @@ impl Error for ConfigLoadError { ConfigLoadError::UnableToReadFile => "Unable to read config file", ConfigLoadError::InvalidYAML(_, _) => "Error parsing YAML file, invalid syntax", ConfigLoadError::InvalidConfigDirectory => "Invalid config directory", - ConfigLoadError::InvalidParameter(_) => "Invalid parameter, use of reserved parameters in app-specific configs is not permitted", - ConfigLoadError::MissingName(_) => "The 'name' field is required in app-specific configurations, but it's missing", + ConfigLoadError::InvalidParameter(_) => "Invalid parameter, use of reserved parameters in user defined configs is not permitted", ConfigLoadError::NameDuplicate(_) => "Found duplicate 'name' in some configurations, please use different names", ConfigLoadError::UnableToCreateDefaultConfig => "Could not generate default config file", } @@ -343,8 +428,8 @@ mod tests { use tempfile::{NamedTempFile, TempDir}; use std::any::Any; - const TEST_WORKING_CONFIG_FILE : &str = include_str!("../res/test/working_config.yaml"); - const TEST_CONFIG_FILE_WITH_BAD_YAML : &str = include_str!("../res/test/config_with_bad_yaml.yaml"); + const TEST_WORKING_CONFIG_FILE : &str = include_str!("../res/test/working_config.yml"); + const TEST_CONFIG_FILE_WITH_BAD_YAML : &str = include_str!("../res/test/config_with_bad_yaml.yml"); // Test Configs @@ -397,18 +482,18 @@ mod tests { } #[test] - fn test_specific_config_does_not_have_reserved_fields() { + fn test_user_defined_config_does_not_have_reserved_fields() { let working_config_file = create_tmp_file(r###" backend: Clipboard "###); let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), true); + assert_eq!(config.unwrap().validate_user_defined_config(), true); } #[test] - fn test_specific_config_has_reserved_fields_config_caching_interval() { + fn test_user_defined_config_has_reserved_fields_config_caching_interval() { let working_config_file = create_tmp_file(r###" # This should not happen in an app-specific config @@ -416,11 +501,11 @@ mod tests { "###); let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); + assert_eq!(config.unwrap().validate_user_defined_config(), false); } #[test] - fn test_specific_config_has_reserved_fields_toggle_key() { + fn test_user_defined_config_has_reserved_fields_toggle_key() { let working_config_file = create_tmp_file(r###" # This should not happen in an app-specific config @@ -428,11 +513,11 @@ mod tests { "###); let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); + assert_eq!(config.unwrap().validate_user_defined_config(), false); } #[test] - fn test_specific_config_has_reserved_fields_toggle_interval() { + fn test_user_defined_config_has_reserved_fields_toggle_interval() { let working_config_file = create_tmp_file(r###" # This should not happen in an app-specific config @@ -440,11 +525,11 @@ mod tests { "###); let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); + assert_eq!(config.unwrap().validate_user_defined_config(), false); } #[test] - fn test_specific_config_has_reserved_fields_backspace_limit() { + fn test_user_defined_config_has_reserved_fields_backspace_limit() { let working_config_file = create_tmp_file(r###" # This should not happen in an app-specific config @@ -452,7 +537,7 @@ mod tests { "###); let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); + assert_eq!(config.unwrap().validate_user_defined_config(), false); } #[test] @@ -516,59 +601,80 @@ mod tests { let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); fs::write(default_path, DEFAULT_CONFIG_FILE_CONTENT); - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" config_caching_interval: 10000 "###); + let user_defined_path_copy = user_defined_path.clone(); let config_set = ConfigSet::load(tmp_dir.path()); assert!(config_set.is_err()); - assert_eq!(config_set.unwrap_err(), ConfigLoadError::InvalidParameter(specific_path_copy)) + assert_eq!(config_set.unwrap_err(), ConfigLoadError::InvalidParameter(user_defined_path_copy)) } #[test] - fn test_config_set_specific_file_missing_name() { + fn test_config_set_specific_file_missing_name_auto_generated() { let tmp_dir = TempDir::new().expect("unable to create temp directory"); let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); fs::write(default_path, DEFAULT_CONFIG_FILE_CONTENT); - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" backend: Clipboard "###); + let user_defined_path_copy = user_defined_path.clone(); let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_err()); - assert_eq!(config_set.unwrap_err(), ConfigLoadError::MissingName(specific_path_copy)) + assert!(config_set.is_ok()); + assert_eq!(config_set.unwrap().specific[0].name, user_defined_path_copy.to_str().unwrap_or_default()) } pub fn create_temp_espanso_directory() -> TempDir { + create_temp_espanso_directory_with_default_content(DEFAULT_CONFIG_FILE_CONTENT) + } + + pub fn create_temp_espanso_directory_with_default_content(default_content: &str) -> TempDir { let tmp_dir = TempDir::new().expect("unable to create temp directory"); let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, DEFAULT_CONFIG_FILE_CONTENT); + fs::write(default_path, default_content); tmp_dir } - pub fn create_temp_file_in_dir(tmp_dir: &TempDir, name: &str, content: &str) -> PathBuf { - let specific_path = tmp_dir.path().join(name); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, content); + pub fn create_temp_file_in_dir(tmp_dir: &PathBuf, name: &str, content: &str) -> PathBuf { + let user_defined_path = tmp_dir.join(name); + let user_defined_path_copy = user_defined_path.clone(); + fs::write(user_defined_path, content); - specific_path_copy + user_defined_path_copy + } + + pub fn create_user_config_file(tmp_dir: &Path, name: &str, content: &str) -> PathBuf { + let user_config_dir = tmp_dir.join(USER_CONFIGS_FOLDER_NAME); + if !user_config_dir.exists() { + create_dir_all(&user_config_dir); + } + + create_temp_file_in_dir(&user_config_dir, name, content) + } + + pub fn create_package_file(tmp_dir: &Path, package_name: &str, filename: &str, content: &str) -> PathBuf { + let package_config_dir = tmp_dir.join(PACKAGES_FOLDER_NAME); + let package_dir = package_config_dir.join(package_name); + if !package_dir.exists() { + create_dir_all(&package_dir); + } + + create_temp_file_in_dir(&package_dir, filename, content) } #[test] fn test_config_set_specific_file_duplicate_name() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" name: specific1 "###); - let specific_path2 = create_temp_file_in_dir(&tmp_dir, "specific2.yaml", r###" + let user_defined_path2 = create_user_config_file(tmp_dir.path(), "specific2.yml", r###" name: specific1 "###); @@ -578,7 +684,7 @@ mod tests { } #[test] - fn test_specific_config_set_merge_with_parent_matches() { + fn test_user_defined_config_set_merge_with_parent_matches() { let tmp_dir = TempDir::new().expect("unable to create temp directory"); let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); fs::write(default_path, r###" @@ -589,9 +695,7 @@ mod tests { replace: "Bob" "###); - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific1.yml", r###" name: specific1 matches: @@ -609,7 +713,7 @@ mod tests { } #[test] - fn test_specific_config_set_merge_with_parent_matches_child_priority() { + fn test_user_defined_config_set_merge_with_parent_matches_child_priority() { let tmp_dir = TempDir::new().expect("unable to create temp directory"); let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); fs::write(default_path, r###" @@ -620,9 +724,7 @@ mod tests { replace: "Bob" "###); - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" + let user_defined_path2 = create_user_config_file(tmp_dir.path(), "specific2.yml", r###" name: specific1 matches: @@ -639,7 +741,7 @@ mod tests { } #[test] - fn test_specific_config_set_exclude_merge_with_parent_matches() { + fn test_user_defined_config_set_exclude_merge_with_parent_matches() { let tmp_dir = TempDir::new().expect("unable to create temp directory"); let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); fs::write(default_path, r###" @@ -650,12 +752,10 @@ mod tests { replace: "Bob" "###); - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" + let user_defined_path2 = create_user_config_file(tmp_dir.path(), "specific2.yml", r###" name: specific1 - exclude_parent_matches: true + exclude_default_matches: true matches: - trigger: "hello" @@ -681,12 +781,10 @@ mod tests { replace: "Bob" "###); - let specific_path = tmp_dir.path().join("specific.zzz"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" + let user_defined_path2 = create_user_config_file(tmp_dir.path(), "specific.zzz", r###" name: specific1 - exclude_parent_matches: true + exclude_default_matches: true matches: - trigger: "hello" @@ -696,4 +794,196 @@ mod tests { let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); assert_eq!(config_set.specific.len(), 0); } + + #[test] + fn test_config_set_no_parent_configs_works_correctly() { + let tmp_dir = create_temp_espanso_directory(); + + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" + name: specific1 + "###); + + let user_defined_path2 = create_user_config_file(tmp_dir.path(), "specific2.yml", r###" + name: specific2 + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 2); + } + + #[test] + fn test_config_set_default_parent_works_correctly() { + let tmp_dir = create_temp_espanso_directory_with_default_content(r###" + matches: + - trigger: hasta + replace: Hasta la vista + "###); + + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" + parent: default + + matches: + - trigger: "hello" + replace: "world" + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 0); + assert_eq!(config_set.default.matches.len(), 2); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hasta")); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hello")); + } + + #[test] + fn test_config_set_no_parent_should_not_merge() { + let tmp_dir = create_temp_espanso_directory_with_default_content(r###" + matches: + - trigger: hasta + replace: Hasta la vista + "###); + + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" + matches: + - trigger: "hello" + replace: "world" + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 1); + assert_eq!(config_set.default.matches.len(), 1); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hasta")); + assert!(!config_set.default.matches.iter().any(|m| m.trigger == "hello")); + assert!(config_set.specific[0].matches.iter().any(|m| m.trigger == "hello")); + } + + #[test] + fn test_config_set_default_nested_parent_works_correctly() { + let tmp_dir = create_temp_espanso_directory_with_default_content(r###" + matches: + - trigger: hasta + replace: Hasta la vista + "###); + + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" + name: custom1 + parent: default + + matches: + - trigger: "hello" + replace: "world" + "###); + + let user_defined_path2 = create_user_config_file(tmp_dir.path(), "specific2.yml", r###" + parent: custom1 + + matches: + - trigger: "super" + replace: "mario" + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 0); + assert_eq!(config_set.default.matches.len(), 3); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hasta")); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hello")); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "super")); + } + + #[test] + fn test_config_set_parent_merge_children_priority_should_be_higher() { + let tmp_dir = create_temp_espanso_directory_with_default_content(r###" + matches: + - trigger: hasta + replace: Hasta la vista + "###); + + let user_defined_path = create_user_config_file(tmp_dir.path(), "specific.yml", r###" + parent: default + + matches: + - trigger: "hasta" + replace: "world" + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 0); + assert_eq!(config_set.default.matches.len(), 1); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hasta" && m.replace == "world")); + } + + #[test] + fn test_config_set_package_configs_default_merge() { + let tmp_dir = create_temp_espanso_directory_with_default_content(r###" + matches: + - trigger: hasta + replace: Hasta la vista + "###); + + let package_path = create_package_file(tmp_dir.path(), "package1", "package.yml", r###" + parent: default + + matches: + - trigger: "harry" + replace: "potter" + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 0); + assert_eq!(config_set.default.matches.len(), 2); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hasta")); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "harry")); + } + + #[test] + fn test_config_set_package_configs_without_merge() { + let tmp_dir = create_temp_espanso_directory_with_default_content(r###" + matches: + - trigger: hasta + replace: Hasta la vista + "###); + + let package_path = create_package_file(tmp_dir.path(), "package1", "package.yml", r###" + matches: + - trigger: "harry" + replace: "potter" + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 1); + assert_eq!(config_set.default.matches.len(), 1); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hasta")); + assert!(config_set.specific[0].matches.iter().any(|m| m.trigger == "harry")); + } + + #[test] + fn test_config_set_package_configs_multiple_files() { + let tmp_dir = create_temp_espanso_directory_with_default_content(r###" + matches: + - trigger: hasta + replace: Hasta la vista + "###); + + let package_path = create_package_file(tmp_dir.path(), "package1", "package.yml", r###" + name: package1 + + matches: + - trigger: "harry" + replace: "potter" + "###); + + let package_path2 = create_package_file(tmp_dir.path(), "package1", "addon.yml", r###" + parent: package1 + + matches: + - trigger: "ron" + replace: "weasley" + "###); + + let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); + assert_eq!(config_set.specific.len(), 1); + assert_eq!(config_set.default.matches.len(), 1); + assert!(config_set.default.matches.iter().any(|m| m.trigger == "hasta")); + assert!(config_set.specific[0].matches.iter().any(|m| m.trigger == "harry")); + assert!(config_set.specific[0].matches.iter().any(|m| m.trigger == "ron")); + } } \ No newline at end of file diff --git a/src/config/runtime.rs b/src/config/runtime.rs index e817352..3bb0a8b 100644 --- a/src/config/runtime.rs +++ b/src/config/runtime.rs @@ -204,13 +204,12 @@ impl <'a, S: SystemManager> super::ConfigManager<'a> for RuntimeConfigManager<'a #[cfg(test)] mod tests { use super::*; - use std::io::Write; use tempfile::{NamedTempFile, TempDir}; use crate::config::{DEFAULT_CONFIG_FILE_NAME, DEFAULT_CONFIG_FILE_CONTENT}; use std::fs; use std::path::PathBuf; use crate::config::ConfigManager; - use crate::config::tests::{create_temp_espanso_directory, create_temp_file_in_dir}; + use crate::config::tests::{create_temp_espanso_directory, create_temp_file_in_dir, create_user_config_file}; struct DummySystemManager { title: RefCell, @@ -252,18 +251,18 @@ mod tests { fn test_runtime_constructor_regex_load_correctly() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: myname1 filter_exec: "Title" "###); - let specific_path2 = create_temp_file_in_dir(&tmp_dir, "specific2.yaml", r###" + let specific_path2 = create_user_config_file(&tmp_dir.path(), "specific2.yml", r###" name: myname2 filter_title: "Yeah" filter_class: "Car" "###); - let specific_path3 = create_temp_file_in_dir(&tmp_dir, "specific3.yaml", r###" + let specific_path3 = create_user_config_file(&tmp_dir.path(), "specific3.yml", r###" name: myname3 filter_title: "Nice" "###); @@ -303,18 +302,18 @@ mod tests { fn test_runtime_constructor_malformed_regexes_are_ignored() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: myname1 filter_exec: "[`-_]" "###); - let specific_path2 = create_temp_file_in_dir(&tmp_dir, "specific2.yaml", r###" + let specific_path2 = create_user_config_file(&tmp_dir.path(), "specific2.yml", r###" name: myname2 filter_title: "[`-_]" filter_class: "Car" "###); - let specific_path3 = create_temp_file_in_dir(&tmp_dir, "specific3.yaml", r###" + let specific_path3 = create_user_config_file(&tmp_dir.path(), "specific3.yml", r###" name: myname3 filter_title: "Nice" "###); @@ -354,7 +353,7 @@ mod tests { fn test_runtime_calculate_active_config_specific_title_match() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: chrome filter_title: "Chrome" "###); @@ -372,7 +371,7 @@ mod tests { fn test_runtime_calculate_active_config_specific_class_match() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: chrome filter_class: "Chrome" "###); @@ -390,7 +389,7 @@ mod tests { fn test_runtime_calculate_active_config_specific_exec_match() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: chrome filter_exec: "chrome.exe" "###); @@ -408,7 +407,7 @@ mod tests { fn test_runtime_calculate_active_config_specific_multi_filter_match() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: chrome filter_class: Browser filter_exec: "firefox.exe" @@ -428,7 +427,7 @@ mod tests { fn test_runtime_calculate_active_config_no_match() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: firefox filter_title: "Firefox" "###); @@ -447,7 +446,7 @@ mod tests { fn test_runtime_active_config_cache() { let tmp_dir = create_temp_espanso_directory(); - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" + let specific_path = create_user_config_file(&tmp_dir.path(), "specific.yml", r###" name: firefox filter_title: "Firefox" "###); diff --git a/src/main.rs b/src/main.rs index ac5689f..58a8c83 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,27 +43,36 @@ use crate::system::SystemManager; use crate::ui::UIManager; use crate::protocol::*; use std::io::{BufReader, BufRead}; +use crate::package::default::DefaultPackageManager; +use crate::package::{PackageManager, InstallResult, UpdateResult, RemoveResult}; mod ui; mod event; mod check; +mod utils; mod bridge; mod engine; mod config; mod system; -mod sysdaemon; mod context; mod matcher; +mod package; mod keyboard; mod protocol; mod clipboard; mod extension; +mod sysdaemon; const VERSION: &'static str = env!("CARGO_PKG_VERSION"); const LOG_FILE: &str = "espanso.log"; fn main() { - let matches = App::new("espanso") + let install_subcommand = SubCommand::with_name("install") + .about("Install a package. Equivalent to 'espanso package install'") + .arg(Arg::with_name("package_name") + .help("Package name")); + + let mut clap_instance = App::new("espanso") .version(VERSION) .author("Federico Terzi") .about("Cross-platform Text Expander written in Rust") @@ -71,7 +80,7 @@ fn main() { .short("c") .long("config") .value_name("FILE") - .help("Sets a custom config directory. If not specified, reads the default $HOME/.espanso/default.yaml file, creating it if not present.") + .help("Sets a custom config directory. If not specified, reads the default $HOME/.espanso/default.yml file, creating it if not present.") .takes_value(true)) .arg(Arg::with_name("v") .short("v") @@ -108,7 +117,26 @@ fn main() { .about("Restart the espanso daemon.")) .subcommand(SubCommand::with_name("status") .about("Check if the espanso daemon is running or not.")) - .get_matches(); + + // Package manager + .subcommand(SubCommand::with_name("package") + .about("Espanso package manager commands") + .subcommand(install_subcommand.clone()) + .subcommand(SubCommand::with_name("list") + .about("List all installed packages") + .arg(Arg::with_name("full") + .help("Print all package info") + .long("full"))) + .subcommand(SubCommand::with_name("remove") + .about("Remove an installed package") + .arg(Arg::with_name("package_name") + .help("Package name"))) + .subcommand(SubCommand::with_name("refresh") + .about("Update espanso package index")) + ) + .subcommand(install_subcommand); + + let matches = clap_instance.clone().get_matches(); let log_level = matches.occurrences_of("v") as i32; @@ -190,8 +218,32 @@ fn main() { return; } - // Defaults to start subcommand - start_main(config_set); + if let Some(matches) = matches.subcommand_matches("install") { + install_main(config_set, matches); + return; + } + + if let Some(matches) = matches.subcommand_matches("package") { + if let Some(matches) = matches.subcommand_matches("install") { + install_main(config_set, matches); + return; + } + if let Some(matches) = matches.subcommand_matches("remove") { + remove_package_main(config_set, matches); + return; + } + if let Some(matches) = matches.subcommand_matches("list") { + list_package_main(config_set, matches); + return; + } + if let Some(_) = matches.subcommand_matches("refresh") { + update_index_main(config_set); + return; + } + } + + // Defaults help print + clap_instance.print_long_help().expect("Unable to print help"); } /// Daemon subcommand, start the event loop and spawn a background thread worker @@ -547,6 +599,142 @@ fn unregister_main(config_set: ConfigSet) { sysdaemon::unregister(config_set); } +fn install_main(_config_set: ConfigSet, matches: &ArgMatches) { + let package_name = matches.value_of("package_name").unwrap_or_else(|| { + eprintln!("Missing package name!"); + exit(1); + }); + + let mut package_manager = DefaultPackageManager::new_default(); + + if package_manager.is_index_outdated() { + println!("Updating package index..."); + let res = package_manager.update_index(false); + + match res { + Ok(update_result) => { + match update_result { + UpdateResult::NotOutdated => { + eprintln!("Index was already up to date"); + }, + UpdateResult::Updated => { + println!("Index updated!"); + }, + } + }, + Err(e) => { + eprintln!("{}", e); + exit(2); + }, + } + }else{ + println!("Using cached package index, run 'espanso package refresh' to update it.") + } + + let res = package_manager.install_package(package_name); + + match res { + Ok(install_result) => { + match install_result { + InstallResult::NotFoundInIndex => { + eprintln!("Package not found"); + }, + InstallResult::NotFoundInRepo => { + eprintln!("Package not found in repository, are you sure the folder exist in the repo?"); + }, + InstallResult::UnableToParsePackageInfo => { + eprintln!("Unable to parse Package info from README.md"); + }, + InstallResult::MissingPackageVersion => { + eprintln!("Missing package version"); + }, + InstallResult::AlreadyInstalled => { + eprintln!("{} already installed!", package_name); + }, + InstallResult::Installed => { + println!("{} successfully installed!", package_name); + println!(); + println!("You need to restart espanso for changes to take effect, using:"); + println!(" espanso restart"); + }, + } + }, + Err(e) => { + eprintln!("{}", e); + }, + } +} + +fn remove_package_main(_config_set: ConfigSet, matches: &ArgMatches) { + let package_name = matches.value_of("package_name").unwrap_or_else(|| { + eprintln!("Missing package name!"); + exit(1); + }); + + let package_manager = DefaultPackageManager::new_default(); + + let res = package_manager.remove_package(package_name); + + match res { + Ok(remove_result) => { + match remove_result { + RemoveResult::NotFound => { + eprintln!("{} package was not installed.", package_name); + }, + RemoveResult::Removed => { + println!("{} successfully removed!", package_name); + println!(); + println!("You need to restart espanso for changes to take effect, using:"); + println!(" espanso restart"); + }, + } + }, + Err(e) => { + eprintln!("{}", e); + }, + } +} + +fn update_index_main(_config_set: ConfigSet) { + let mut package_manager = DefaultPackageManager::new_default(); + + let res = package_manager.update_index(true); + + match res { + Ok(update_result) => { + match update_result { + UpdateResult::NotOutdated => { + eprintln!("Index was already up to date"); + }, + UpdateResult::Updated => { + println!("Index updated!"); + }, + } + }, + Err(e) => { + eprintln!("{}", e); + exit(2); + }, + } +} + +fn list_package_main(_config_set: ConfigSet, matches: &ArgMatches) { + let package_manager = DefaultPackageManager::new_default(); + + let list = package_manager.list_local_packages(); + + if matches.is_present("full") { + for package in list.iter() { + println!("{:?}", package); + } + }else{ + for package in list.iter() { + println!("{} - {}", package.name, package.version); + } + } +} + + fn acquire_lock() -> Option { let espanso_dir = context::get_data_dir(); let lock_file_path = espanso_dir.join("espanso.lock"); diff --git a/src/package/default.rs b/src/package/default.rs new file mode 100644 index 0000000..96ce792 --- /dev/null +++ b/src/package/default.rs @@ -0,0 +1,597 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +use std::path::{PathBuf, Path}; +use crate::package::{PackageIndex, UpdateResult, Package, InstallResult, RemoveResult}; +use std::error::Error; +use std::fs::{File, create_dir}; +use std::io::{BufReader, BufRead}; +use std::time::{SystemTime, UNIX_EPOCH}; +use crate::package::UpdateResult::{NotOutdated, Updated}; +use crate::package::InstallResult::{NotFoundInIndex, AlreadyInstalled}; +use std::fs; +use tempfile::TempDir; +use git2::Repository; +use regex::Regex; +use crate::package::RemoveResult::Removed; +use std::collections::HashMap; + +const DEFAULT_PACKAGE_INDEX_FILE : &str = "package_index.json"; + +pub struct DefaultPackageManager { + package_dir: PathBuf, + data_dir: PathBuf, + + local_index: Option, +} + +impl DefaultPackageManager { + pub fn new(package_dir: PathBuf, data_dir: PathBuf) -> DefaultPackageManager { + let local_index = Self::load_local_index(&data_dir); + + DefaultPackageManager{ + package_dir, + data_dir, + local_index + } + } + + pub fn new_default() -> DefaultPackageManager { + DefaultPackageManager::new( + crate::config::ConfigSet::get_default_packages_dir(), + crate::context::get_data_dir() + ) + } + + fn get_package_index_path(data_dir: &Path) -> PathBuf { + data_dir.join(DEFAULT_PACKAGE_INDEX_FILE) + } + + fn load_local_index(data_dir: &Path) -> Option { + let local_index_file = File::open(Self::get_package_index_path(data_dir)); + if let Ok(local_index_file) = local_index_file { + let reader = BufReader::new(local_index_file); + let local_index = serde_json::from_reader(reader); + + if let Ok(local_index) = local_index { + return local_index + } + } + + None + } + + fn request_index() -> Result> { + let client = reqwest::Client::new(); + let request = client.get("https://hub.espanso.org/json/") + .header("User-Agent", format!("espanso/{}", crate::VERSION)); + + let mut res = request.send()?; + let body = res.text()?; + let index : PackageIndex = serde_json::from_str(&body)?; + + Ok(index) + } + + fn clone_repo_to_temp(repo_url: &str) -> Result> { + let temp_dir = TempDir::new()?; + let _repo = Repository::clone(repo_url, temp_dir.path())?; + Ok(temp_dir) + } + + fn parse_package_from_readme(readme_path: &Path) -> Option { + lazy_static! { + static ref FIELD_REGEX: Regex = Regex::new(r###"^\s*(.*?)\s*:\s*"?(.*?)"?$"###).unwrap(); + } + + // Read readme line by line + let file = File::open(readme_path); + if let Ok(file) = file { + let reader = BufReader::new(file); + + let mut fields :HashMap = HashMap::new(); + + let mut started = false; + + for (_index, line) in reader.lines().enumerate() { + let line = line.unwrap(); + if line.contains("---") { + if started { + break + }else{ + started = true; + } + }else{ + if started { + let caps = FIELD_REGEX.captures(&line); + if let Some(caps) = caps { + let property = caps.get(1); + let value = caps.get(2); + if property.is_some() && value.is_some() { + fields.insert(property.unwrap().as_str().to_owned(), + value.unwrap().as_str().to_owned()); + } + } + } + } + } + + if !fields.contains_key("package_name") || + !fields.contains_key("package_title") || + !fields.contains_key("package_version") || + !fields.contains_key("package_repo") || + !fields.contains_key("package_desc") || + !fields.contains_key("package_author") { + return None + } + + let package = Package { + name: fields.get("package_name").unwrap().clone(), + title: fields.get("package_title").unwrap().clone(), + version: fields.get("package_version").unwrap().clone(), + repo: fields.get("package_repo").unwrap().clone(), + desc: fields.get("package_desc").unwrap().clone(), + author: fields.get("package_author").unwrap().clone() + }; + + Some(package) + }else{ + None + } + } + + fn local_index_timestamp(&self) -> u64 { + if let Some(local_index) = &self.local_index { + return local_index.last_update + } + + return 0; + } + + fn list_local_packages_names(&self) -> Vec { + let dir = fs::read_dir(&self.package_dir); + let mut output = Vec::new(); + if let Ok(dir) = dir { + for entry in dir { + if let Ok(entry) = entry { + let path = entry.path(); + if path.is_dir() { + let name = path.file_name(); + if let Some(name) = name { + output.push(name.to_str().unwrap().to_owned()) + } + } + } + } + } + + output + } + + fn cache_local_index(&self) { + if let Some(local_index) = &self.local_index { + let serialized = serde_json::to_string(local_index).expect("Unable to serialize local index"); + let local_index_file = self.data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(local_index_file, serialized).expect("Unable to cache local index"); + } + } +} + +impl super::PackageManager for DefaultPackageManager { + fn is_index_outdated(&self) -> bool { + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); + let current_timestamp = current_time.as_secs(); + + let local_index_timestamp = self.local_index_timestamp(); + + // Local index is outdated if older than a day + local_index_timestamp + 60*60*24 < current_timestamp + } + + fn update_index(&mut self, force: bool) -> Result> { + if force || self.is_index_outdated() { + let updated_index = DefaultPackageManager::request_index()?; + self.local_index = Some(updated_index); + + // Save the index to file + self.cache_local_index(); + + Ok(Updated) + }else{ + Ok(NotOutdated) + } + } + + fn get_package(&self, name: &str) -> Option { + if let Some(local_index) = &self.local_index { + let result = local_index.packages.iter().find(|package| { + package.name == name + }); + if let Some(package) = result { + return Some(package.clone()) + } + } + + None + } + + fn install_package(&self, name: &str) -> Result> { + let package = self.get_package(name); + match package { + Some(package) => { + self.install_package_from_repo(name, &package.repo) + }, + None => { + Ok(NotFoundInIndex) + }, + } + } + + fn install_package_from_repo(&self, name: &str, repo_url: &str) -> Result> { + // Check if package is already installed + let packages = self.list_local_packages_names(); + if packages.iter().any(|p| p == name) { // Package already installed + return Ok(AlreadyInstalled); + } + + let temp_dir = Self::clone_repo_to_temp(repo_url)?; + + let temp_package_dir = temp_dir.path().join(name); + if !temp_package_dir.exists() { + return Ok(InstallResult::NotFoundInRepo); + } + + let readme_path = temp_package_dir.join("README.md"); + + let package = Self::parse_package_from_readme(&readme_path); + if !package.is_some() { + return Ok(InstallResult::UnableToParsePackageInfo); // TODO: test + } + let package = package.unwrap(); + + let source_dir = temp_package_dir.join(package.version); + if !source_dir.exists() { + return Ok(InstallResult::MissingPackageVersion); // TODO: test + } + + let target_dir = &self.package_dir.join(name); + create_dir(&target_dir)?; + + crate::utils::copy_dir(&source_dir, target_dir)?; + + let readme_dest = target_dir.join("README.md"); + std::fs::copy(readme_path, readme_dest)?; + + Ok(InstallResult::Installed) + } + + fn remove_package(&self, name: &str) -> Result> { + let package_dir = self.package_dir.join(name); + if !package_dir.exists() { + return Ok(RemoveResult::NotFound); + } + + std::fs::remove_dir_all(package_dir)?; + + Ok(Removed) + } + + fn list_local_packages(&self) -> Vec { + let mut output = Vec::new(); + + let package_names = self.list_local_packages_names(); + + for name in package_names.iter() { + let package_dir = &self.package_dir.join(name); + let readme_file = package_dir.join("README.md"); + let package = Self::parse_package_from_readme(&readme_file); + if let Some(package) = package { + output.push(package); + } + } + + output + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::{TempDir, NamedTempFile}; + use std::path::Path; + use crate::package::PackageManager; + use std::fs::{create_dir, create_dir_all}; + use crate::package::InstallResult::{Installed, NotFoundInRepo}; + use std::io::Write; + + const OUTDATED_INDEX_CONTENT : &str = include_str!("../res/test/outdated_index.json"); + const INDEX_CONTENT_WITHOUT_UPDATE: &str = include_str!("../res/test/index_without_update.json"); + const GET_PACKAGE_INDEX: &str = include_str!("../res/test/get_package_index.json"); + const INSTALL_PACKAGE_INDEX: &str = include_str!("../res/test/install_package_index.json"); + + struct TempPackageManager { + package_dir: TempDir, + data_dir: TempDir, + package_manager: DefaultPackageManager, + } + + fn create_temp_package_manager(setup: F) -> TempPackageManager where F: Fn(&Path, &Path) -> (){ + let package_dir = TempDir::new().expect("unable to create temp directory"); + let data_dir = TempDir::new().expect("unable to create temp directory"); + + setup(package_dir.path(), data_dir.path()); + + let package_manager = DefaultPackageManager::new( + package_dir.path().clone().to_path_buf(), + data_dir.path().clone().to_path_buf() + ); + + TempPackageManager { + package_dir, + data_dir, + package_manager + } + } + + #[test] + fn test_download_index() { + let temp = create_temp_package_manager(|_, _| {}); + let index = DefaultPackageManager::request_index(); + + assert!(index.is_ok()); + assert!(index.unwrap().packages.len() > 0); + } + + #[test] + fn test_outdated_index() { + let temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, OUTDATED_INDEX_CONTENT); + }); + + assert!(temp.package_manager.is_index_outdated()); + } + + #[test] + fn test_up_to_date_index_should_not_be_updated() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); + let current_timestamp = current_time.as_secs(); + let new_contents = INDEX_CONTENT_WITHOUT_UPDATE.replace("XXXX", &format!("{}", current_timestamp)); + std::fs::write(index_file, new_contents); + }); + + assert_eq!(temp.package_manager.update_index(false).unwrap(), UpdateResult::NotOutdated); + } + + #[test] + fn test_up_to_date_index_with_force_should_be_updated() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); + let current_timestamp = current_time.as_secs(); + let new_contents = INDEX_CONTENT_WITHOUT_UPDATE.replace("XXXX", &format!("{}", current_timestamp)); + std::fs::write(index_file, new_contents); + }); + + assert_eq!(temp.package_manager.update_index(true).unwrap(), UpdateResult::Updated); + } + + #[test] + fn test_outdated_index_should_be_updated() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, OUTDATED_INDEX_CONTENT); + }); + + assert_eq!(temp.package_manager.update_index(false).unwrap(), UpdateResult::Updated); + } + + #[test] + fn test_update_index_should_create_file() { + let mut temp = create_temp_package_manager(|_, _| {}); + + assert_eq!(temp.package_manager.update_index(false).unwrap(), UpdateResult::Updated); + assert!(temp.data_dir.path().join(DEFAULT_PACKAGE_INDEX_FILE).exists()) + } + + #[test] + fn test_get_package_should_be_found() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, GET_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.get_package("italian-accents").unwrap().title, "Italian Accents"); + } + + #[test] + fn test_get_package_should_not_be_found() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, GET_PACKAGE_INDEX); + }); + + assert!(temp.package_manager.get_package("not-existing").is_none()); + } + + #[test] + fn test_list_local_packages_names() { + let mut temp = create_temp_package_manager(|package_dir, _| { + create_dir(package_dir.join("package-1")); + create_dir(package_dir.join("package2")); + std::fs::write(package_dir.join("dummyfile.txt"), "test"); + }); + + let packages = temp.package_manager.list_local_packages_names(); + assert_eq!(packages.len(), 2); + assert!(packages.iter().any(|p| p == "package-1")); + assert!(packages.iter().any(|p| p == "package2")); + } + + #[test] + fn test_install_package_not_found() { + let mut temp = create_temp_package_manager(|package_dir, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, INSTALL_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.install_package("doesnotexist").unwrap(), NotFoundInIndex); + } + + #[test] + fn test_install_package_already_installed() { + let mut temp = create_temp_package_manager(|package_dir, data_dir| { + create_dir(package_dir.join("italian-accents")); + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, INSTALL_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.install_package("italian-accents").unwrap(), AlreadyInstalled); + } + + #[test] + fn test_clone_temp_repository() { + let cloned_dir = DefaultPackageManager::clone_repo_to_temp("https://github.com/federico-terzi/espanso-hub-core").unwrap(); + assert!(cloned_dir.path().join("LICENSE").exists()); + } + + #[test] + fn test_install_package() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, INSTALL_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.install_package("dummy-package").unwrap(), Installed); + assert!(temp.package_dir.path().join("dummy-package").exists()); + assert!(temp.package_dir.path().join("dummy-package/README.md").exists()); + assert!(temp.package_dir.path().join("dummy-package/package.yml").exists()); + } + + #[test] + fn test_install_package_does_not_exist_in_repo() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, INSTALL_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.install_package("not-existing").unwrap(), NotFoundInRepo); + } + + #[test] + fn test_list_local_packages() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, INSTALL_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.install_package("dummy-package").unwrap(), Installed); + assert!(temp.package_dir.path().join("dummy-package").exists()); + assert!(temp.package_dir.path().join("dummy-package/README.md").exists()); + assert!(temp.package_dir.path().join("dummy-package/package.yml").exists()); + + let list = temp.package_manager.list_local_packages(); + assert_eq!(list.len(), 1); + assert_eq!(list[0].name, "dummy-package"); + } + + #[test] + fn test_remove_package() { + let mut temp = create_temp_package_manager(|package_dir, _| { + let dummy_package_dir = package_dir.join("dummy-package"); + create_dir_all(&dummy_package_dir); + std::fs::write(dummy_package_dir.join("README.md"), "readme"); + std::fs::write(dummy_package_dir.join("package.yml"), "name: package"); + }); + + assert!(temp.package_dir.path().join("dummy-package").exists()); + assert!(temp.package_dir.path().join("dummy-package/README.md").exists()); + assert!(temp.package_dir.path().join("dummy-package/package.yml").exists()); + assert_eq!(temp.package_manager.remove_package("dummy-package").unwrap(), RemoveResult::Removed); + assert!(!temp.package_dir.path().join("dummy-package").exists()); + assert!(!temp.package_dir.path().join("dummy-package/README.md").exists()); + assert!(!temp.package_dir.path().join("dummy-package/package.yml").exists()); + } + + #[test] + fn test_remove_package_not_found() { + let mut temp = create_temp_package_manager(|_, _| {}); + + assert_eq!(temp.package_manager.remove_package("not-existing").unwrap(), RemoveResult::NotFound); + } + + #[test] + fn test_parse_package_from_readme() { + let file = NamedTempFile::new().unwrap(); + fs::write(file.path(), r###" + --- + package_name: "italian-accents" + package_title: "Italian Accents" + package_desc: "Include Italian accents substitutions to espanso." + package_version: "0.1.0" + package_author: "Federico Terzi" + package_repo: "https://github.com/federico-terzi/espanso-hub-core" + --- + "###); + + let package = DefaultPackageManager::parse_package_from_readme(file.path()).unwrap(); + + let target_package = Package { + name: "italian-accents".to_string(), + title: "Italian Accents".to_string(), + version: "0.1.0".to_string(), + repo: "https://github.com/federico-terzi/espanso-hub-core".to_string(), + desc: "Include Italian accents substitutions to espanso.".to_string(), + author: "Federico Terzi".to_string() + }; + + assert_eq!(package, target_package); + } + + #[test] + fn test_parse_package_from_readme_with_bad_metadata() { + let file = NamedTempFile::new().unwrap(); + fs::write(file.path(), r###" + --- + package_name: italian-accents + package_title: "Italian Accents" + package_desc: "Include Italian accents substitutions to espanso." + package_version:"0.1.0" + package_author:Federico Terzi + package_repo: "https://github.com/federico-terzi/espanso-hub-core" + --- + Readme text + "###); + + let package = DefaultPackageManager::parse_package_from_readme(file.path()).unwrap(); + + let target_package = Package { + name: "italian-accents".to_string(), + title: "Italian Accents".to_string(), + version: "0.1.0".to_string(), + repo: "https://github.com/federico-terzi/espanso-hub-core".to_string(), + desc: "Include Italian accents substitutions to espanso.".to_string(), + author: "Federico Terzi".to_string() + }; + + assert_eq!(package, target_package); + } +} \ No newline at end of file diff --git a/src/package/mod.rs b/src/package/mod.rs new file mode 100644 index 0000000..3ba505d --- /dev/null +++ b/src/package/mod.rs @@ -0,0 +1,77 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +pub(crate) mod default; +use serde::{Serialize, Deserialize}; +use std::error::Error; + +pub trait PackageManager { + fn is_index_outdated(&self) -> bool; + fn update_index(&mut self, force: bool) -> Result>; + + fn get_package(&self, name: &str) -> Option; + + fn install_package(&self, name: &str) -> Result>; + fn install_package_from_repo(&self, name: &str, repo_url: &str) -> Result>; + + fn remove_package(&self, name: &str) -> Result>; + + fn list_local_packages(&self) -> Vec; +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct Package { + pub name: String, + pub title: String, + pub version: String, + pub repo: String, + pub desc: String, + pub author: String +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct PackageIndex { + #[serde(rename = "lastUpdate")] + pub last_update: u64, + + pub packages: Vec +} + + +#[derive(Clone, Debug, PartialEq)] +pub enum UpdateResult { + NotOutdated, + Updated, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum InstallResult { + NotFoundInIndex, + NotFoundInRepo, + UnableToParsePackageInfo, + MissingPackageVersion, + AlreadyInstalled, + Installed +} + +#[derive(Clone, Debug, PartialEq)] +pub enum RemoveResult { + NotFound, + Removed +} \ No newline at end of file diff --git a/src/res/config.yaml b/src/res/config.yml similarity index 50% rename from src/res/config.yaml rename to src/res/config.yml index af10305..7ad3e30 100644 --- a/src/res/config.yaml +++ b/src/res/config.yml @@ -2,7 +2,7 @@ # This is the default configuration file, change it as you like it # You can refer to the official documentation: -# https://github.com/federico-terzi/espanso +# https://espanso.org/docs/ # Matches are the substitution rules, when you type the "trigger" string # it gets replaced by the "replace" string. @@ -27,34 +27,4 @@ matches: - name: output type: shell params: - cmd: "echo Hello from you shell" - - # Emojis - - trigger: ":lol" - replace: "😂" - - trigger: ":llol" - replace: "😂😂😂😂" - - trigger: ":sad" - replace: "☹" - - trigger: ":ssad" - replace: "☹☹☹☹" - - # Accented letters - - trigger: "e''" - replace: "è" - - trigger: "e//" - replace: "é" - - trigger: "a''" - replace: "à" - - trigger: "i''" - replace: "ì" - - trigger: "o''" - replace: "ò" - - trigger: "u''" - replace: "ù" - - # Capital accented letters - - trigger: "E''" - replace: "È" - - trigger: "E//" - replace: "É" \ No newline at end of file + cmd: "echo Hello from your shell" \ No newline at end of file diff --git a/src/res/test/config_with_bad_yaml.yaml b/src/res/test/config_with_bad_yaml.yml similarity index 100% rename from src/res/test/config_with_bad_yaml.yaml rename to src/res/test/config_with_bad_yaml.yml diff --git a/src/res/test/get_package_index.json b/src/res/test/get_package_index.json new file mode 100644 index 0000000..7512f40 --- /dev/null +++ b/src/res/test/get_package_index.json @@ -0,0 +1,27 @@ +{ + "lastUpdate": 1565437389, + "packages": [ + + { + "name": "basic-emojis", + "title": "Basic Emojis", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "A package to include some basic emojis in espanso.", + "author": "Federico Terzi" + + }, + + + { + "name": "italian-accents", + "title": "Italian Accents", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Include Italian accents substitutions to espanso.", + "author": "Federico Terzi" + + } + + +]} \ No newline at end of file diff --git a/src/res/test/index_without_update.json b/src/res/test/index_without_update.json new file mode 100644 index 0000000..4746703 --- /dev/null +++ b/src/res/test/index_without_update.json @@ -0,0 +1,27 @@ +{ + "lastUpdate": XXXX, + "packages": [ + + { + "name": "basic-emojis", + "title": "Basic Emojis", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "A package to include some basic emojis in espanso.", + "author": "Federico Terzi" + + }, + + + { + "name": "italian-accents", + "title": "Italian Accents", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Include Italian accents substitutions to espanso.", + "author": "Federico Terzi" + + } + + +]} \ No newline at end of file diff --git a/src/res/test/install_package_index.json b/src/res/test/install_package_index.json new file mode 100644 index 0000000..df67503 --- /dev/null +++ b/src/res/test/install_package_index.json @@ -0,0 +1,35 @@ +{ + "lastUpdate": 1565437389, + "packages": [ + + { + "name": "dummy-package", + "title": "Dummy Package", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Dummy package", + "author": "Federico Terzi" + + }, + + + { + "name": "italian-accents", + "title": "Italian Accents", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Include Italian accents substitutions to espanso.", + "author": "Federico Terzi" + + }, + + { + "name": "not-existing", + "title": "Not Existing", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Package that does not exist in the repo", + "author": "Federico Terzi" + + } + ]} \ No newline at end of file diff --git a/src/res/test/outdated_index.json b/src/res/test/outdated_index.json new file mode 100644 index 0000000..7512f40 --- /dev/null +++ b/src/res/test/outdated_index.json @@ -0,0 +1,27 @@ +{ + "lastUpdate": 1565437389, + "packages": [ + + { + "name": "basic-emojis", + "title": "Basic Emojis", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "A package to include some basic emojis in espanso.", + "author": "Federico Terzi" + + }, + + + { + "name": "italian-accents", + "title": "Italian Accents", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Include Italian accents substitutions to espanso.", + "author": "Federico Terzi" + + } + + +]} \ No newline at end of file diff --git a/src/res/test/working_config.yaml b/src/res/test/working_config.yml similarity index 100% rename from src/res/test/working_config.yaml rename to src/res/test/working_config.yml diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..ffd9106 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,94 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +use std::path::Path; +use std::error::Error; +use std::fs::create_dir; + +pub fn copy_dir(source_dir: &Path, dest_dir: &Path) -> Result<(), Box> { + for entry in std::fs::read_dir(source_dir)? { + let entry = entry?; + let entry = entry.path(); + if entry.is_dir() { + let name = entry.file_name().expect("Error obtaining the filename"); + let target_dir = dest_dir.join(name); + create_dir(&target_dir)?; + copy_dir(&entry, &target_dir)?; + }else if entry.is_file() { + let target_entry = dest_dir.join(entry.file_name().expect("Error obtaining the filename")); + std::fs::copy(entry, target_entry)?; + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + use std::fs::create_dir; + + #[test] + fn test_copy_dir_into() { + let source_tmp_dir = TempDir::new().expect("Error creating temp directory"); + let dest_tmp_dir = TempDir::new().expect("Error creating temp directory"); + + let source_dir = source_tmp_dir.path().join("source"); + create_dir(&source_dir); + std::fs::write(source_dir.join("file1.txt"), "file1"); + std::fs::write(source_dir.join("file2.txt"), "file2"); + + let target_dir = dest_tmp_dir.path().join("source"); + create_dir(&target_dir); + + copy_dir(&source_dir, &target_dir); + + assert!(dest_tmp_dir.path().join("source").exists()); + assert!(dest_tmp_dir.path().join("source/file1.txt").exists()); + assert!(dest_tmp_dir.path().join("source/file2.txt").exists()); + } + + #[test] + fn test_copy_dir_into_recursive() { + let source_tmp_dir = TempDir::new().expect("Error creating temp directory"); + let dest_tmp_dir = TempDir::new().expect("Error creating temp directory"); + + let source_dir = source_tmp_dir.path().join("source"); + create_dir(&source_dir); + std::fs::write(source_dir.join("file1.txt"), "file1"); + std::fs::write(source_dir.join("file2.txt"), "file2"); + let nested_dir = source_dir.join("nested"); + create_dir(&nested_dir); + std::fs::write(nested_dir.join("nestedfile.txt"), "nestedfile1"); + + let target_dir = dest_tmp_dir.path().join("source"); + create_dir(&target_dir); + + copy_dir(&source_dir, &target_dir); + + assert!(dest_tmp_dir.path().join("source").exists()); + assert!(dest_tmp_dir.path().join("source/file1.txt").exists()); + assert!(dest_tmp_dir.path().join("source/file2.txt").exists()); + + assert!(dest_tmp_dir.path().join("source/nested").exists()); + assert!(dest_tmp_dir.path().join("source/nested/nestedfile.txt").exists()); + } + +} \ No newline at end of file