diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 762758a4c..000000000 --- a/Cargo.lock +++ /dev/null @@ -1,3091 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "aho-corasick" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "antidote" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "approx" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayref" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayvec" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "badge" -version = "0.2.0" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rusttype 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "block-buffer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bodyparser" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "persistent 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "buf_redux" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytes" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bytesize" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cargo" -version = "0.35.0" -source = "git+https://github.com/rust-lang/cargo.git#9f1f786c94468809cf772c4a8e14ffa8e10ebbca" -dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.23.0 (git+https://github.com/rust-lang/cargo.git)", - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "im-rc 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opener 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clap" -version = "2.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "commoncrypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "commoncrypto-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "comrak" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "conduit-mime-types" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "core-foundation" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation" -version = "0.6.2" -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.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation-sys" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (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 = "crates-index-diff" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crates-io" -version = "0.23.0" -source = "git+https://github.com/rust-lang/cargo.git#9f1f786c94468809cf772c4a8e14ffa8e10ebbca" -dependencies = [ - "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cratesfyi" -version = "0.6.0" -dependencies = [ - "badge 0.2.0", - "cargo 0.35.0 (git+https://github.com/rust-lang/cargo.git)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "comrak 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-index-diff 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars-iron 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", - "html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "magic 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "params 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "postgres 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2_postgres 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "sass-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-channel" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crossbeam-utils" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crypto-hash" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crypto-mac" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curl" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl-sys 0.4.15 (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.43 (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.37 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curl-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libnghttp2-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.37 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "digest" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dtoa" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "dtoa" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "encoding_rs" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "entities" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "env_logger" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "error" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fallible-iterator" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "filetime" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "filetime" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.10 (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" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (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 = "futf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "futures" -version = "0.1.25" -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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fwdansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "git2" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (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.37 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "git2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (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.37 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "git2-curl" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "globset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "h2" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.10 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "handlebars" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "handlebars-iron" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "handlebars 0.24.2 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hmac" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "home" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "html5ever" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "http" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (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.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "httparse" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "humantime" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper" -version = "0.10.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper" -version = "0.12.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (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.12 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (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.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.11 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ignore" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "im-rc" -version = "12.2.0" -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)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "indexmap" -version = "1.0.1" -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.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "iron" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "itoa" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itoa" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "jobserver" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazycell" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.43" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libflate" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libgit2-sys" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.37 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libnghttp2-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libssh2-sys" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.37 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libz-sys" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.3.3 (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.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "magic" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "magic-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "magic-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "markup5ever" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tendril 0.4.0 (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 = "md5" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (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 = "memoffset" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime_guess" -version = "1.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime_guess" -version = "2.0.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mime 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz-sys" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio-uds" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (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 = "miow" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "modifier" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "mount" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sequence_trie 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "multipart" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "buf_redux 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 1.8.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "native-tls" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.13 (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.37 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.4 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "nodrop" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-rational" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num_cpus" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "opener" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl" -version = "0.10.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.5 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.37 (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.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ordered-float" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "owning_ref" -version = "0.3.3" -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 = "params" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bodyparser 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "multipart 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "urlencoded 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.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.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (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 = "persistent" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pest" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pest" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pest_derive" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf" -version = "0.7.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_codegen" -version = "0.7.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_generator" -version = "0.7.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_shared" -version = "0.7.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pkg-config" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "plugin" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "postgres" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "postgres-shared 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "postgres-protocol" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "postgres-shared" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "r2d2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "r2d2_postgres" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "postgres 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "postgres-shared 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_syscall" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "reqwest" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "route-recognizer" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "router" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-workspace-hack" -version = "1.0.0" -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 = "rustfix" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rusttype" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "approx 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ryu" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safemem" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safemem" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "same-file" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sass-rs" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "sass-sys 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sass-sys" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "schannel" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "antidote 1.0.0 (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 = "security-framework" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "security-framework-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (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)", - "serde 1.0.84 (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 = "sequence_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "1.0.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_ignored" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_urlencoded" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha2" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "shell-escape" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "siphasher" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slab" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slug" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "smallvec" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "socket2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (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 = "staticfile" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mount 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "stb_truetype" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "string" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "string_cache" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "string_cache_codegen" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "string_cache_shared" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strsim" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.13.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.15.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tar" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempfile" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tendril" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "utf-8 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termcolor" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-uds" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "traitobject" -version = "0.1.0" -source = "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 = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typed-arena" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typemap" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ucd-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicase" -version = "2.2.0" -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.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unidecode" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unsafe-any" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "url" -version = "1.7.1" -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_serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "urlencoded" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bodyparser 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf-8" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "utf8-ranges" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "uuid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "vcpkg" -version = "0.2.6" -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 = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "walkdir" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "walkdir" -version = "2.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "want" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (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 = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (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 = "wincolor" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" -"checksum approx 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f71f10b5c4946a64aad7b8cf65e3406cd3da22fc448595991d22423cf6db67b4" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" -"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" -"checksum bodyparser 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6928e817538b74a73d1dd6e9a942a2a35c632a597b6bb14fd009480f859a6bf5" -"checksum buf_redux 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "861b9d19b9f5cb40647242d10d0cb0a13de0a96d5ff8c8a01ea324fa3956eb7d" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" -"checksum bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0ce55bd354b095246fc34caf4e9e242f5297a7fd938b090cadfea6eee614aa62" -"checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" -"checksum cargo 0.35.0 (git+https://github.com/rust-lang/cargo.git)" = "" -"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" -"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" -"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" -"checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -"checksum comrak 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a9bd60be8877a3343d25b9a3dadbaf7f02f9ac843b54e663ecef73e29e8b9c6b" -"checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" -"checksum core-foundation 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "58667b9a618a37ea8c4c4cb5298703e5dfadcd3698c79f54fc43e6a2e94733ea" -"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum crates-index-diff 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd2579b790a03abb6ffcffbc0d1ac9cb00acd545ef8e5887b464a580131660a" -"checksum crates-io 0.23.0 (git+https://github.com/rust-lang/cargo.git)" = "" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827" -"checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" -"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" -"checksum crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416" -"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" -"checksum crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c55913cc2799171a550e307918c0a360e8c16004820291bf3b638969b4a01816" -"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" -"checksum crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958" -"checksum curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c7c9d851c825e0c033979d4516c9173bc19a78a96eb4d6ae51d4045440eafa16" -"checksum curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "721c204978be2143fab0a84b708c49d79d1f6100b8785610f456043a90708870" -"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" -"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d" -"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" -"checksum encoding_rs 0.8.10 (registry+https://github.com/rust-lang/crates.io-index)" = "065f4d0c826fdaef059ac45487169d918558e3cf86c9d89f6e81cf52369126e5" -"checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" -"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e" -"checksum error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e606f14042bb87cc02ef6a14db6c90ab92ed6f62d87e69377bc759fd7987cc" -"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" -"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea79295a7a3e0d77f19e763cf1fe7189cd95fc2b36735ea0ea6b711a7380f509" -"checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" -"checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f" -"checksum flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4af030962d89d62aa52cd9492083b1cd9b2d1a77764878102a6c0f86b4d5444d" -"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-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 futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" -"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71" -"checksum git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0" -"checksum git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d58551e903ed7e2d6fe3a2f3c7efa3a784ec29b19d0fbb035aaf0497c183fbdd" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" -"checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c" -"checksum handlebars 0.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1060eaf359ded4fc5827db4591949fff18b0b736821c94c347a441d7019c2545" -"checksum handlebars-iron 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8e885e22dfcf8fbb0ce797cb402b82b6cafea35100a42790bd84c32b718040" -"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44f3bdb08579d99d7dc761c0e266f13b5f2ab8c8c703b9fc9ef333cd8f48f55e" -"checksum home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "80dff82fb58cfbbc617fb9a9184b010be0529201553cda50ad04372bc2333aff" -"checksum html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b04478cf718862650a0bf66acaf8f2f8c906fbc703f35c916c1f4211b069a364" -"checksum http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "24f58e8c2d8e886055c3ead7b28793e1455270b5fb39650984c224bc538ba581" -"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" -"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" -"checksum hyper 0.12.11 (registry+https://github.com/rust-lang/crates.io-index)" = "78d50abbd1790e0f4c74cb1d4a2211b439bac661d54107ad5564c55e77906762" -"checksum hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32cd73f14ad370d3b4d4b7dce08f69b81536c82e39fcc89731930fe5788cd661" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum ignore 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36ecfc5ad80f0b1226df948c562e2cddd446096be3f644c95106400eae8a5e01" -"checksum im-rc 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4591152fd573cf453a890b5f9fdc5c328a751a0785539316739d5f85e5c468c" -"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2440ae846e7a8c7f9b401db8f6e31b4ea5e7d3688b91761337da7e054520c75b" -"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1" -"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" -"checksum jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "60af5f849e1981434e4a31d3d782c4774ae9b434ce55b101a96ecfd09147e8be" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" -"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" -"checksum libflate 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "21138fc6669f438ed7ae3559d5789a5f0ba32f28c1f0608d1e452b0bb06ee936" -"checksum libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" -"checksum libnghttp2-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ffbfb81475cc9f625e44f3a8f8b9cf7173815ae1c7cc2fa91853ec009e38198" -"checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" -"checksum libz-sys 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "4401fe74560a0d46fce3464625ac8aa7a79d291dd28cee021d18852d5191c280" -"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -"checksum magic 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f74caec41a12630bb8fd9546530a41addb720eb0c10593855f59ce96a779aa" -"checksum magic-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17442cc60e34d501588c95bc976da04b6a87c51ab02370e95e1c2893a52df16c" -"checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "79c56d6a0b07f9e19282511c83fc5b086364cbae4ba8c7d5f190c3d9b0425a48" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mime 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "4b082692d3f6cf41b453af73839ce3dfc212c4411cbb2441dff80a716e38bd79" -"checksum mime_guess 1.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2d4c0961143b8efdcfa29c3ae63281601b446a4a668165454b6c90f8024954c5" -"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" -"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" -"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" -"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58" -"checksum mount 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32245731923cd096899502fc4c4317cfd09f121e80e73f7f576cf3777a824256" -"checksum multipart 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b16d6498fe5b0c2f6d973fd9753da099948834f96584d628e44a75f0d2955b03" -"checksum native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8b0a7bd714e83db15676d31caf968ad7318e9cc35f93c85a90231c8f22867549" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" -"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum opener 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "176cd8eadff5ef9fa5c6d19452535662c02c6bf29b3d594a3fc01f749bb24c94" -"checksum openssl 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5af9e83eb3c51ee806387d26a43056f3246d865844caa6dd704d2ba7e831c264" -"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d4edbc8dfa63f557aee3a498179af2cc6a989e12ba1751840046c79afc9e615a" -"checksum ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0015e9e8e28ee20c581cfbfe47c650cedeb9ed0721090e0b7ebb10b9cdbcc2" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum params 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "421e9f2c30e80365c9672709be664bfc84f73b088720d1cc1f4e99675814bb37" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" -"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum persistent 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c9c94f2ef72dc272c6bcc8157ccf2bc7da14f4c58c69059ac2fc48492d6916" -"checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" -"checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" -"checksum pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3294f437119209b084c797604295f40227cffa35c57220b1e99a6ff3bf8ee4" -"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc" -"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f" -"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" -"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" -"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" -"checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" -"checksum postgres 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "115dde90ef51af573580c035857badbece2aa5cde3de1dfb3c932969ca92a6c5" -"checksum postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2487e66455bf88a1b247bf08a3ce7fe5197ac6d67228d920b0ee6a0e97fd7312" -"checksum postgres-shared 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bafecadf25b7de9a5f747e93073db444c9ddcc7b3ae37bcdf63c2508f9a17f2d" -"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" -"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" -"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" -"checksum r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f9078ca6a8a5568ed142083bb2f7dc9295b69d16f867ddcc9849e51b17d8db46" -"checksum r2d2_postgres 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "78c7fe9c0c3d2c298cf262bc3ce4b89cdf0eab620fd9fe759f65b34a1a00fb93" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" -"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -"checksum regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2069749032ea3ec200ca51e4a31df41759190a88edca0d2d86ee8bedf7073341" -"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum reqwest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1d68c7bf0b1dc3860b80c6d31d05808bf54cdc1bfc70a4680893791becd083ae" -"checksum route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3255338088df8146ba63d60a9b8e3556f1146ce2973bc05a75181a42ce2256" -"checksum router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b1797ff166029cb632237bb5542696e54961b4cf75a324c6f05c9cf0584e4e" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c21531a91512a4a51b490be6ba1c8eff34fdda0dc5bf87dc28d86748aac56" -"checksum rusttype 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20" -"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" -"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" -"checksum same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f7794e2fda7f594866840e95f5c5962e886e228e68b6505885811a94dd728c" -"checksum sass-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90f8cf6e645aa843ffffcbdc1e8752b1f221dfa314c81895aeb229a77aea7e05" -"checksum sass-sys 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "173ac202b4585ecfb1521159491175a787584fcc346457d53a099b240c69cd41" -"checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" -"checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0" -"checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf" -"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 sequence_trie 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c915714ca833b1d4d6b8f6a9d72a3ff632fe45b40a8d184ef79c81bec6327eed" -"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" -"checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" -"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c" -"checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" -"checksum serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "67f7d2e9edc3523a9c8ec8cd6ec481b3a27810aafee3e625d311febd3e656b4c" -"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce" -"checksum serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aaed41d9fb1e2f587201b863356590c90c1157495d811430a0c0325fe8169650" -"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" -"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" -"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" -"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum slug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39af1ce888a1253c8b9fcfa36626557650fb487c013620a743262d2769a3e9f3" -"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" -"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31493480e073d52522a94cdf56269dd8eb05f99549effd1826b0271690608878" -"checksum stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48fa7d3136d8645909de1f7c7eb5416cc43057a75ace08fc39ae736bc9da8af1" -"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" -"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" -"checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" -"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" -"checksum stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" -"checksum syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b036b7b35e846707c0e55c2c9441fa47867c0f87fca416921db3261b1d8c741a" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec37f4fab4bafaf6b5621c1d54e6aa5d4d059a8f84929e87abfdd7f9f04c6db2" -"checksum tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "a303ba60a099fcd2aaa646b14d2724591a96a75283e4b7ed3d1a1658909d9ae2" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "55c1195ef8513f3273d55ff59fe5da6940287a0d7a98331254397f464833675b" -"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" -"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "6e93c78d23cc61aa245a8acd2c4a79c4d7fa7fb5c3ca90d5737029f043a84895" -"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f90fcd90952f0a496d438a976afba8e5c205fb12123f813d8ab3aa1c8436638c" -"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" -"checksum tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5cbe4ca6e71cb0b62a66e4e6f53a8c06a6eefe46cc5f665ad6f274c9906f135" -"checksum tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "8b8a85fffbec3c5ab1ab62324570230dcd37ee5996a7859da5caf7b9d45e3e8c" -"checksum tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4b26fd37f1125738b2170c80b551f69ff6fecb277e6e5ca885e53eec2b005018" -"checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912" -"checksum tokio-threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bbd8a8b911301c60cbfaa2a6588fb210e5c1038375b8bdecc47aa09a94c3c05f" -"checksum tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3a52f00c97fedb6d535d27f65cccb7181c8dd4c6edc3eda9ea93f6d45d05168e" -"checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c" -"checksum tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22e3aa6d1fcc19e635418dc0a30ab5bd65d347973d6f43f1a37bf8d9d1335fc9" -"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6c06a92aef38bb4dc5b0df00d68496fc31307c5344c867bb61678c6e1671ec5" -"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" -"checksum unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb95ee07cd579ed18131f2d9e7a17c25a4b76022935c7f2460d2bfae89fd2" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" -"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" -"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" -"checksum urlencoded 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c28708636d6f7298a53b1cdb6af40f1ab523209a7cb83cf4d41b3ebc671d319" -"checksum utf-8 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bab35f71693630bb1953dce0f2bcd780e7cde025027124a202ac08a45ba25141" -"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4" -"checksum uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6" -"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" -"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 void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c66c0b9792f0a765345452775f3adbd28dde9d33f30d13e5dcc5ae17cf6f3780" -"checksum walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "af464bc7be7b785c7ac72e266a6b67c4c9070155606f51655a650a6686204e35" -"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index f5c586f9c..000000000 --- a/Cargo.toml +++ /dev/null @@ -1,56 +0,0 @@ -[package] -name = "cratesfyi" -version = "0.6.0" -authors = ["Onur Aslan "] -readme = "README.md" -license = "MIT" -repository = "https://github.com/rust-lang/docs.rs" -build = "build.rs" - -[dependencies] -log = "0.4" -rustc-serialize = "0.3" -regex = "1" -clap = "2" -crates-index-diff = "4" -git2 = "0.7" -time = "0.1" -reqwest = "0.9" -semver = "0.9" -slug = "=0.1.1" -env_logger = "0.6" -magic = "0.12" -r2d2 = "0.8" -r2d2_postgres = "0.14" -url = "1.4" -libc = "0.2" -badge = { version = "0", path = "src/web/badge" } -failure = "0.1.3" -comrak = { version = "0.3", default-features = false } -toml = "0.4" -html5ever = "0.22" -cargo = { git = "https://github.com/rust-lang/cargo.git" } - -# iron dependencies -iron = "0.5" -router = "0.5" -handlebars-iron = "0.22" -params = "0.6" -staticfile = { version = "0.4", features = [ "cache" ] } - -[dependencies.postgres] -version = "0.15" -features = [ "with-time", "with-rustc-serialize" ] - -[dev-dependencies] -tempdir = "0.3" - -[build-dependencies] -time = "0.1" -git2 = "0.7" -sass-rs = "0.2" - -[[bin]] -name = "cratesfyi" -test = false -doc = false diff --git a/README.md b/README.md deleted file mode 100644 index b4299b801..000000000 --- a/README.md +++ /dev/null @@ -1,153 +0,0 @@ -# Docs.rs - -[![Build Status](https://dev.azure.com/docsrs/docs.rs/_apis/build/status/docs.rs?branchName=master)](https://dev.azure.com/docsrs/docs.rs/_build/latest?definitionId=1) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/rust-lang/docs.rs/master/LICENSE) - -Docs.rs (formerly cratesfyi) is an open source project to host documentation -of crates for the Rust Programming Language. - -Docs.rs automatically builds crates' documentation released on crates.io using -the nightly release of the Rust compiler. - -The README of a crate is taken from the readme field defined in Cargo.toml. -If a crate doesn't have this field, no README will be displayed. - -### Redirections - -Docs.rs is using semver to parse URLs. You can use this feature to access -crates' documentation easily. Example of URL redirections for `clap` crate: - -| URL | Redirects to documentation of | -|------------------------------|------------------------------------------------| -| | Latest version of clap | -| | 2.* version | -| | 2.9.* version | -| | 2.9.3 version (you don't need = unlike semver) | - -The crates.fyi domain will redirect to docs.rs, supporting all of the -redirects discussed above - - -### Badges - -You can use badges to show state of your documentation to your users. -The default badge will be pointed at the latest version of a crate. -You can use `version` parameter to show status of documentation for -any version you want. - -Badge will display in blue if docs.rs is successfully hosting your crate -documentation, and red if building documentation failing. - -Example badges for `mio` crate: - -| URL | Badge | -|-------|-------| -| Latest version: | ![mio](https://docs.rs/mio/badge.svg) | -| Version 0.4.4: | ![mio](https://docs.rs/mio/badge.svg?version=0.4.4) | -| Version 0.1.0: | ![mio](https://docs.rs/mio/badge.svg?version=0.1.0) | - - -## Development - -We strongly recommend using vagrant, this will give you a virtual machine -already configured and ready to start developing on. - -### Getting started - -Make sure you have vagrant, virtualbox and a ssh client and you need -to able to download ~800MB data on the first run. - - -```sh -git clone https://github.com/rust-lang/docs.rs.git docs.rs -cd docs.rs -vagrant up # This may take a little while on the first run -``` - -You can always run `vagrant provision` to reconfigure virtual machine. -Provision will install required dependencies and nightly rust compiler -into virtual machine. It will also configure lxc-container inside -virtual machine. - -### CLI - -Make sure you are running every listed command inside `/vagrant` directory -in virtual machine. You can connect to virtual machine with `vagrant ssh` and -switch current working directory with: `cd /vagrant` inside virtual machine. - - -#### Starting web server - -This command will start web interface of docs.rs and you can access it from: -`http://localhost:3000/` - -``` -cargo run -- start-web-server -``` - - -#### `build` subcommand - -```sh -# Builds and adds it into database -# This is the main command to build and add a documentation into docs.rs. -cargo run -- build crate - - -# Adds essential files (css and fonts) into database to avoid duplication -# This command needs to be run after each rustc update -cargo run -- build add-essential-files - - -# Builds every crate and adds them into database -# (beware: this may take months to finish) -cargo run -- build world -``` - - -#### `database` subcommand - -```sh -# Initializes database. Currently, only creates tables in database. -cargo run -- database init - - -# Adds a directory into database to serve with `staticfile` crate. -cargo run -- database add-directory [PREFIX] - - -# Updates github stats for crates. -# You need to set CRATESFYI_GITHUB_USERNAME, CRATESFYI_GITHUB_ACCESSTOKEN -# environment variables in order to run this command. -# You can set this environment variables in ~/.cratesfyi.env file. -cargo run -- database update-github-fields - - -# Updates search-index. -# daemon is running this command occasionally, and this command must be -# run to update recent-version of a crate index and search index. -# If you are having any trouble with accessing right version of a crate, -# run this command. Otherwise it's not required. -cargo run -- database update-search-index - - -# Updates release activitiy chart -cargo run -- database update-release-activity -``` - -If you want to explore or edit database manually, you can connect database -with `psql` command. - - -#### `doc` subcommand - -This subcommand will only build documentation of a crate. -It is designed to run inside a secure container. - -``` -cargo run -- doc -``` - -#### Contact - -Docs.rs is run and maintaned by [Rustdoc team](https://www.rust-lang.org/governance/teams/dev-tools#Rustdoc%20team-info). You can find us in #rustdoc on [Discord](https://discord.gg/rust-lang). diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index f86ed9644..000000000 --- a/Vagrantfile +++ /dev/null @@ -1,153 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure("2") do |config| - config.vm.box = "docs.rs_v2" - config.vm.box_url = "https://docs.rs/vagrant_v2.box" - config.vm.box_download_checksum = "7c6d9ef85a55461bce361e9734baf54a6eea9affa2334480cd7613a9a6b62bc4" - config.vm.box_download_checksum_type = "sha256" - - config.ssh.username = "cratesfyi" - - config.vm.network "forwarded_port", guest: 3000, host: 3000 - - # Use 25% of available system memory and all CPU's - config.vm.provider "virtualbox" do |vb| - host = RbConfig::CONFIG['host_os'] - - if host =~ /darwin/ - cpus = `sysctl -n hw.ncpu`.to_i - mem = `sysctl -n hw.memsize`.to_i / 1024 / 1024 / 4 - elsif host =~ /linux/ - cpus = `nproc`.to_i - mem = `grep 'MemTotal' /proc/meminfo | sed -e 's/MemTotal://' -e 's/ kB//'`.to_i / 1024 / 4 - else - cpus = 2 - mem = 1024 - end - - vb.memory = mem - vb.cpus = cpus - end - - - # docs.rs vagrant image comes with only a pre-configured cratesfyi-container - # installing rest with provision - config.vm.provision "shell", inline: <<-SHELL - set -ev - - ############################################################ - # Installing docs.rs dependencies # - ############################################################ - apt-get update - apt-get install -y --no-install-recommends cmake curl cmake gcc g++ git libmagic-dev libssl-dev pkg-config - - ############################################################ - # Installing rustc into cratesfyi-container # - ############################################################ - lxc-attach -n cratesfyi-container -- apt-get update - lxc-attach -n cratesfyi-container -- apt-get install -y --no-install-recommends curl ca-certificates binutils gcc libc6-dev libmagic1 - lxc-attach -n cratesfyi-container -- su - cratesfyi -c 'curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly' - - ############################################################ - # Installing extra targets into cratesfyi-container # - ############################################################ - lxc-attach -n cratesfyi-container -- su - cratesfyi -c 'rustup target add x86_64-apple-darwin' - lxc-attach -n cratesfyi-container -- su - cratesfyi -c 'rustup target add x86_64-pc-windows-msvc' - - ############################################################ - # Creating rustc links for cratesfyi user # - ############################################################ - for directory in .cargo .rustup .multirust; do - [[ -h /home/cratesfyi/$directory ]] || sudo -u cratesfyi ln -vs /var/lib/lxc/cratesfyi-container/rootfs/home/cratesfyi/$directory /home/cratesfyi/ - done - - ############################################################ - # Setting up environment variables # - ############################################################ - [[ -f /home/cratesfyi/.cratesfyi.env ]] || sudo -u cratesfyi tee /home/cratesfyi/.cratesfyi.env <<\EOF -CRATESFYI_PREFIX=/home/cratesfyi/cratesfyi-prefix -CRATESFYI_DATABASE_URL=postgresql://cratesfyi@localhost -CRATESFYI_GITHUB_USERNAME= -CRATESFYI_GITHUB_ACCESSTOKEN= -RUST_LOG=cratesfyi -CARGO_TARGET_DIR=/home/cratesfyi/docs.rs/target -EOF - - ############################################################ - # Loading environment variables # - ############################################################ - source /home/cratesfyi/.cratesfyi.env - - ############################################################ - # Preparing cratesfyi-prefix # - ############################################################ - sudo -u cratesfyi mkdir -vp /home/cratesfyi/cratesfyi-prefix/documentations \ - /home/cratesfyi/cratesfyi-prefix/public_html - - ############################################################ - # Getting external css files from docs.rs # - ############################################################ - sudo -u cratesfyi wget -qcP /home/cratesfyi/cratesfyi-prefix/public_html \ - https://docs.rs/rustdoc-20160526-1.10.0-nightly-97e3a2401.css \ - https://docs.rs/main-20160526-1.10.0-nightly-97e3a2401.css - - ############################################################ - # Cloning crates.io-index # - ############################################################ - if [ ! -d /home/cratesfyi/cratesfyi-prefix/crates.io-index ]; then - sudo -u cratesfyi git clone https://github.com/rust-lang/crates.io-index /home/cratesfyi/cratesfyi-prefix/crates.io-index - else - sudo -u cratesfyi git --git-dir=/home/cratesfyi/cratesfyi-prefix/crates.io-index/.git pull - fi - - # Create `crates-index-diff_last-seen` branch for tracking new crates - sudo -u cratesfyi git --git-dir=/home/cratesfyi/cratesfyi-prefix/crates.io-index/.git branch crates-index-diff_last-seen || true - - ############################################################ - # Building docs.rs # - ############################################################ - su - cratesfyi -c "cd /vagrant && cargo build" 2>&1 - - ############################################################ - # Copying docs.rs into container # - ############################################################ - cp -v /home/cratesfyi/docs.rs/target/debug/cratesfyi /var/lib/lxc/cratesfyi-container/rootfs/usr/local/bin - - ############################################################ - # Re-creating database # - ############################################################ - echo 'DROP DATABASE cratesfyi; CREATE DATABASE cratesfyi OWNER cratesfyi' | sudo -u postgres psql - - ############################################################ - # Initializing database scheme # - ############################################################ - su - cratesfyi -c "cd /vagrant && cargo run -- database init" - - ############################################################ - # Add essential files for downloaded nigthly # - ############################################################ - su - cratesfyi -c "cd /vagrant && cargo run -- build add-essential-files" 2>&1 - - ############################################################ - # Populating database by building some crates # - ############################################################ - su - cratesfyi -c "cd /vagrant && cargo run -- build crate rand 0.3.15" 2>&1 - su - cratesfyi -c "cd /vagrant && cargo run -- build crate log 0.3.6" 2>&1 - su - cratesfyi -c "cd /vagrant && cargo run -- build crate regex 0.1.80" 2>&1 - - ############################################################ - # Update search index and release activity # - ############################################################ - su - cratesfyi -c "cd /vagrant && cargo run -- database update-search-index" 2>&1 - su - cratesfyi -c "cd /vagrant && cargo run -- database update-release-activity" 2>&1 - - - ############################################################ - # docs.rs vagrant box is ready! # - #----------------------------------------------------------# - # You can connect to virtual machine with `vagrant ssh`. # - # docs.rs is available in `/vagrant` folder! # - ############################################################ - SHELL -end diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index f4b9ff411..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,101 +0,0 @@ -# Ref: https://aka.ms/yaml - -resources: - containers: - - container: debian-jessie - image: onuras/docs.rs:debian-jessie - - container: debian-stretch - image: onuras/docs.rs:debian-stretch - - -jobs: -- job: test - pool: - vmImage: 'Ubuntu 16.04' - strategy: - matrix: - jessie: - containerResource: debian-jessie - stretch: - containerResource: debian-stretch - container: $[ variables['containerResource'] ] - steps: - - script: curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable - displayName: 'Install rustc' - - script: | - export PATH=$PATH:$HOME/.cargo/bin - cargo build --verbose - displayName: 'Build docs.rs' - - script: | - export PATH=$PATH:$HOME/.cargo/bin - cargo test --verbose -- --test-threads=1 - displayName: 'Test docs.rs' - - -- job: release - condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') - pool: - vmImage: 'Ubuntu 16.04' - strategy: - matrix: - jessie: - containerResource: debian-jessie - stretch: - containerResource: debian-stretch - container: $[ variables['containerResource'] ] - steps: - - script: curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable - displayName: 'Install rustc' - - script: | - export PATH=$PATH:$HOME/.cargo/bin - cargo build --verbose --release - displayName: 'Build docs.rs' - - task: CopyFiles@2 - inputs: - contents: '$(System.DefaultWorkingDirectory)/templates/**' - targetFolder: $(Build.ArtifactStagingDirectory) - displayName: 'Copy templates' - - task: CopyFiles@2 - inputs: - contents: '$(System.DefaultWorkingDirectory)/target/release/cratesfyi' - targetFolder: $(Build.ArtifactStagingDirectory) - displayName: 'Copy build' - - task: PublishBuildArtifacts@1 - inputs: - artifactName: $(containerResource) - displayName: 'Upload artifacts' - - -- job: deploy - dependsOn: - - test - - release - condition: succeeded() - pool: - vmImage: 'Ubuntu 16.04' - container: debian-stretch - steps: - - checkout: none - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: debian-jessie - downloadPath: $(System.DefaultWorkingDirectory) - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: debian-stretch - downloadPath: $(System.DefaultWorkingDirectory) - - task: DownloadSecureFile@1 - inputs: - secureFile: docs.rs.ssh.private.key - - script: tar czfv $(Build.BinariesDirectory)/$(Build.SourceVersion).tar.gz . - displayName: 'Pack build' - - script: | - mkdir -p ~/.ssh - chmod 700 ~/.ssh - echo "$(docs.rs.ssh.hostname)" > ~/.ssh/known_hosts - chmod 644 ~/.ssh/known_hosts - eval $(ssh-agent -s) - cat $DOWNLOADSECUREFILE_SECUREFILEPATH | tr -d '\r' | ssh-add - > /dev/null - scp -P $(docs.rs.ssh.port) $(Build.BinariesDirectory)/$(Build.SourceVersion).tar.gz $(docs.rs.ssh.destination):azure-deploys/ - ssh -p $(docs.rs.ssh.port) $(docs.rs.ssh.destination) azure-deploys/install-deploy.sh $(Build.SourceVersion) - displayName: 'Upload build into docs.rs and run deploy script' diff --git a/build.rs b/build.rs deleted file mode 100644 index 292f85b2f..000000000 --- a/build.rs +++ /dev/null @@ -1,51 +0,0 @@ - -extern crate time; -extern crate sass_rs; -extern crate git2; - -use std::env; -use std::path::Path; -use std::fs::File; -use std::io::Write; -use git2::Repository; - - -fn main() { - write_git_version(); - compile_sass(); -} - - -fn write_git_version() { - let git_hash = get_git_hash().unwrap_or("???????".to_owned()); - let build_date = time::strftime("%Y-%m-%d", &time::now_utc()).unwrap(); - let dest_path = Path::new(&env::var("OUT_DIR").unwrap()).join("git_version"); - let mut file = File::create(&dest_path).unwrap(); - write!(file, "({} {})", git_hash, build_date).unwrap(); -} - - -fn get_git_hash() -> Option { - let repo = match Repository::open(env::current_dir().unwrap()) { - Ok(repo) => repo, - Err(_) => return None, - }; - let head = repo.head().unwrap(); - head.target().map(|h| { - let mut h = format!("{}", h); - h.truncate(7); - h - }) -} - - -fn compile_sass() { - use sass_rs::Context; - - let mut file_context = Context::new_file(concat!(env!("CARGO_MANIFEST_DIR"), - "/templates/style.scss")).unwrap(); - let css = file_context.compile().unwrap(); - let dest_path = Path::new(&env::var("OUT_DIR").unwrap()).join("style.css"); - let mut file = File::create(&dest_path).unwrap(); - file.write_all(css.as_bytes()).unwrap(); -} diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index de740541c..000000000 --- a/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ - -format_strings = false diff --git a/src/bin/cratesfyi.rs b/src/bin/cratesfyi.rs deleted file mode 100644 index 8caa05848..000000000 --- a/src/bin/cratesfyi.rs +++ /dev/null @@ -1,248 +0,0 @@ - - -extern crate cratesfyi; -extern crate clap; -extern crate log; -extern crate env_logger; -extern crate time; - - -use std::env; -use std::path::PathBuf; - -use clap::{Arg, App, SubCommand}; -use cratesfyi::{DocBuilder, DocBuilderOptions, db}; -use cratesfyi::utils::build_doc; -use cratesfyi::start_web_server; -use cratesfyi::db::add_path_into_database; - - -pub fn main() { - logger_init(); - - let matches = App::new("cratesfyi") - .version(cratesfyi::BUILD_VERSION) - .about(env!("CARGO_PKG_DESCRIPTION")) - .subcommand(SubCommand::with_name("doc") - .about("Builds documentation of a crate") - .arg(Arg::with_name("CRATE_NAME") - .index(1) - .required(true) - .help("Crate name")) - .arg(Arg::with_name("CRATE_VERSION") - .index(2) - .required(false) - .help("Crate version")) - .arg(Arg::with_name("TARGET") - .index(3) - .required(false) - .help("The target platform to compile for"))) - .subcommand(SubCommand::with_name("build") - .about("Builds documentation in a chroot environment") - .arg(Arg::with_name("PREFIX") - .short("P") - .long("prefix") - .takes_value(true)) - .arg(Arg::with_name("DESTINATION") - .short("d") - .long("destination") - .help("Sets destination path") - .takes_value(true)) - .arg(Arg::with_name("CHROOT_PATH") - .short("c") - .long("chroot-path") - .help("Sets chroot path") - .takes_value(true)) - .arg(Arg::with_name("CHROOT_USER") - .short("u") - .long("chroot-user") - .help("Sets chroot user name") - .takes_value(true)) - .arg(Arg::with_name("CONTAINER_NAME") - .short("n") - .long("container-name") - .help("Sets name of the container") - .takes_value(true)) - .arg(Arg::with_name("CRATES_IO_INDEX_PATH") - .long("crates-io-index-path") - .help("Sets crates.io-index path") - .takes_value(true)) - .arg(Arg::with_name("SKIP_IF_EXISTS") - .short("s") - .long("skip") - .help("Skips building documentation if \ - documentation exists")) - .arg(Arg::with_name("SKIP_IF_LOG_EXISTS") - .long("skip-if-log-exists") - .help("Skips building documentation if build \ - log exists")) - .arg(Arg::with_name("KEEP_BUILD_DIRECTORY") - .short("-k") - .long("keep-build-directory") - .help("Keeps build directory after build.")) - .subcommand(SubCommand::with_name("world").about("Builds documentation of every \ - crate")) - .subcommand(SubCommand::with_name("crate") - .about("Builds documentation for a crate") - .arg(Arg::with_name("CRATE_NAME") - .index(1) - .required(true) - .help("Crate name")) - .arg(Arg::with_name("CRATE_VERSION") - .index(2) - .required(true) - .help("Version of crate"))) - .subcommand(SubCommand::with_name("add-essential-files") - .about("Adds essential files for rustc")) - .subcommand(SubCommand::with_name("lock").about("Locks cratesfyi daemon to stop \ - building new crates")) - .subcommand(SubCommand::with_name("unlock") - .about("Unlocks cratesfyi daemon to continue \ - building new crates")) - .subcommand(SubCommand::with_name("print-options"))) - .subcommand(SubCommand::with_name("start-web-server") - .about("Starts web server") - .arg(Arg::with_name("SOCKET_ADDR") - .index(1) - .required(false) - .help("Socket address to listen to"))) - .subcommand(SubCommand::with_name("daemon").about("Starts cratesfyi daemon")) - .subcommand(SubCommand::with_name("database") - .about("Database operations") - .subcommand(SubCommand::with_name("init").about("Initialize database. Currently \ - only creates tables in database.")) - .subcommand(SubCommand::with_name("update-github-fields") - .about("Updates github stats for crates.")) - .subcommand(SubCommand::with_name("add-directory") - .about("Adds a directory into database") - .arg(Arg::with_name("DIRECTORY") - .index(1) - .required(true) - .help("Path of file or \ - directory")) - .arg(Arg::with_name("PREFIX") - .index(2) - .help("Prefix of files in \ - database"))) - .subcommand(SubCommand::with_name("update-release-activity")) - .about("Updates montly release activity \ - chart") - .subcommand(SubCommand::with_name("update-search-index")) - .about("Updates search index")) - .get_matches(); - - - - // doc subcommand - if let Some(matches) = matches.subcommand_matches("doc") { - let name = matches.value_of("CRATE_NAME").unwrap(); - let version = matches.value_of("CRATE_VERSION"); - let target = matches.value_of("TARGET"); - if let Err(e) = build_doc(name, version, target) { - panic!("{:#?}", e); - } - } else if let Some(matches) = matches.subcommand_matches("build") { - let docbuilder_opts = { - let mut docbuilder_opts = if let Some(prefix) = matches.value_of("PREFIX") { - DocBuilderOptions::from_prefix(PathBuf::from(prefix)) - } else if let Ok(prefix) = env::var("CRATESFYI_PREFIX") { - DocBuilderOptions::from_prefix(PathBuf::from(prefix)) - } else { - DocBuilderOptions::default() - }; - - // set options - if let Some(destination) = matches.value_of("DESTINATION") { - docbuilder_opts.destination = PathBuf::from(destination); - } - - if let Some(chroot_path) = matches.value_of("CHROOT_PATH") { - docbuilder_opts.chroot_path = PathBuf::from(chroot_path); - } - - if let Some(chroot_user) = matches.value_of("CHROOT_USER") { - docbuilder_opts.chroot_user = chroot_user.to_string(); - } - - if let Some(container_name) = matches.value_of("CONTAINER_NAME") { - docbuilder_opts.container_name = container_name.to_string(); - } - - if let Some(crates_io_index_path) = matches.value_of("CRATES_IO_INDEX_PATH") { - docbuilder_opts.crates_io_index_path = PathBuf::from(crates_io_index_path); - } - - docbuilder_opts.skip_if_exists = matches.is_present("SKIP_IF_EXISTS"); - docbuilder_opts.skip_if_log_exists = matches.is_present("SKIP_IF_LOG_EXISTS"); - docbuilder_opts.keep_build_directory = matches.is_present("KEEP_BUILD_DIRECTORY"); - - docbuilder_opts.check_paths().unwrap(); - - docbuilder_opts - }; - - let mut docbuilder = DocBuilder::new(docbuilder_opts); - - if let Some(_) = matches.subcommand_matches("world") { - docbuilder.load_cache().expect("Failed to load cache"); - docbuilder.build_world().expect("Failed to build world"); - docbuilder.save_cache().expect("Failed to save cache"); - } else if let Some(matches) = matches.subcommand_matches("crate") { - docbuilder.load_cache().expect("Failed to load cache"); - docbuilder.build_package(matches.value_of("CRATE_NAME").unwrap(), - matches.value_of("CRATE_VERSION").unwrap()) - .expect("Building documentation failed"); - docbuilder.save_cache().expect("Failed to save cache"); - } else if let Some(_) = matches.subcommand_matches("add-essential-files") { - docbuilder.add_essential_files().expect("Failed to add essential files"); - } else if let Some(_) = matches.subcommand_matches("lock") { - docbuilder.lock().expect("Failed to lock"); - } else if let Some(_) = matches.subcommand_matches("unlock") { - docbuilder.unlock().expect("Failed to unlock"); - } else if let Some(_) = matches.subcommand_matches("print-options") { - println!("{:?}", docbuilder.options()); - } - - } else if let Some(matches) = matches.subcommand_matches("database") { - if let Some(_) = matches.subcommand_matches("init") { - let conn = db::connect_db().unwrap(); - db::create_tables(&conn).expect("Failed to initialize database"); - } else if let Some(_) = matches.subcommand_matches("update-github-fields") { - cratesfyi::utils::github_updater().expect("Failed to update github fields"); - } else if let Some(matches) = matches.subcommand_matches("add-directory") { - add_path_into_database(&db::connect_db().unwrap(), - matches.value_of("PREFIX").unwrap_or(""), - matches.value_of("DIRECTORY").unwrap()) - .expect("Failed to add directory into database"); - } else if let Some(_) = matches.subcommand_matches("update-release-activity") { - // FIXME: This is actually util command not database - cratesfyi::utils::update_release_activity().expect("Failed to update release activity"); - } else if let Some(_) = matches.subcommand_matches("update-search-index") { - let conn = db::connect_db().unwrap(); - db::update_search_index(&conn).expect("Failed to update search index"); - } - } else if let Some(matches) = matches.subcommand_matches("start-web-server") { - start_web_server(Some(matches.value_of("SOCKET_ADDR").unwrap_or("0.0.0.0:3000"))); - } else if let Some(_) = matches.subcommand_matches("daemon") { - cratesfyi::utils::start_daemon(); - } else { - println!("{}", matches.usage()); - } -} - - - -fn logger_init() { - use std::io::Write; - - let mut builder = env_logger::Builder::new(); - builder.format(|buf, record| { - writeln!(buf, "{} [{}] {}: {}", - time::now().strftime("%Y/%m/%d %H:%M:%S").unwrap(), - record.level(), - record.target(), - record.args()) - }); - builder.parse(&env::var("RUST_LOG").unwrap_or("cratesfyi=info".to_owned())); - builder.init(); -} diff --git a/src/db/add_package.rs b/src/db/add_package.rs deleted file mode 100644 index 53483caa3..000000000 --- a/src/db/add_package.rs +++ /dev/null @@ -1,456 +0,0 @@ - -use ChrootBuilderResult; -use Metadata; -use utils::source_path; -use regex::Regex; - -use std::io::prelude::*; -use std::io::BufReader; -use std::path::{Path, PathBuf}; -use std::fs; - -use cargo::core::{Package, TargetKind}; -use rustc_serialize::json::{Json, ToJson}; -use slug::slugify; -use reqwest::Client; -use reqwest::header::ACCEPT; -use semver; -use postgres::Connection; -use time; -use error::Result; -use failure::err_msg; - -/// Adds a package into database. -/// -/// Package must be built first. -pub fn add_package_into_database(conn: &Connection, - pkg: &Package, - res: &ChrootBuilderResult, - files: Option, - doc_targets: Vec) - -> Result { - debug!("Adding package into database"); - let crate_id = try!(initialize_package_in_database(&conn, &pkg)); - let dependencies = convert_dependencies(&pkg); - let rustdoc = get_rustdoc(&pkg).unwrap_or(None); - let readme = get_readme(&pkg).unwrap_or(None); - let (release_time, yanked, downloads) = try!(get_release_time_yanked_downloads(&pkg)); - let is_library = match pkg.targets()[0].kind() { - &TargetKind::Lib(_) => true, - _ => false, - }; - let metadata = Metadata::from_package(pkg)?; - - let release_id: i32 = { - let rows = try!(conn.query("SELECT id FROM releases WHERE crate_id = $1 AND version = $2", - &[&crate_id, &format!("{}", pkg.manifest().version())])); - - if rows.len() == 0 { - let rows = try!(conn.query("INSERT INTO releases ( - crate_id, version, release_time, - dependencies, target_name, yanked, build_status, - rustdoc_status, test_status, license, repository_url, - homepage_url, description, description_long, readme, - authors, keywords, have_examples, downloads, files, - doc_targets, is_library, doc_rustc_version, - documentation_url, default_target - ) - VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, - $11, $12, $13, $14, $15, $16, $17, $18, $19, - $20, $21, $22, $23, $24, $25 - ) - RETURNING id", - &[&crate_id, - &format!("{}", pkg.manifest().version()), - &release_time, - &dependencies.to_json(), - &pkg.targets()[0].name().replace("-", "_"), - &yanked, - &res.build_success, - &res.have_doc, - &false, // TODO: Add test status somehow - &pkg.manifest().metadata().license, - &pkg.manifest().metadata().repository, - &pkg.manifest().metadata().homepage, - &pkg.manifest().metadata().description, - &rustdoc, - &readme, - &pkg.manifest().metadata().authors.to_json(), - &pkg.manifest().metadata().keywords.to_json(), - &res.have_examples, - &downloads, - &files, - &doc_targets.to_json(), - &is_library, - &res.rustc_version, - &pkg.manifest().metadata().documentation, - &metadata.default_target])); - // return id - rows.get(0).get(0) - - } else { - try!(conn.query("UPDATE releases - SET release_time = $3, - dependencies = $4, - target_name = $5, - yanked = $6, - build_status = $7, - rustdoc_status = $8, - test_status = $9, - license = $10, - repository_url = $11, - homepage_url = $12, - description = $13, - description_long = $14, - readme = $15, - authors = $16, - keywords = $17, - have_examples = $18, - downloads = $19, - files = $20, - doc_targets = $21, - is_library = $22, - doc_rustc_version = $23, - documentation_url = $24, - default_target = $25 - WHERE crate_id = $1 AND version = $2", - &[&crate_id, - &format!("{}", pkg.manifest().version()), - &release_time, - &dependencies.to_json(), - &pkg.targets()[0].name().replace("-", "_"), - &yanked, - &res.build_success, - &res.have_doc, - &false, // TODO: Add test status somehow - &pkg.manifest().metadata().license, - &pkg.manifest().metadata().repository, - &pkg.manifest().metadata().homepage, - &pkg.manifest().metadata().description, - &rustdoc, - &readme, - &pkg.manifest().metadata().authors.to_json(), - &pkg.manifest().metadata().keywords.to_json(), - &res.have_examples, - &downloads, - &files, - &doc_targets.to_json(), - &is_library, - &res.rustc_version, - &pkg.manifest().metadata().documentation, - &metadata.default_target])); - rows.get(0).get(0) - } - }; - - - try!(add_keywords_into_database(&conn, &pkg, &release_id)); - try!(add_authors_into_database(&conn, &pkg, &release_id)); - try!(add_owners_into_database(&conn, &pkg, &crate_id)); - - - // Update versions - { - let mut versions: Json = try!(conn.query("SELECT versions FROM crates WHERE id = $1", - &[&crate_id])) - .get(0) - .get(0); - if let Some(versions_array) = versions.as_array_mut() { - let mut found = false; - for version in versions_array.clone() { - if &semver::Version::parse(version.as_string().unwrap()).unwrap() == - pkg.manifest().version() { - found = true; - } - } - if !found { - versions_array.push(format!("{}", &pkg.manifest().version()).to_json()); - } - } - let _ = conn.query("UPDATE crates SET versions = $1 WHERE id = $2", - &[&versions, &crate_id]); - } - - Ok(release_id) -} - - -/// Adds a build into database -pub fn add_build_into_database(conn: &Connection, - release_id: &i32, - res: &ChrootBuilderResult) - -> Result { - debug!("Adding build into database"); - let rows = try!(conn.query("INSERT INTO builds (rid, rustc_version, - cratesfyi_version, - build_status, output) - VALUES ($1, $2, $3, $4, $5) - RETURNING id", - &[release_id, - &res.rustc_version, - &res.cratesfyi_version, - &res.build_success, - &res.output])); - Ok(rows.get(0).get(0)) -} - - -fn initialize_package_in_database(conn: &Connection, pkg: &Package) -> Result { - let mut rows = try!(conn.query("SELECT id FROM crates WHERE name = $1", - &[&pkg.manifest().name().as_str()])); - // insert crate into database if it is not exists - if rows.len() == 0 { - rows = try!(conn.query("INSERT INTO crates (name) VALUES ($1) RETURNING id", - &[&pkg.manifest().name().as_str()])); - } - Ok(rows.get(0).get(0)) -} - - - -/// Convert dependencies into Vec<(String, String)> -fn convert_dependencies(pkg: &Package) -> Vec<(String, String)> { - let mut dependencies: Vec<(String, String)> = Vec::new(); - for dependency in pkg.manifest().dependencies() { - let name = dependency.package_name().to_string(); - let version = format!("{}", dependency.version_req()); - dependencies.push((name, version)); - } - dependencies -} - - -/// Reads readme if there is any read defined in Cargo.toml of a Package -fn get_readme(pkg: &Package) -> Result> { - let readme_path = PathBuf::from(try!(source_path(&pkg).ok_or_else(|| err_msg("File not found")))) - .join(pkg.manifest().metadata().readme.clone().unwrap_or("README.md".to_owned())); - - if !readme_path.exists() { - return Ok(None); - } - - let mut reader = try!(fs::File::open(readme_path).map(|f| BufReader::new(f))); - let mut readme = String::new(); - try!(reader.read_to_string(&mut readme)); - Ok(Some(readme)) -} - - -fn get_rustdoc(pkg: &Package) -> Result> { - if let Some(src_path) = pkg.manifest().targets()[0].src_path().path() { - if src_path.is_absolute() { - read_rust_doc(src_path) - } else { - let mut path = PathBuf::from(try!(source_path(&pkg).ok_or_else(|| err_msg("File not found")))); - path.push(src_path); - read_rust_doc(path.as_path()) - } - } else { - // FIXME: should we care about metabuild targets? - Ok(None) - } -} - - -/// Reads rustdoc from library -fn read_rust_doc(file_path: &Path) -> Result> { - let reader = try!(fs::File::open(file_path).map(|f| BufReader::new(f))); - let mut rustdoc = String::new(); - - for line in reader.lines() { - let line = try!(line); - if line.starts_with("//!") { - // some lines may or may not have a space between the `//!` and the start of the text - let line = line.trim_start_matches("//!").trim_start(); - if !line.is_empty() { - rustdoc.push_str(line); - } - rustdoc.push('\n'); - } - } - - if rustdoc.is_empty() { - Ok(None) - } else if rustdoc.len() > 51200 { - Ok(Some(format!("(Library doc comment ignored due to being too long. ({} > 51200))", rustdoc.len()))) - } else { - Ok(Some(rustdoc)) - } -} - - - -/// Get release_time, yanked and downloads from crates.io -fn get_release_time_yanked_downloads - (pkg: &Package) - -> Result<(Option, Option, Option)> { - let url = format!("https://crates.io/api/v1/crates/{}/versions", - pkg.manifest().name()); - // FIXME: There is probably better way to do this - // and so many unwraps... - let client = Client::new(); - let mut res = try!(client.get(&url[..]) - .header(ACCEPT, "application/json") - .send()); - let mut body = String::new(); - res.read_to_string(&mut body).unwrap(); - let json = Json::from_str(&body[..]).unwrap(); - let versions = try!(json.as_object() - .and_then(|o| o.get("versions")) - .and_then(|v| v.as_array()) - .ok_or_else(|| err_msg("Not a JSON object"))); - - let (mut release_time, mut yanked, mut downloads) = (None, None, None); - - for version in versions { - let version = try!(version.as_object().ok_or_else(|| err_msg("Not a JSON object"))); - let version_num = try!(version.get("num") - .and_then(|v| v.as_string()) - .ok_or_else(|| err_msg("Not a JSON object"))); - - if &semver::Version::parse(version_num).unwrap() == pkg.manifest().version() { - let release_time_raw = try!(version.get("created_at") - .and_then(|c| c.as_string()) - .ok_or_else(|| err_msg("Not a JSON object"))); - release_time = Some(time::strptime(release_time_raw, "%Y-%m-%dT%H:%M:%S") - .unwrap() - .to_timespec()); - - yanked = Some(try!(version.get("yanked") - .and_then(|c| c.as_boolean()) - .ok_or_else(|| err_msg("Not a JSON object")))); - - downloads = Some(try!(version.get("downloads") - .and_then(|c| c.as_i64()) - .ok_or_else(|| err_msg("Not a JSON object"))) as i32); - - break; - } - } - - Ok((release_time, yanked, downloads)) -} - - -/// Adds keywords into database -fn add_keywords_into_database(conn: &Connection, pkg: &Package, release_id: &i32) -> Result<()> { - for keyword in &pkg.manifest().metadata().keywords { - let slug = slugify(&keyword); - let keyword_id: i32 = { - let rows = try!(conn.query("SELECT id FROM keywords WHERE slug = $1", &[&slug])); - if rows.len() > 0 { - rows.get(0).get(0) - } else { - try!(conn.query("INSERT INTO keywords (name, slug) VALUES ($1, $2) RETURNING id", - &[&keyword, &slug])) - .get(0) - .get(0) - } - }; - // add releationship - let _ = conn.query("INSERT INTO keyword_rels (rid, kid) VALUES ($1, $2)", - &[release_id, &keyword_id]); - } - - Ok(()) -} - - - -/// Adds authors into database -fn add_authors_into_database(conn: &Connection, pkg: &Package, release_id: &i32) -> Result<()> { - - let author_capture_re = Regex::new("^([^><]+)<*(.*?)>*$").unwrap(); - for author in &pkg.manifest().metadata().authors { - if let Some(author_captures) = author_capture_re.captures(&author[..]) { - let author = author_captures.get(1).map(|m| m.as_str()).unwrap_or("").trim(); - let email = author_captures.get(2).map(|m| m.as_str()).unwrap_or("").trim(); - let slug = slugify(&author); - - let author_id: i32 = { - let rows = try!(conn.query("SELECT id FROM authors WHERE slug = $1", &[&slug])); - if rows.len() > 0 { - rows.get(0).get(0) - } else { - try!(conn.query("INSERT INTO authors (name, email, slug) VALUES ($1, $2, $3) - RETURNING id", - &[&author, &email, &slug])) - .get(0) - .get(0) - } - }; - - // add relationship - let _ = conn.query("INSERT INTO author_rels (rid, aid) VALUES ($1, $2)", - &[release_id, &author_id]); - } - } - - Ok(()) -} - - - -/// Adds owners into database -fn add_owners_into_database(conn: &Connection, pkg: &Package, crate_id: &i32) -> Result<()> { - // owners available in: https://crates.io/api/v1/crates/rand/owners - let owners_url = format!("https://crates.io/api/v1/crates/{}/owners", - &pkg.manifest().name()); - let client = Client::new(); - let mut res = try!(client.get(&owners_url[..]) - .header(ACCEPT, "application/json") - .send()); - // FIXME: There is probably better way to do this - // and so many unwraps... - let mut body = String::new(); - res.read_to_string(&mut body).unwrap(); - let json = try!(Json::from_str(&body[..])); - - if let Some(owners) = json.as_object() - .and_then(|j| j.get("users")) - .and_then(|j| j.as_array()) { - for owner in owners { - // FIXME: I know there is a better way to do this - let avatar = owner.as_object() - .and_then(|o| o.get("avatar")) - .and_then(|o| o.as_string()) - .unwrap_or(""); - let email = owner.as_object() - .and_then(|o| o.get("email")) - .and_then(|o| o.as_string()) - .unwrap_or(""); - let login = owner.as_object() - .and_then(|o| o.get("login")) - .and_then(|o| o.as_string()) - .unwrap_or(""); - let name = owner.as_object() - .and_then(|o| o.get("name")) - .and_then(|o| o.as_string()) - .unwrap_or(""); - - if login.is_empty() { - continue; - } - - let owner_id: i32 = { - let rows = try!(conn.query("SELECT id FROM owners WHERE login = $1", &[&login])); - if rows.len() > 0 { - rows.get(0).get(0) - } else { - try!(conn.query("INSERT INTO owners (login, avatar, name, email) - VALUES ($1, $2, $3, $4) - RETURNING id", - &[&login, &avatar, &name, &email])) - .get(0) - .get(0) - } - }; - - // add relationship - let _ = conn.query("INSERT INTO owner_rels (cid, oid) VALUES ($1, $2)", - &[crate_id, &owner_id]); - } - - } - Ok(()) -} diff --git a/src/db/file.rs b/src/db/file.rs deleted file mode 100644 index d22a2c38d..000000000 --- a/src/db/file.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Simple module to store files in database. -//! -//! cratesfyi is generating more than 5 million files, they are small and mostly html files. -//! They are using so many inodes and it is better to store them in database instead of -//! filesystem. This module is adding files into database and retrieving them. - - -use std::path::Path; -use postgres::Connection; -use rustc_serialize::json::{Json, ToJson}; -use std::fs::File; -use std::io::Read; -use error::Result; -use failure::err_msg; - - -fn file_path(prefix: &str, name: &str) -> String { - match prefix.is_empty() { - true => name.to_owned(), - false => format!("{}/{}", prefix, name), - } -} - - -fn get_file_list_from_dir>(path: P, - prefix: &str, - files: &mut Vec) - -> Result<()> { - let path = path.as_ref(); - - for file in try!(path.read_dir()) { - let file = try!(file); - - if try!(file.file_type()).is_file() { - file.file_name().to_str().map(|name| files.push(file_path(prefix, name))); - } else if try!(file.file_type()).is_dir() { - file.file_name() - .to_str() - .map(|name| get_file_list_from_dir(file.path(), &file_path(prefix, name), files)); - } - } - - Ok(()) -} - - -pub fn get_file_list>(path: P) -> Result> { - let path = path.as_ref(); - let mut files: Vec = Vec::new(); - - if !path.exists() { - return Err(err_msg("File not found")); - } else if path.is_file() { - path.file_name() - .and_then(|name| name.to_str()) - .map(|name| files.push(format!("{}", name))); - } else if path.is_dir() { - try!(get_file_list_from_dir(path, "", &mut files)); - } - - Ok(files) -} - - -/// Adds files into database and returns list of files with their mime type in Json -pub fn add_path_into_database>(conn: &Connection, - prefix: &str, - path: P) - -> Result { - use magic::{Cookie, flags}; - let cookie = try!(Cookie::open(flags::MIME_TYPE)); - try!(cookie.load::<&str>(&[])); - - let trans = try!(conn.transaction()); - - let mut file_list_with_mimes: Vec<(String, String)> = Vec::new(); - - for file_path_str in try!(get_file_list(&path)) { - let (path, content, mime) = { - let path = Path::new(path.as_ref()).join(&file_path_str); - // Some files have insufficient permissions (like .lock file created by cargo in - // documentation directory). We are skipping this files. - let mut file = match File::open(path) { - Ok(f) => f, - Err(_) => continue, - }; - let mut content: Vec = Vec::new(); - try!(file.read_to_end(&mut content)); - let mime = { - let mime = try!(cookie.buffer(&content)); - // css's are causing some problem in browsers - // magic will return text/plain for css file types - // convert them to text/css - // do the same for javascript files - if mime == "text/plain" { - if file_path_str.ends_with(".css") { - "text/css".to_owned() - } else if file_path_str.ends_with(".js") { - "application/javascript".to_owned() - } else { - mime.to_owned() - } - } else { - mime.to_owned() - } - }; - - file_list_with_mimes.push((mime.clone(), file_path_str.clone())); - - (file_path(prefix, &file_path_str), content, mime) - }; - - // check if file already exists in database - let rows = try!(conn.query("SELECT COUNT(*) FROM files WHERE path = $1", &[&path])); - - if rows.get(0).get::(0) == 0 { - try!(trans.query("INSERT INTO files (path, mime, content) VALUES ($1, $2, $3)", - &[&path, &mime, &content])); - } else { - try!(trans.query("UPDATE files SET mime = $2, content = $3, date_updated = NOW() \ - WHERE path = $1", - &[&path, &mime, &content])); - } - } - - try!(trans.commit()); - - file_list_to_json(file_list_with_mimes) -} - - - -fn file_list_to_json(file_list: Vec<(String, String)>) -> Result { - - let mut file_list_json: Vec = Vec::new(); - - for file in file_list { - let mut v: Vec = Vec::new(); - v.push(file.0.clone()); - v.push(file.1.clone()); - file_list_json.push(v.to_json()); - } - - Ok(file_list_json.to_json()) -} - - - -#[cfg(test)] -mod test { - extern crate env_logger; - use std::env; - use super::{get_file_list, add_path_into_database}; - use super::super::connect_db; - - #[test] - fn test_get_file_list() { - let _ = env_logger::try_init(); - - let files = get_file_list(env::current_dir().unwrap()); - assert!(files.is_ok()); - assert!(files.unwrap().len() > 0); - - let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap(); - assert_eq!(files[0], "Cargo.toml"); - } - - #[test] - #[ignore] - fn test_add_path_into_database() { - let _ = env_logger::try_init(); - - let conn = connect_db().unwrap(); - let res = add_path_into_database(&conn, "example", env::current_dir().unwrap().join("src")); - assert!(res.is_ok()); - } -} diff --git a/src/db/mod.rs b/src/db/mod.rs deleted file mode 100644 index c725814db..000000000 --- a/src/db/mod.rs +++ /dev/null @@ -1,215 +0,0 @@ -//! Database operations - -pub use self::add_package::add_package_into_database; -pub use self::add_package::add_build_into_database; -pub use self::file::add_path_into_database; - -use postgres::{Connection, TlsMode}; -use postgres::error::Error; -use std::env; -use r2d2; -use r2d2_postgres; - -mod add_package; -mod file; - - -/// Connects to database -pub fn connect_db() -> Result { - // FIXME: unwrap might not be the best here - let db_url = env::var("CRATESFYI_DATABASE_URL") - .expect("CRATESFYI_DATABASE_URL environment variable is not exists"); - Connection::connect(&db_url[..], TlsMode::None) -} - - -pub fn create_pool() -> r2d2::Pool { - let db_url = env::var("CRATESFYI_DATABASE_URL") - .expect("CRATESFYI_DATABASE_URL environment variable is not exists"); - let manager = r2d2_postgres::PostgresConnectionManager::new(&db_url[..], - r2d2_postgres::TlsMode::None) - .expect("Failed to create PostgresConnectionManager"); - r2d2::Pool::builder().build(manager).expect("Failed to create r2d2 pool") -} - - -/// Updates content column in crates table. -/// -/// This column will be used for searches and always contains `tsvector` of: -/// -/// * crate name (rank A-weight) -/// * latest release description (rank B-weight) -/// * latest release keywords (rank B-weight) -/// * latest release readme (rank C-weight) -/// * latest release root rustdoc (rank C-weight) -pub fn update_search_index(conn: &Connection) -> Result { - conn.execute(" - WITH doc as ( - SELECT DISTINCT ON(releases.crate_id) - releases.id, - releases.crate_id, - setweight(to_tsvector(crates.name), 'A') || - setweight(to_tsvector(coalesce(releases.description, '')), 'B') || - setweight(to_tsvector(coalesce(( - SELECT string_agg(value, ' ') - FROM json_array_elements_text(releases.keywords)), '')), 'B') - as content - FROM releases - INNER JOIN crates ON crates.id = releases.crate_id - ORDER BY releases.crate_id, releases.release_time DESC - ) - UPDATE crates - SET latest_version_id = doc.id, - content = doc.content - FROM doc - WHERE crates.id = doc.crate_id AND - (crates.latest_version_id = 0 OR crates.latest_version_id != doc.id);", - &[]) -} - - -/// Creates database tables -pub fn create_tables(conn: &Connection) -> Result<(), Error> { - let queries = ["CREATE TABLE crates ( - id SERIAL PRIMARY KEY, - name VARCHAR(255) UNIQUE NOT NULL, - latest_version_id INT DEFAULT 0, - versions JSON DEFAULT '[]', - downloads_total INT DEFAULT 0, - github_description VARCHAR(1024), - github_stars INT DEFAULT 0, - github_forks INT DEFAULT 0, - github_issues INT DEFAULT 0, - github_last_commit TIMESTAMP, - github_last_update TIMESTAMP, - content tsvector - )", - "CREATE TABLE releases ( - id SERIAL PRIMARY KEY, - crate_id INT NOT NULL REFERENCES crates(id), - version VARCHAR(100), - release_time TIMESTAMP, - dependencies JSON, - target_name VARCHAR(255), - yanked BOOL DEFAULT FALSE, - is_library BOOL DEFAULT TRUE, - build_status BOOL DEFAULT FALSE, - rustdoc_status BOOL DEFAULT FALSE, - test_status BOOL DEFAULT FALSE, - license VARCHAR(100), - repository_url VARCHAR(255), - homepage_url VARCHAR(255), - documentation_url VARCHAR(255), - description VARCHAR(1024), - description_long VARCHAR(51200), - readme VARCHAR(51200), - authors JSON, - keywords JSON, - have_examples BOOL DEFAULT FALSE, - downloads INT DEFAULT 0, - files JSON, - doc_targets JSON DEFAULT '[]', - doc_rustc_version VARCHAR(100) NOT NULL, - default_target VARCHAR(100), - UNIQUE (crate_id, version) - )", - "CREATE TABLE authors ( - id SERIAL PRIMARY KEY, - name VARCHAR(255), - email VARCHAR(255), - slug VARCHAR(255) UNIQUE NOT NULL - )", - "CREATE TABLE author_rels ( - rid INT REFERENCES releases(id), - aid INT REFERENCES authors(id), - UNIQUE(rid, aid) - )", - "CREATE TABLE keywords ( - id SERIAL PRIMARY KEY, - name VARCHAR(255), - slug VARCHAR(255) NOT NULL UNIQUE - )", - "CREATE TABLE keyword_rels ( - rid INT REFERENCES releases(id), - kid INT REFERENCES keywords(id), - UNIQUE(rid, kid) - )", - "CREATE TABLE owners ( - id SERIAL PRIMARY KEY, - login VARCHAR(255) NOT NULL UNIQUE, - avatar VARCHAR(255), - name VARCHAR(255), - email VARCHAR(255) - )", - "CREATE TABLE owner_rels ( - cid INT REFERENCES releases(id), - oid INT REFERENCES owners(id), - UNIQUE(cid, oid) - )", - "CREATE TABLE builds ( - id SERIAL, - rid INT NOT NULL REFERENCES releases(id), - rustc_version VARCHAR(100) NOT NULL, - cratesfyi_version VARCHAR(100) NOT NULL, - build_status BOOL NOT NULL, - build_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - output TEXT - )", - "CREATE TABLE queue ( - id SERIAL, - name VARCHAR(255), - version VARCHAR(100), - attempt INT DEFAULT 0, - date_added TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - UNIQUE(name, version) - )", - "CREATE TABLE files ( - path VARCHAR(4096) NOT NULL PRIMARY KEY, - mime VARCHAR(100) NOT NULL, - date_added TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - date_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - content BYTEA - )", - "CREATE INDEX ON releases (release_time DESC)", - "CREATE INDEX content_idx ON crates USING gin(content)", - "CREATE TABLE config ( - name VARCHAR(100) NOT NULL PRIMARY KEY, - value JSON NOT NULL - )", - "INSERT INTO config VALUES ('database_version', '1'::json)"]; - - for query in queries.into_iter() { - try!(conn.execute(query, &[])); - } - - Ok(()) -} - - - -#[cfg(test)] -mod test { - extern crate env_logger; - use super::*; - - #[test] - #[ignore] - fn test_connect_db() { - let conn = connect_db(); - assert!(conn.is_ok()); - } - - - #[test] - #[ignore] - fn test_create_tables() { - let _ = env_logger::try_init(); - let conn = connect_db(); - assert!(conn.is_ok()); - - // FIXME: As expected this test always fails if database is already created - let res = create_tables(&conn.unwrap()); - info!("RES: {:#?}", res); - assert!(res.is_ok()); - } -} diff --git a/src/docbuilder/chroot_builder.rs b/src/docbuilder/chroot_builder.rs deleted file mode 100644 index 1c07b158a..000000000 --- a/src/docbuilder/chroot_builder.rs +++ /dev/null @@ -1,505 +0,0 @@ - -use super::DocBuilder; -use super::crates::crates_from_path; -use super::metadata::Metadata; -use utils::{get_package, source_path, copy_doc_dir, - update_sources, parse_rustc_version, command_result}; -use db::{connect_db, add_package_into_database, add_build_into_database, add_path_into_database}; -use cargo::core::Package; -use cargo::util::CargoResultExt; -use std::process::Command; -use std::path::PathBuf; -use std::fs::remove_dir_all; -use postgres::Connection; -use rustc_serialize::json::{Json, ToJson}; -use error::Result; - - -/// List of targets supported by docs.rs -const TARGETS: [&'static str; 6] = [ - "i686-apple-darwin", - "i686-pc-windows-msvc", - "i686-unknown-linux-gnu", - "x86_64-apple-darwin", - "x86_64-pc-windows-msvc", - "x86_64-unknown-linux-gnu" -]; - - - -#[derive(Debug)] -pub struct ChrootBuilderResult { - pub output: String, - pub build_success: bool, - pub have_doc: bool, - pub have_examples: bool, - pub rustc_version: String, - pub cratesfyi_version: String, -} - - -impl DocBuilder { - /// Builds every package documentation in chroot environment - pub fn build_world(&mut self) -> Result<()> { - try!(update_sources()); - - let mut count = 0; - - crates(self.options.crates_io_index_path.clone(), |name, version| { - match self.build_package(name, version) { - Ok(status) => { - count += 1; - if status && count % 10 == 0 { - let _ = self.save_cache(); - } - } - Err(err) => warn!("Failed to build package {}-{}: {}", name, version, err), - } - self.cache.insert(format!("{}-{}", name, version)); - }) - } - - - /// Builds package documentation in chroot environment and adds into cratesfyi database - pub fn build_package(&mut self, name: &str, version: &str) -> Result { - // Skip crates according to options - if (self.options.skip_if_log_exists && - self.cache.contains(&format!("{}-{}", name, version)[..])) || - (self.options.skip_if_exists && - self.db_cache.contains(&format!("{}-{}", name, version)[..])) { - return Ok(false); - } - - info!("Building package {}-{}", name, version); - - // Start with clean documentation directory - try!(self.remove_build_dir()); - - // Database connection - let conn = try!(connect_db()); - - // get_package (and cargo) is using semver, add '=' in front of version. - let pkg = try!(get_package(name, Some(&format!("={}", version)[..]))); - let metadata = Metadata::from_package(&pkg)?; - let res = self.build_package_in_chroot(&pkg, metadata.default_target.clone()); - - // copy sources and documentation - let file_list = try!(self.add_sources_into_database(&conn, &pkg)); - let successfully_targets = if res.have_doc { - try!(self.copy_documentation(&pkg, - &res.rustc_version, - metadata.default_target.as_ref().map(String::as_str), - true)); - let successfully_targets = self.build_package_for_all_targets(&pkg); - for target in &successfully_targets { - try!(self.copy_documentation(&pkg, &res.rustc_version, Some(target), false)); - } - try!(self.add_documentation_into_database(&conn, &pkg)); - successfully_targets - } else { - Vec::new() - }; - - let release_id = try!(add_package_into_database(&conn, - &pkg, - &res, - Some(file_list), - successfully_targets)); - try!(add_build_into_database(&conn, &release_id, &res)); - - // remove documentation, source and build directory after we are done - try!(self.clean(&pkg)); - - // add package into build cache - self.cache.insert(format!("{}-{}", name, version)); - - Ok(res.build_success) - } - - - /// Builds documentation of a package with cratesfyi in chroot environment - fn build_package_in_chroot(&self, package: &Package, default_target: Option) -> ChrootBuilderResult { - debug!("Building package in chroot"); - let (rustc_version, cratesfyi_version) = self.get_versions(); - let cmd = format!("cratesfyi doc {} ={} {}", - package.manifest().name(), - package.manifest().version(), - default_target.as_ref().unwrap_or(&"".to_string())); - match self.chroot_command(cmd) { - Ok(o) => { - ChrootBuilderResult { - output: o, - build_success: true, - have_doc: self.have_documentation(&package, default_target), - have_examples: self.have_examples(&package), - rustc_version: rustc_version, - cratesfyi_version: cratesfyi_version, - } - } - Err(e) => { - ChrootBuilderResult { - output: e.to_string(), - build_success: false, - have_doc: false, - have_examples: self.have_examples(&package), - rustc_version: rustc_version, - cratesfyi_version: cratesfyi_version, - } - } - } - } - - - - /// Builds documentation of crate for every target and returns Vec of successfully targets - fn build_package_for_all_targets(&self, package: &Package) -> Vec { - let mut successfuly_targets = Vec::new(); - - for target in TARGETS.iter() { - debug!("Building {} for {}", canonical_name(&package), target); - let cmd = format!("cratesfyi doc {} ={} {}", - package.manifest().name(), - package.manifest().version(), - target); - if let Ok(_) = self.chroot_command(cmd) { - // Cargo is not giving any error and not generating documentation of some crates - // when we use a target compile options. Check documentation exists before - // adding target to successfully_targets. - // FIXME: Need to figure out why some docs are not generated with target option - let target_doc_path = PathBuf::from(&self.options.chroot_path) - .join("home") - .join(&self.options.chroot_user) - .join("cratesfyi") - .join(&target) - .join("doc"); - if target_doc_path.exists() { - successfuly_targets.push(target.to_string()); - } - } - } - successfuly_targets - } - - - /// Copies documentation to destination directory - fn copy_documentation(&self, - package: &Package, - rustc_version: &str, - target: Option<&str>, - is_default_target: bool) - -> Result<()> { - let mut crate_doc_path = PathBuf::from(&self.options.chroot_path) - .join("home") - .join(&self.options.chroot_user) - .join("cratesfyi"); - - // docs are available in cratesfyi/$TARGET when target is being used - if let Some(target) = target { - crate_doc_path.push(target); - } - - let mut destination = PathBuf::from(&self.options.destination) - .join(format!("{}/{}", - package.manifest().name(), - package.manifest().version())); - - // only add target name to destination directory when we are copying a non-default target. - // this is allowing us to host documents in the root of the crate documentation directory. - // for example winapi will be available in docs.rs/winapi/$version/winapi/ for it's - // default target: x86_64-pc-windows-msvc. But since it will be built under - // cratesfyi/x86_64-pc-windows-msvc we still need target in this function. - if !is_default_target { - if let Some(target) = target { - destination.push(target); - } - } - - copy_doc_dir(crate_doc_path, - destination, - parse_rustc_version(rustc_version)?.trim()) - } - - - /// Removes build directory of a package in chroot - fn remove_build_dir(&self) -> Result<()> { - let crate_doc_path = PathBuf::from(&self.options.chroot_path) - .join("home") - .join(&self.options.chroot_user) - .join("cratesfyi") - .join("doc"); - let _ = remove_dir_all(crate_doc_path); - for target in TARGETS.iter() { - let crate_doc_path = PathBuf::from(&self.options.chroot_path) - .join("home") - .join(&self.options.chroot_user) - .join("cratesfyi") - .join(target) - .join("doc"); - let _ = remove_dir_all(crate_doc_path); - } - Ok(()) - } - - - /// Remove documentation, build directory and sources directory of a package - fn clean(&self, package: &Package) -> Result<()> { - debug!("Cleaning package"); - use std::fs::remove_dir_all; - let documentation_path = PathBuf::from(&self.options.destination) - .join(package.manifest().name().as_str()); - let source_path = source_path(&package).unwrap(); - // Some crates don't have documentation, so we don't care if removing_dir_all fails - let _ = self.remove_build_dir(); - let _ = remove_dir_all(documentation_path); - let _ = remove_dir_all(source_path); - Ok(()) - } - - - /// Runs a command in a chroot environment - fn chroot_command>(&self, cmd: T) -> Result { - command_result(Command::new("sudo") - .arg("lxc-attach") - .arg("-n") - .arg(&self.options.container_name) - .arg("--") - .arg("su") - .arg("-") - .arg(&self.options.chroot_user) - .arg("-c") - .arg(cmd.as_ref()) - .output() - .unwrap()) - } - - - /// Checks a package build directory to determine if package have docs - /// - /// This function is checking first target in targets to see if documentation exists for a - /// crate. Package must be successfully built in chroot environment first. - fn have_documentation(&self, package: &Package, default_target: Option) -> bool { - let mut crate_doc_path = PathBuf::from(&self.options.chroot_path) - .join("home") - .join(&self.options.chroot_user) - .join("cratesfyi"); - - if let Some(default_doc_path) = default_target { - crate_doc_path.push(default_doc_path); - } - - crate_doc_path.push("doc"); - crate_doc_path.push(package.targets()[0].name().replace("-", "_").to_string()); - crate_doc_path.exists() - } - - - /// Checks if package have examples - fn have_examples(&self, package: &Package) -> bool { - let path = source_path(&package).unwrap().join("examples"); - path.exists() && path.is_dir() - } - - - /// Gets rustc and cratesfyi version from chroot environment - pub fn get_versions(&self) -> (String, String) { - // It is safe to use expect here - // chroot environment must always have rustc and cratesfyi installed - (String::from(self.chroot_command("rustc --version") - .expect("Failed to get rustc version") - .trim()), - String::from(self.chroot_command("cratesfyi --version") - .expect("Failed to get cratesfyi version") - .trim())) - } - - - /// Adds sources into database - fn add_sources_into_database(&self, conn: &Connection, package: &Package) -> Result { - debug!("Adding sources into database"); - let prefix = format!("sources/{}/{}", - package.manifest().name(), - package.manifest().version()); - add_path_into_database(conn, &prefix, source_path(&package).unwrap()) - } - - - /// Adds documentations into database - fn add_documentation_into_database(&self, - conn: &Connection, - package: &Package) - -> Result { - debug!("Adding documentation into database"); - let prefix = format!("rustdoc/{}/{}", - package.manifest().name(), - package.manifest().version()); - let crate_doc_path = PathBuf::from(&self.options.destination).join(format!("{}/{}", - package.manifest().name(), - package.manifest().version())); - add_path_into_database(conn, &prefix, crate_doc_path) - } - - - /// This function will build an empty crate and will add essential documentation files. - /// - /// It is required to run after every rustc update. cratesfyi is not keeping this files - /// for every crate to avoid duplications. - /// - /// List of the files: - /// - /// * rustdoc.css (with rustc version) - /// * main.css (with rustc version) - /// * main.js (with rustc version) - /// * jquery.js (with rustc version) - /// * playpen.js (with rustc version) - /// * normalize.css - /// * FiraSans-Medium.woff - /// * FiraSans-Regular.woff - /// * Heuristica-Italic.woff - /// * SourceCodePro-Regular.woff - /// * SourceCodePro-Semibold.woff - /// * SourceSerifPro-Bold.woff - /// * SourceSerifPro-Regular.woff - pub fn add_essential_files(&self) -> Result<()> { - use std::fs::{copy, create_dir_all}; - - // acme-client-0.0.0 is an empty library crate and it will always build - let pkg = try!(get_package("acme-client", Some("=0.0.0"))); - let res = self.build_package_in_chroot(&pkg, None); - let rustc_version = parse_rustc_version(&res.rustc_version)?; - - if !res.build_success { - return Err(format_err!("Failed to build empty crate for: {}", res.rustc_version)); - } - - info!("Copying essential files for: {}", res.rustc_version); - - let files = (// files require rustc version subfix - ["brush.svg", - "wheel.svg", - "down-arrow.svg", - "dark.css", - "light.css", - "main.js", - "normalize.css", - "rustdoc.css", - "settings.css", - "storage.js", - "theme.js", - "source-script.js", - "noscript.css", - "rust-logo.png"], - // favicon.ico is not needed because we set our own - // files doesn't require rustc version subfix - ["FiraSans-Medium.woff", - "FiraSans-Regular.woff", - "SourceCodePro-Regular.woff", - "SourceCodePro-Semibold.woff", - "SourceSerifPro-Bold.ttf.woff", - "SourceSerifPro-Regular.ttf.woff", - "SourceSerifPro-It.ttf.woff"]); - - let source = PathBuf::from(&self.options.chroot_path) - .join("home") - .join(&self.options.chroot_user) - .join("cratesfyi") - .join("doc"); - - // use copy_documentation destination directory so self.clean can remove it when - // we are done - let destination = PathBuf::from(&self.options.destination) - .join(format!("{}/{}", pkg.manifest().name(), pkg.manifest().version())); - try!(create_dir_all(&destination)); - - for file in files.0.iter() { - let spl: Vec<&str> = file.split('.').collect(); - let file_name = format!("{}-{}.{}", spl[0], rustc_version, spl[1]); - let source_path = source.join(&file_name); - let destination_path = destination.join(&file_name); - try!(copy(&source_path, &destination_path) - .chain_err(|| format!("couldn't copy '{}' to '{}'", source_path.display(), destination_path.display()))); - } - - for file in files.1.iter() { - let source_path = source.join(file); - let destination_path = destination.join(file); - try!(copy(&source_path, &destination_path) - .chain_err(|| format!("couldn't copy '{}' to '{}'", source_path.display(), destination_path.display()))); - } - - let conn = try!(connect_db()); - try!(add_path_into_database(&conn, "", destination)); - - try!(self.clean(&pkg)); - - let (vers, _) = self.get_versions(); - - try!(conn.query("INSERT INTO config (name, value) VALUES ('rustc_version', $1)", - &[&vers.to_json()]) - .or_else(|_| { - conn.query("UPDATE config SET value = $1 WHERE name = 'rustc_version'", - &[&vers.to_json()]) - })); - - Ok(()) - } -} - - -/// Returns canonical name of a package. -/// -/// It's just package-version. All directory structure used in cratesfyi is -/// following this naming scheme. -fn canonical_name(package: &Package) -> String { - format!("{}-{}", - package.manifest().name(), - package.manifest().version()) -} - - -/// Runs `func` with the all crates from crates-io.index repository path. -/// -/// First argument of func is the name of crate and -/// second argument is the version of crate. Func will be run for every crate. -fn crates(path: PathBuf, mut func: F) -> Result<()> - where F: FnMut(&str, &str) -> () -{ - crates_from_path(&path, &mut func) -} - - -#[cfg(test)] -mod test { - extern crate env_logger; - use std::path::PathBuf; - use {DocBuilder, DocBuilderOptions}; - - #[test] - #[ignore] - fn test_build_world() { - let _ = env_logger::try_init(); - let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix")); - let mut docbuilder = DocBuilder::new(options); - // This test is building WHOLE WORLD and may take forever - assert!(docbuilder.build_world().is_ok()); - } - - #[test] - #[ignore] - fn test_build_package() { - let _ = env_logger::try_init(); - let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix")); - let mut docbuilder = DocBuilder::new(options); - let res = docbuilder.build_package("rand", "0.3.14"); - assert!(res.is_ok()); - } - - #[test] - #[ignore] - fn test_add_essential_files() { - let _ = env_logger::try_init(); - let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix")); - let docbuilder = DocBuilder::new(options); - - docbuilder.add_essential_files().unwrap(); - } -} diff --git a/src/docbuilder/crates.rs b/src/docbuilder/crates.rs deleted file mode 100644 index b84e7b19d..000000000 --- a/src/docbuilder/crates.rs +++ /dev/null @@ -1,85 +0,0 @@ - -use std::io::prelude::*; -use std::io::BufReader; -use std::fs; -use std::path::PathBuf; -use rustc_serialize::json::Json; -use error::Result; -use failure::err_msg; - -fn crates_from_file(path: &PathBuf, func: &mut F) -> Result<()> - where F: FnMut(&str, &str) -> () -{ - - let reader = try!(fs::File::open(path).map(|f| BufReader::new(f))); - - let mut name = String::new(); - let mut versions = Vec::new(); - - for line in reader.lines() { - // some crates have invalid UTF-8 (nanny-sys-0.0.7) - // skip them - let line = match line { - Ok(l) => l, - Err(_) => continue, - }; - let data = match Json::from_str(line.trim()) { - Ok(d) => d, - Err(_) => continue, - }; - - let obj = try!(data.as_object().ok_or_else(|| err_msg("Not a JSON object"))); - let crate_name = try!(obj.get("name") - .and_then(|n| n.as_string()) - .ok_or_else(|| err_msg("`name` not found in JSON object"))); - let vers = try!(obj.get("vers") - .and_then(|n| n.as_string()) - .ok_or_else(|| err_msg("`vers` not found in JSON object"))); - - // Skip yanked crates - if obj.get("yanked").and_then(|n| n.as_boolean()).unwrap_or(false) { - continue; - } - - name.clear(); - name.push_str(crate_name); - versions.push(format!("{}", vers)); - } - - if !name.is_empty() { - versions.reverse(); - for version in versions { - func(&name[..], &version[..]); - } - } - - Ok(()) -} - - - -pub fn crates_from_path(path: &PathBuf, func: &mut F) -> Result<()> - where F: FnMut(&str, &str) -> () -{ - - if !path.is_dir() { - return Err(err_msg("Not a directory")); - } - - for file in try!(path.read_dir()) { - let file = try!(file); - let path = file.path(); - // skip files under .git and config.json - if path.to_str().unwrap().contains(".git") || path.file_name().unwrap() == "config.json" { - continue; - } - - if path.is_dir() { - try!(crates_from_path(&path, func)); - } else { - try!(crates_from_file(&path, func)); - } - } - - Ok(()) -} diff --git a/src/docbuilder/metadata.rs b/src/docbuilder/metadata.rs deleted file mode 100644 index e99e10cb4..000000000 --- a/src/docbuilder/metadata.rs +++ /dev/null @@ -1,186 +0,0 @@ - -use std::path::Path; -use cargo::core::Package; -use toml::Value; -use error::Result; -use failure::err_msg; - -/// Metadata for custom builds -/// -/// You can customize docs.rs builds by defining `[package.metadata.docs.rs]` table in your -/// crates' `Cargo.toml`. -/// -/// An example metadata: -/// -/// ```text -/// [package] -/// name = "test" -/// -/// [package.metadata.docs.rs] -/// features = [ "feature1", "feature2" ] -/// all-features = true -/// no-default-features = true -/// default-target = "x86_64-unknown-linux-gnu" -/// rustc-args = [ "--example-rustc-arg" ] -/// rustdoc-args = [ "--example-rustdoc-arg" ] -/// dependencies = [ "example-system-dependency" ] -/// ``` -/// -/// You can define one or more fields in your `Cargo.toml`. -pub struct Metadata { - /// List of features docs.rs will build. - /// - /// By default, docs.rs will only build default features. - pub features: Option>, - - /// Set `all-features` to true if you want docs.rs to build all features for your crate - pub all_features: bool, - - /// Docs.rs will always build default features. - /// - /// Set `no-default-fatures` to `false` if you want to build only certain features. - pub no_default_features: bool, - - /// Docs.rs is running on `x86_64-unknown-linux-gnu` target system and default documentation - /// is always built on this target. You can change default target by setting this. - pub default_target: Option, - - /// List of command line arguments for `rustc`. - pub rustc_args: Option>, - - /// List of command line arguments for `rustdoc`. - pub rustdoc_args: Option>, - - /// System dependencies. - /// - /// Docs.rs is running on a Debian jessie. - pub dependencies: Option>, -} - - - -impl Metadata { - pub fn from_package(pkg: &Package) -> Result { - let src_path = pkg.manifest_path().parent().ok_or_else(|| err_msg("Source path not available"))?; - for c in ["Cargo.toml.orig", "Cargo.toml"].iter() { - let manifest_path = src_path.clone().join(c); - if manifest_path.exists() { - return Ok(Metadata::from_manifest(manifest_path)); - } - } - Err(err_msg("Manifest not found")) - } - - pub fn from_manifest>(path: P) -> Metadata { - use std::fs::File; - use std::io::Read; - let mut f = match File::open(path) { - Ok(f) => f, - Err(_) => return Metadata::default(), - }; - let mut s = String::new(); - if let Err(_) = f.read_to_string(&mut s) { - return Metadata::default(); - } - Metadata::from_str(&s) - } - - - // This is similar to Default trait but it's private - fn default() -> Metadata { - Metadata { - features: None, - all_features: false, - no_default_features: false, - default_target: None, - rustc_args: None, - rustdoc_args: None, - dependencies: None, - } - } - - - fn from_str(manifest: &str) -> Metadata { - let mut metadata = Metadata::default(); - - let manifest = match manifest.parse::() { - Ok(m) => m, - Err(_) => return metadata, - }; - - if let Some(table) = manifest.get("package").and_then(|p| p.as_table()) - .and_then(|p| p.get("metadata")).and_then(|p| p.as_table()) - .and_then(|p| p.get("docs")).and_then(|p| p.as_table()) - .and_then(|p| p.get("rs")).and_then(|p| p.as_table()) { - metadata.features = table.get("features").and_then(|f| f.as_array()) - .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect()); - metadata.no_default_features = table.get("no-default-features") - .and_then(|v| v.as_bool()).unwrap_or(metadata.no_default_features); - metadata.all_features = table.get("all-features") - .and_then(|v| v.as_bool()).unwrap_or(metadata.all_features); - metadata.default_target = table.get("default-target") - .and_then(|v| v.as_str()).map(|v| v.to_owned()); - metadata.rustc_args = table.get("rustc-args").and_then(|f| f.as_array()) - .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect()); - metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_array()) - .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect()); - metadata.dependencies = table.get("dependencies").and_then(|f| f.as_array()) - .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect()); - } - - metadata - } -} - - - -#[cfg(test)] -mod test { - extern crate env_logger; - use super::Metadata; - - #[test] - fn test_cratesfyi_metadata() { - let _ = env_logger::try_init(); - let manifest = r#" - [package] - name = "test" - - [package.metadata.docs.rs] - features = [ "feature1", "feature2" ] - all-features = true - no-default-features = true - default-target = "x86_64-unknown-linux-gnu" - rustc-args = [ "--example-rustc-arg" ] - rustdoc-args = [ "--example-rustdoc-arg" ] - dependencies = [ "example-system-dependency" ] - "#; - - let metadata = Metadata::from_str(manifest); - - assert!(metadata.features.is_some()); - assert!(metadata.all_features == true); - assert!(metadata.no_default_features == true); - assert!(metadata.default_target.is_some()); - assert!(metadata.rustdoc_args.is_some()); - - let features = metadata.features.unwrap(); - assert_eq!(features.len(), 2); - assert_eq!(features[0], "feature1".to_owned()); - assert_eq!(features[1], "feature2".to_owned()); - - assert_eq!(metadata.default_target.unwrap(), "x86_64-unknown-linux-gnu".to_owned()); - - let rustc_args = metadata.rustc_args.unwrap(); - assert_eq!(rustc_args.len(), 1); - assert_eq!(rustc_args[0], "--example-rustc-arg".to_owned()); - - let rustdoc_args = metadata.rustdoc_args.unwrap(); - assert_eq!(rustdoc_args.len(), 1); - assert_eq!(rustdoc_args[0], "--example-rustdoc-arg".to_owned()); - - let dependencies = metadata.dependencies.unwrap(); - assert_eq!(dependencies.len(), 1); - assert_eq!(dependencies[0], "example-system-dependency".to_owned()); - } -} diff --git a/src/docbuilder/mod.rs b/src/docbuilder/mod.rs deleted file mode 100644 index 3fe748abd..000000000 --- a/src/docbuilder/mod.rs +++ /dev/null @@ -1,117 +0,0 @@ - -pub mod options; -pub mod metadata; -mod chroot_builder; -mod crates; -mod queue; - -pub use self::chroot_builder::ChrootBuilderResult; - - -use std::fs; -use std::io::prelude::*; -use std::io::BufReader; -use std::path::PathBuf; -use std::collections::BTreeSet; -use DocBuilderOptions; -use error::Result; - - -/// chroot based documentation builder -pub struct DocBuilder { - options: DocBuilderOptions, - cache: BTreeSet, - db_cache: BTreeSet, -} - - -impl DocBuilder { - pub fn new(options: DocBuilderOptions) -> DocBuilder { - DocBuilder { - options: options, - cache: BTreeSet::new(), - db_cache: BTreeSet::new(), - } - } - - - /// Loads build cache - pub fn load_cache(&mut self) -> Result<()> { - debug!("Loading cache"); - let path = PathBuf::from(&self.options.prefix).join("cache"); - let reader = fs::File::open(path).map(|f| BufReader::new(f)); - - if reader.is_err() { - return Ok(()); - } - - for line in reader.unwrap().lines() { - self.cache.insert(try!(line)); - } - - try!(self.load_database_cache()); - - Ok(()) - } - - - fn load_database_cache(&mut self) -> Result<()> { - debug!("Loading database cache"); - use db::connect_db; - let conn = try!(connect_db()); - - for row in &conn.query("SELECT name, version FROM crates, releases \ - WHERE crates.id = releases.crate_id", - &[]) - .unwrap() { - let name: String = row.get(0); - let version: String = row.get(1); - self.db_cache.insert(format!("{}-{}", name, version)); - } - - Ok(()) - } - - - /// Saves build cache - pub fn save_cache(&self) -> Result<()> { - debug!("Saving cache"); - let path = PathBuf::from(&self.options.prefix).join("cache"); - let mut file = try!(fs::OpenOptions::new() - .write(true) - .create(true) - .open(path)); - for krate in &self.cache { - try!(writeln!(file, "{}", krate)); - } - Ok(()) - } - - - fn lock_path(&self) -> PathBuf { - self.options.prefix.join("cratesfyi.lock") - } - - /// Creates a lock file. Daemon will check this lock file and stop operating if its exists. - pub fn lock(&self) -> Result<()> { - let path = self.lock_path(); - if !path.exists() { - try!(fs::OpenOptions::new().write(true).create(true).open(path)); - } - Ok(()) - } - - /// Removes lock file. - pub fn unlock(&self) -> Result<()> { - let path = self.lock_path(); - if path.exists() { - try!(fs::remove_file(path)); - } - Ok(()) - } - - /// Returns a reference of options - pub fn options(&self) -> &DocBuilderOptions { - &self.options - } -} diff --git a/src/docbuilder/options.rs b/src/docbuilder/options.rs deleted file mode 100644 index 7cb6d8af0..000000000 --- a/src/docbuilder/options.rs +++ /dev/null @@ -1,113 +0,0 @@ - - -use std::{env, fmt}; -use std::path::PathBuf; -use error::Result; - -#[derive(Clone)] -pub struct DocBuilderOptions { - pub keep_build_directory: bool, - pub prefix: PathBuf, - pub destination: PathBuf, - pub chroot_path: PathBuf, - pub chroot_user: String, - pub container_name: String, - pub crates_io_index_path: PathBuf, - pub skip_if_exists: bool, - pub skip_if_log_exists: bool, - pub skip_oldest_versions: bool, - pub build_only_latest_version: bool, - pub debug: bool, -} - - - -impl Default for DocBuilderOptions { - fn default() -> DocBuilderOptions { - - let cwd = env::current_dir().unwrap(); - - let (prefix, destination, chroot_path, crates_io_index_path) = - generate_paths(cwd); - - DocBuilderOptions { - prefix: prefix, - destination: destination, - chroot_path: chroot_path, - crates_io_index_path: crates_io_index_path, - - chroot_user: "cratesfyi".to_string(), - container_name: "cratesfyi-container".to_string(), - - keep_build_directory: false, - skip_if_exists: false, - skip_if_log_exists: false, - skip_oldest_versions: false, - build_only_latest_version: false, - debug: false, - } - } -} - - -impl fmt::Debug for DocBuilderOptions { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, - "DocBuilderOptions {{ destination: {:?}, chroot_path: {:?}, \ - crates_io_index_path: {:?}, \ - container_name: {:?}, chroot_user: {:?}, \ - keep_build_directory: {:?}, skip_if_exists: {:?}, \ - skip_if_log_exists: {:?}, debug: {:?} }}", - self.destination, - self.chroot_path, - self.crates_io_index_path, - self.container_name, - self.chroot_user, - self.keep_build_directory, - self.skip_if_exists, - self.skip_if_log_exists, - self.debug) - } -} - - -impl DocBuilderOptions { - /// Creates new DocBuilderOptions from prefix - pub fn from_prefix(prefix: PathBuf) -> DocBuilderOptions { - let (prefix, destination, chroot_path, crates_io_index_path) = - generate_paths(prefix); - DocBuilderOptions { - prefix: prefix, - destination: destination, - chroot_path: chroot_path, - crates_io_index_path: crates_io_index_path, - - ..Default::default() - } - } - - - pub fn check_paths(&self) -> Result<()> { - if !self.destination.exists() { - bail!("destination path '{}' does not exist", self.destination.display()); - } - if !self.chroot_path.exists() { - bail!("chroot path '{}' does not exist", self.chroot_path.display()); - } - if !self.crates_io_index_path.exists() { - bail!("crates.io-index path '{}' does not exist", self.crates_io_index_path.display()); - } - Ok(()) - } -} - - - -fn generate_paths(prefix: PathBuf) -> (PathBuf, PathBuf, PathBuf, PathBuf) { - - let destination = PathBuf::from(&prefix).join("documentations"); - let chroot_path = PathBuf::from(&prefix).join("cratesfyi-container/rootfs"); - let crates_io_index_path = PathBuf::from(&prefix).join("crates.io-index"); - - (prefix, destination, chroot_path, crates_io_index_path) -} diff --git a/src/docbuilder/queue.rs b/src/docbuilder/queue.rs deleted file mode 100644 index 23fdc7757..000000000 --- a/src/docbuilder/queue.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! Updates crates.io index and builds new packages - - -use super::DocBuilder; -use db::connect_db; -use error::Result; -use crates_index_diff::{ChangeKind, Index}; - - -impl DocBuilder { - /// Updates crates.io-index repository and adds new crates into build queue. - /// Returns size of queue - pub fn get_new_crates(&mut self) -> Result { - let conn = try!(connect_db()); - let index = try!(Index::from_path_or_cloned(&self.options.crates_io_index_path)); - let mut changes = try!(index.fetch_changes()); - - // I belive this will fix ordering of queue if we get more than one crate from changes - changes.reverse(); - - for krate in changes.iter().filter(|k| k.kind != ChangeKind::Yanked) { - conn.execute("INSERT INTO queue (name, version) VALUES ($1, $2)", - &[&krate.name, &krate.version]) - .ok(); - debug!("{}-{} added into build queue", krate.name, krate.version); - } - - let queue_count = conn.query("SELECT COUNT(*) FROM queue WHERE attempt < 5", &[]) - .unwrap() - .get(0) - .get(0); - - Ok(queue_count) - } - - - /// Builds packages from queue - pub fn build_packages_queue(&mut self) -> Result { - let conn = try!(connect_db()); - let mut build_count = 0; - - for row in &try!(conn.query("SELECT id, name, version - FROM queue - WHERE attempt < 5 - ORDER BY id ASC", - &[])) { - let id: i32 = row.get(0); - let name: String = row.get(1); - let version: String = row.get(2); - - match self.build_package(&name[..], &version[..]) { - Ok(_) => { - build_count += 1; - let _ = conn.execute("DELETE FROM queue WHERE id = $1", &[&id]); - } - Err(e) => { - // Increase attempt count - let _ = conn.execute("UPDATE queue SET attempt = attempt + 1 WHERE id = $1", - &[&id]); - error!("Failed to build package {}-{} from queue: {}", - name, - version, - e) - } - } - } - - Ok(build_count) - } -} - -#[cfg(test)] -mod test { - extern crate env_logger; - use std::path::PathBuf; - use {DocBuilder, DocBuilderOptions}; - - #[test] - #[ignore] - fn test_get_new_crates() { - let _ = env_logger::try_init(); - let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix")); - let mut docbuilder = DocBuilder::new(options); - let res = docbuilder.get_new_crates(); - if res.is_err() { - error!("{:?}", res); - } - assert!(res.is_ok()); - } - - - #[test] - #[ignore] - fn test_build_packages_queue() { - let _ = env_logger::try_init(); - let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix")); - let mut docbuilder = DocBuilder::new(options); - assert!(docbuilder.build_packages_queue().is_ok()); - } -} diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index 3f200eff0..000000000 --- a/src/error.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Errors used in cratesfyi - -use std::result::Result as StdResult; - -pub use failure::{Error, ResultExt}; - -pub type Result = StdResult; diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 17bc0af96..000000000 --- a/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! [Docs.rs](https://docs.rs) (formerly cratesfyi) is an open source project to host -//! documentation of crates for the Rust Programming Language. - -#[macro_use] -extern crate log; -#[macro_use] -extern crate failure; -extern crate cargo; -extern crate regex; -extern crate rustc_serialize; -extern crate postgres; -extern crate reqwest; -extern crate time; -extern crate semver; -extern crate slug; -extern crate magic; -extern crate iron; -extern crate router; -extern crate staticfile; -extern crate handlebars_iron; -extern crate comrak; -extern crate r2d2; -extern crate r2d2_postgres; -extern crate url; -extern crate params; -extern crate libc; -extern crate badge; -extern crate crates_index_diff; -extern crate git2; -extern crate toml; -extern crate html5ever; - -pub use self::docbuilder::DocBuilder; -pub use self::docbuilder::ChrootBuilderResult; -pub use self::docbuilder::options::DocBuilderOptions; -pub use self::docbuilder::metadata::Metadata; -pub use self::web::start_web_server; - -pub mod error; -pub mod db; -pub mod utils; -mod docbuilder; -mod web; - - -/// Version string generated at build time contains last git -/// commit hash and build date -pub const BUILD_VERSION: &'static str = concat!(env!("CARGO_PKG_VERSION"), - " ", - include_str!(concat!(env!("OUT_DIR"), - "/git_version"))); diff --git a/src/utils/build_doc.rs b/src/utils/build_doc.rs deleted file mode 100644 index a6e6e3cb1..000000000 --- a/src/utils/build_doc.rs +++ /dev/null @@ -1,240 +0,0 @@ -//! Crate documentation builder -//! -//! This module is extremely similar to cargo install operation, except it's building -//! documentation of a crate and not installing anything. - -use std::path::{Path, PathBuf}; -use std::env; -use std::sync::Arc; - -use cargo::core::{self, SourceId, Dependency, Source, Package, Workspace}; -use cargo::core::compiler::{DefaultExecutor, CompileMode, MessageFormat, BuildConfig, Executor}; -use cargo::core::package::PackageSet; -use cargo::core::registry::PackageRegistry; -use cargo::core::resolver; -use cargo::core::source::SourceMap; -use cargo::util::{CargoResult, Config, internal, Filesystem}; -use cargo::sources::SourceConfigMap; -use cargo::ops::{self, Packages}; - -use utils::{get_current_versions, parse_rustc_version}; -use error::Result; - -use Metadata; - - -/// Builds documentation of a crate and version. -/// -/// Crate will be built into current working directory/crate-version. -/// -/// It will build latest version, if no version is given. -// idea is to make cargo to download -// and build a crate and its documentation -// instead of doing it manually like in the previous version of cratesfyi -pub fn build_doc(name: &str, vers: Option<&str>, target: Option<&str>) -> Result { - core::enable_nightly_features(); - let config = try!(Config::default()); - let source_id = try!(SourceId::crates_io(&config)); - - let source_cfg_map = try!(SourceConfigMap::new(&config)); - let mut source = try!(source_cfg_map.load(source_id)); - - // update crates.io-index registry - try!(source.update()); - - let dep = try!(Dependency::parse_no_deprecated(name, vers, source_id)); - let deps = try!(source.query_vec(&dep)); - let pkgid = try!(deps.iter().map(|p| p.package_id()).max() - // FIXME: This is probably not a rusty way to handle options and results - // or maybe it is who knows... - .ok_or(internal("no package id available"))); - - let mut source_map = SourceMap::new(); - source_map.insert(source); - - let pkg_set = try!(PackageSet::new(&[pkgid.clone()], source_map, &config)); - - let pkg = try!(pkg_set.get_one(pkgid)).clone(); - - let current_dir = try!(env::current_dir()); - let target_dir = PathBuf::from(current_dir).join("cratesfyi"); - - let metadata = Metadata::from_package(&pkg).map_err(|e| internal(e.to_string()))?; - - // This is only way to pass rustc_args to cargo. - // CompileOptions::target_rustc_args is used only for the current crate, - // and since docs.rs never runs rustc on the current crate, we assume rustc_args - // will be used for the dependencies. That is why we are creating RUSTFLAGS environment - // variable instead of using target_rustc_args. - if let Some(rustc_args) = metadata.rustc_args { - env::set_var("RUSTFLAGS", rustc_args.join(" ")); - } - - // since https://github.com/rust-lang/rust/pull/48511 we can pass --resource-suffix to - // add correct version numbers to css and javascript files - let mut rustdoc_args: Vec = - vec!["-Z".to_string(), "unstable-options".to_string(), - "--resource-suffix".to_string(), - format!("-{}", parse_rustc_version(get_current_versions()?.0)?), - "--static-root-path".to_string(), "/".to_string(), - "--disable-per-crate-search".to_string()]; - - // since https://github.com/rust-lang/rust/pull/51384, we can pass --extern-html-root-url to - // force rustdoc to link to other docs.rs docs for dependencies - let source = try!(source_cfg_map.load(source_id)); - for (name, dep) in try!(resolve_deps(&pkg, &config, source)) { - rustdoc_args.push("--extern-html-root-url".to_string()); - rustdoc_args.push(format!("{}=https://docs.rs/{}/{}", - name.replace("-", "_"), dep.name(), dep.version())); - } - - if let Some(package_rustdoc_args) = metadata.rustdoc_args { - rustdoc_args.append(&mut package_rustdoc_args.iter().map(|s| s.to_owned()).collect()); - } - - let mut build_config = try!(BuildConfig::new(&config, - None, - &target.map(|t| t.to_string()), - CompileMode::Doc { deps: false })); - build_config.release = false; - build_config.message_format = MessageFormat::Human; - - let opts = ops::CompileOptions { - config: &config, - build_config, - features: metadata.features.unwrap_or(Vec::new()), - all_features: metadata.all_features, - no_default_features: metadata.no_default_features, - spec: Packages::Packages(Vec::new()), - filter: ops::CompileFilter::new(true, - Vec::new(), false, - Vec::new(), false, - Vec::new(), false, - Vec::new(), false, - false), - target_rustc_args: None, - target_rustdoc_args: Some(rustdoc_args), - local_rustdoc_args: None, - export_dir: None, - }; - - let ws = try!(Workspace::ephemeral(pkg, &config, Some(Filesystem::new(target_dir)), false)); - let exec: Arc = Arc::new(DefaultExecutor); - let source = try!(source_cfg_map.load(source_id)); - try!(ops::compile_ws(&ws, Some(source), &opts, &exec)); - - Ok(try!(ws.current()).clone()) -} - -fn resolve_deps<'cfg>(pkg: &Package, config: &'cfg Config, src: Box) - -> CargoResult> -{ - let mut registry = try!(PackageRegistry::new(config)); - registry.add_preloaded(src); - registry.lock_patches(); - - let resolver = try!(resolver::resolve( - &[(pkg.summary().clone(), resolver::Method::Everything)], - pkg.manifest().replace(), - &mut registry, - &Default::default(), - None, - false, - )); - let dep_ids = resolver.deps(pkg.package_id()).map(|p| p.0).collect::>(); - let pkg_set = try!(registry.get(&dep_ids)); - let deps = try!(pkg_set.get_many(dep_ids)); - - let mut ret = Vec::new(); - for dep in deps { - if let Some(d) = pkg.dependencies().iter().find(|d| d.package_name() == dep.name()) { - ret.push((d.name_in_toml().to_string(), dep.clone())); - } - } - - Ok(ret) -} - -/// Downloads a crate and returns Cargo Package. -pub fn get_package(name: &str, vers: Option<&str>) -> CargoResult { - core::enable_nightly_features(); - debug!("Getting package with cargo"); - let config = try!(Config::default()); - let source_id = try!(SourceId::crates_io(&config)); - - let source_map = try!(SourceConfigMap::new(&config)); - let mut source = try!(source_map.load(source_id)); - - try!(source.update()); - - let dep = try!(Dependency::parse_no_deprecated(name, vers, source_id)); - let deps = try!(source.query_vec(&dep)); - let pkgid = try!(deps.iter().map(|p| p.package_id()).max() - // FIXME: This is probably not a rusty way to handle options and results - // or maybe it is who knows... - .ok_or(internal("no package id available"))); - - let mut source_map = SourceMap::new(); - source_map.insert(source); - - let pkg_set = try!(PackageSet::new(&[pkgid.clone()], source_map, &config)); - - let pkg = try!(pkg_set.get_one(pkgid)).clone(); - - Ok(pkg) -} - - -/// Updates central crates-io.index repository -pub fn update_sources() -> CargoResult<()> { - let config = try!(Config::default()); - let source_id = try!(SourceId::crates_io(&config)); - - let source_map = try!(SourceConfigMap::new(&config)); - let mut source = try!(source_map.load(source_id)); - - source.update() -} - - -/// Gets source path of a downloaded package. -pub fn source_path(pkg: &Package) -> Option<&Path> { - // parent of the manifest file is where source codes are stored - pkg.manifest_path().parent() -} - - - - -#[cfg(test)] -mod test { - use std::path::Path; - use super::*; - - #[test] - fn test_get_package() { - let pkg = get_package("rand", None); - assert!(pkg.is_ok()); - - let pkg = pkg.unwrap(); - - let manifest = pkg.manifest(); - assert_eq!(manifest.name().as_str(), "rand"); - } - - - #[test] - fn test_source_path() { - let pkg = get_package("rand", None).unwrap(); - let source_path = source_path(&pkg).unwrap(); - assert!(source_path.is_dir()); - - let cargo_toml_path = Path::new(source_path).join("Cargo.toml"); - assert!(cargo_toml_path.exists()); - assert!(cargo_toml_path.is_file()); - - let src_path = Path::new(source_path).join("src"); - assert!(src_path.exists()); - assert!(src_path.is_dir()); - } -} diff --git a/src/utils/copy.rs b/src/utils/copy.rs deleted file mode 100644 index bc73c8dd1..000000000 --- a/src/utils/copy.rs +++ /dev/null @@ -1,124 +0,0 @@ - -// FIXME: There is so many PathBuf's in this module -// Conver them to Path - -use std::path::{Path, PathBuf}; -use std::fs; -use error::Result; - -use regex::Regex; - - -/// Copies files from source directory to destination directory. -pub fn copy_dir>(source: P, destination: P) -> Result<()> { - copy_files_and_handle_html(source.as_ref().to_path_buf(), - destination.as_ref().to_path_buf(), - false, - "") -} - - -/// Copies documentation from a crate's target directory to destination. -/// -/// Target directory must have doc directory. -/// -/// This function is designed to avoid file duplications. It is using rustc version string -/// to rename common files (css files, jquery.js, playpen.js, main.js etc.) in a standard rustdoc. -pub fn copy_doc_dir>(target: P, - destination: P, - rustc_version: &str) - -> Result<()> { - let source = PathBuf::from(target.as_ref()).join("doc"); - copy_files_and_handle_html(source, - destination.as_ref().to_path_buf(), - true, - rustc_version) -} - - -fn copy_files_and_handle_html(source: PathBuf, - destination: PathBuf, - handle_html: bool, - rustc_version: &str) - -> Result<()> { - - // FIXME: handle_html is useless since we started using --resource-suffix - // argument with rustdoc - - // Make sure destination directory is exists - if !destination.exists() { - try!(fs::create_dir_all(&destination)); - } - - // Avoid copying common files - let dup_regex = Regex::new( - r"(\.lock|\.txt|\.woff|\.svg|\.css|main-.*\.css|main-.*\.js|normalize-.*\.js|rustdoc-.*\.css|storage-.*\.js|theme-.*\.js)$") - .unwrap(); - - for file in try!(source.read_dir()) { - - let file = try!(file); - let mut destination_full_path = PathBuf::from(&destination); - destination_full_path.push(file.file_name()); - - let metadata = try!(file.metadata()); - - if metadata.is_dir() { - try!(fs::create_dir_all(&destination_full_path)); - try!(copy_files_and_handle_html(file.path(), - destination_full_path, - handle_html, - &rustc_version)) - } else if handle_html && dup_regex.is_match(&file.file_name().into_string().unwrap()[..]) { - continue; - } else { - try!(fs::copy(&file.path(), &destination_full_path)); - } - - } - Ok(()) -} - - - -#[cfg(test)] -mod test { - extern crate env_logger; - extern crate tempdir; - use std::fs; - use std::path::Path; - use super::*; - - #[test] - #[ignore] - fn test_copy_dir() { - let destination = tempdir::TempDir::new("cratesfyi").unwrap(); - - // lets try to copy a src directory to tempdir - let res = copy_dir(Path::new("src"), destination.path()); - // remove temp dir - fs::remove_dir_all(destination.path()).unwrap(); - - assert!(res.is_ok()); - } - - - #[test] - #[ignore] - fn test_copy_doc_dir() { - // lets build documentation of rand crate - use utils::build_doc; - let pkg = build_doc("rand", None, None).unwrap(); - - let pkg_dir = format!("rand-{}", pkg.manifest().version()); - let target = Path::new(&pkg_dir); - let destination = tempdir::TempDir::new("cratesfyi").unwrap(); - let res = copy_doc_dir(target, destination.path(), "UNKNOWN"); - - // remove build and temp dir - fs::remove_dir_all(target).unwrap(); - fs::remove_dir_all(destination.path()).unwrap(); - - assert!(res.is_ok()); - } -} diff --git a/src/utils/daemon.rs b/src/utils/daemon.rs deleted file mode 100644 index 0b1e25c45..000000000 --- a/src/utils/daemon.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! Simple daemon -//! -//! This daemon will start web server, track new packages and build them - - -use std::{env, thread}; -use std::process::exit; -use std::fs::File; -use std::io::Write; -use std::time::Duration; -use std::path::PathBuf; -use libc::fork; -use time; -use DocBuilderOptions; -use DocBuilder; -use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub}; -use db::{connect_db, update_search_index}; - - - -pub fn start_daemon() { - // first check required environment variables - for v in ["CRATESFYI_PREFIX", - "CRATESFYI_PREFIX", - "CRATESFYI_GITHUB_USERNAME", - "CRATESFYI_GITHUB_ACCESSTOKEN"] - .iter() { - env::var(v).expect("Environment variable not found"); - } - - let dbopts = opts(); - - // check paths once - dbopts.check_paths().unwrap(); - - // fork the process - let pid = unsafe { fork() }; - if pid > 0 { - let mut file = File::create(dbopts.prefix.join("cratesfyi.pid")) - .expect("Failed to create pid file"); - writeln!(&mut file, "{}", pid).expect("Failed to write pid"); - - info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid); - exit(0); - } - - - // check new crates every minute - thread::spawn(move || { - loop { - thread::sleep(Duration::from_secs(60)); - - let mut opts = opts(); - opts.skip_if_exists = true; - - // check lock file - if opts.prefix.join("cratesfyi.lock").exists() { - warn!("Lock file exits, skipping building new crates"); - continue; - } - - let mut doc_builder = DocBuilder::new(opts); - - debug!("Checking new crates"); - let queue_count = match doc_builder.get_new_crates() { - Ok(size) => size, - Err(e) => { - error!("Failed to get new crates: {}", e); - continue; - } - }; - - // Only build crates if there is any - if queue_count == 0 { - debug!("Queue is empty, going back to sleep"); - continue; - } - - info!("Building {} crates from queue", queue_count); - - // update index - if let Err(e) = update_sources() { - error!("Failed to update sources: {}", e); - continue; - } - - if let Err(e) = doc_builder.load_cache() { - error!("Failed to load cache: {}", e); - continue; - } - - - // Run build_packages_queue in it's own thread to catch panics - // This only panicked twice in the last 6 months but its just a better - // idea to do this. - let res = thread::spawn(move || { - match doc_builder.build_packages_queue() { - Err(e) => error!("Failed build new crates: {}", e), - Ok(n) => { - if n > 0 { - match pubsubhubbub::ping_hubs() { - Err(e) => error!("Failed to ping hub: {}", e), - Ok(n) => debug!("Succesfully pinged {} hubs", n) - } - } - } - } - - if let Err(e) = doc_builder.save_cache() { - error!("Failed to save cache: {}", e); - } - - debug!("Finished building new crates, going back to sleep"); - }) - .join(); - - if let Err(e) = res { - error!("GRAVE ERROR Building new crates panicked: {:?}", e); - } - } - }); - - - // update release activity everyday at 23:55 - thread::spawn(move || { - loop { - thread::sleep(Duration::from_secs(60)); - let now = time::now(); - if now.tm_hour == 23 && now.tm_min == 55 { - info!("Updating release activity"); - if let Err(e) = update_release_activity() { - error!("Failed to update release activity: {}", e); - } - } - } - }); - - - // update search index every 3 hours - thread::spawn(move || { - loop { - thread::sleep(Duration::from_secs(60 * 60 * 3)); - let conn = connect_db().expect("Failed to connect database"); - if let Err(e) = update_search_index(&conn) { - error!("Failed to update search index: {}", e); - } - } - }); - - - // update github stats every 6 hours - thread::spawn(move || { - loop { - thread::sleep(Duration::from_secs(60 * 60 * 6)); - if let Err(e) = github_updater() { - error!("Failed to update github fields: {}", e); - } - } - }); - - // TODO: update ssl certificate every 3 months - - // at least start web server - info!("Starting web server"); - ::start_web_server(None); -} - - - -fn opts() -> DocBuilderOptions { - let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX") - .expect("CRATESFYI_PREFIX environment variable not found")); - DocBuilderOptions::from_prefix(prefix) -} diff --git a/src/utils/github_updater.rs b/src/utils/github_updater.rs deleted file mode 100644 index 9d45d2dc1..000000000 --- a/src/utils/github_updater.rs +++ /dev/null @@ -1,185 +0,0 @@ - -use ::db::connect_db; -use regex::Regex; -use time; -use error::Result; -use failure::err_msg; - - -/// Fields we need use in cratesfyi -#[derive(Debug)] -struct GitHubFields { - pub description: String, - pub stars: i64, - pub forks: i64, - pub issues: i64, - pub last_commit: time::Timespec, -} - - -/// Updates github fields in crates table -pub fn github_updater() -> Result<()> { - let conn = try!(connect_db()); - - // TODO: This query assumes repository field in Cargo.toml is - // always the same across all versions of a crate - for row in &try!(conn.query("SELECT DISTINCT ON (crates.name) - crates.name, - crates.id, - releases.repository_url - FROM crates - INNER JOIN releases ON releases.crate_id = crates.id - WHERE releases.repository_url ~ '^https*://github.com' AND - (crates.github_last_update < NOW() - INTERVAL '1 day' OR - crates.github_last_update IS NULL) - ORDER BY crates.name, releases.release_time DESC", - &[])) { - let crate_name: String = row.get(0); - let crate_id: i32 = row.get(1); - let repository_url: String = row.get(2); - - if let Err(err) = get_github_path(&repository_url[..]) - .ok_or_else(|| err_msg("Failed to get github path")) - .and_then(|path| get_github_fields(&path[..])) - .and_then(|fields| { - conn.execute("UPDATE crates - SET github_description = $1, - github_stars = $2, github_forks = $3, - github_issues = $4, github_last_commit = $5, - github_last_update = NOW() WHERE id = $6", - &[&fields.description, - &(fields.stars as i32), - &(fields.forks as i32), - &(fields.issues as i32), - &(fields.last_commit), - &crate_id]) - .or_else(|e| Err(e.into())) - }) { - debug!("Failed to update github fields of: {} {}", crate_name, err); - } - - // sleep for rate limits - use std::thread; - use std::time::Duration; - thread::sleep(Duration::from_secs(2)); - } - - Ok(()) -} - - -fn get_github_fields(path: &str) -> Result { - use rustc_serialize::json::Json; - - let body = { - use std::io::Read; - use reqwest::{Client, StatusCode}; - use reqwest::header::USER_AGENT; - use std::env; - - let client = Client::new(); - let mut body = String::new(); - - let mut resp = try!(client.get(&format!("https://api.github.com/repos/{}", path)[..]) - .header(USER_AGENT, format!("cratesfyi/{}", env!("CARGO_PKG_VERSION"))) - .basic_auth( - env::var("CRATESFYI_GITHUB_USERNAME") - .ok() - .and_then(|u| Some(u.to_string())) - .unwrap_or("".to_string()), - env::var("CRATESFYI_GITHUB_ACCESSTOKEN").ok(), - ) - .send()); - - if resp.status() != StatusCode::OK { - return Err(err_msg("Failed to get github data")); - } - - try!(resp.read_to_string(&mut body)); - body - }; - - let json = try!(Json::from_str(&body[..])); - let obj = json.as_object().unwrap(); - - Ok(GitHubFields { - description: obj.get("description").and_then(|d| d.as_string()).unwrap_or("").to_string(), - stars: obj.get("stargazers_count").and_then(|d| d.as_i64()).unwrap_or(0), - forks: obj.get("forks_count").and_then(|d| d.as_i64()).unwrap_or(0), - issues: obj.get("open_issues").and_then(|d| d.as_i64()).unwrap_or(0), - last_commit: time::strptime(obj.get("pushed_at") - .and_then(|d| d.as_string()) - .unwrap_or(""), - "%Y-%m-%dT%H:%M:%S") - .unwrap_or(time::now()) - .to_timespec(), - }) -} - - - -fn get_github_path(url: &str) -> Option { - let re = Regex::new(r"https?://github\.com/([\w\._-]+)/([\w\._-]+)").unwrap(); - match re.captures(url) { - Some(cap) => { - let username = cap.get(1).unwrap().as_str(); - let reponame = cap.get(2).unwrap().as_str(); - Some(format!("{}/{}", - username, - if reponame.ends_with(".git") { - reponame.split(".git").nth(0).unwrap() - } else { - reponame - })) - } - None => None, - } -} - - - -#[cfg(test)] -mod test { - extern crate env_logger; - use super::{get_github_path, get_github_fields, github_updater}; - - #[test] - fn test_get_github_path() { - assert_eq!(get_github_path("https://github.com/onur/cratesfyi"), - Some("onur/cratesfyi".to_string())); - assert_eq!(get_github_path("http://github.com/onur/cratesfyi"), - Some("onur/cratesfyi".to_string())); - assert_eq!(get_github_path("https://github.com/onur/cratesfyi.git"), - Some("onur/cratesfyi".to_string())); - assert_eq!(get_github_path("https://github.com/onur23cmD_M_R_L_/crates_fy-i"), - Some("onur23cmD_M_R_L_/crates_fy-i".to_string())); - assert_eq!(get_github_path("https://github.com/docopt/docopt.rs"), - Some("docopt/docopt.rs".to_string())); - } - - - #[test] - #[ignore] - fn test_get_github_fields() { - let _ = env_logger::try_init(); - let fields = get_github_fields("onur/cratesfyi"); - assert!(fields.is_ok()); - - let fields = fields.unwrap(); - assert!(fields.description != "".to_string()); - assert!(fields.stars >= 0); - assert!(fields.forks >= 0); - assert!(fields.issues >= 0); - - use time; - assert!(fields.last_commit <= time::now().to_timespec()); - } - - - #[test] - #[ignore] - fn test_github_updater() { - let _ = env_logger::try_init(); - assert!(github_updater().is_ok()); - } -} diff --git a/src/utils/html.rs b/src/utils/html.rs deleted file mode 100644 index a7fe2b41a..000000000 --- a/src/utils/html.rs +++ /dev/null @@ -1,74 +0,0 @@ -use error::Result; -use failure::err_msg; - -use html5ever::serialize::{serialize, SerializeOpts}; -use html5ever::rcdom::{RcDom, NodeData, Handle}; -use html5ever::driver::{parse_document, ParseOpts}; -use html5ever::tendril::TendrilSink; - -/// Extracts the contents of the `` and `` tags from an HTML document, as well as the -/// classes on the `` tag, if any. -pub fn extract_head_and_body(html: &str) -> Result<(String, String, String)> { - let parser = parse_document(RcDom::default(), ParseOpts::default()); - let dom = parser.one(html); - - let (head, body) = extract_from_rcdom(&dom)?; - let class = extract_class(&body); - - Ok((stringify(head), stringify(body), class)) -} - -fn extract_from_rcdom(dom: &RcDom) -> Result<(Handle, Handle)> { - let mut worklist = vec![dom.document.clone()]; - let (mut head, mut body) = (None, None); - - while let Some(handle) = worklist.pop() { - match handle.data { - NodeData::Element { ref name, .. } => match name.local.as_ref() { - "head" => { - if head.is_some() { - return Err(err_msg("duplicate tag")); - } else { - head = Some(handle.clone()); - } - } - "body" => { - if body.is_some() { - return Err(err_msg("duplicate tag")); - } else { - body = Some(handle.clone()); - } - } - _ => {} // do nothing - } - _ => {} // do nothing - } - - worklist.extend(handle.children.borrow().iter().cloned()); - } - - let head = head.ok_or_else(|| err_msg("couldn't find tag in rustdoc output"))?; - let body = body.ok_or_else(|| err_msg("couldn't find tag in rustdoc output"))?; - Ok((head, body)) -} - -fn stringify(node: Handle) -> String { - let mut vec = Vec::new(); - serialize(&mut vec, &node, SerializeOpts::default()) - .expect("serializing into buffer failed"); - - String::from_utf8(vec).expect("html5ever returned non-utf8 data") -} - -fn extract_class(node: &Handle) -> String { - match node.data { - NodeData::Element { ref attrs, .. } => { - let attrs = attrs.borrow(); - - attrs.iter() - .find(|a| &a.name.local == "class") - .map_or(String::new(), |a| a.value.to_string()) - } - _ => String::new() - } -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs deleted file mode 100644 index c0db8296c..000000000 --- a/src/utils/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Various utilities for cratesfyi - - -pub use self::build_doc::{build_doc, get_package, source_path, update_sources}; -pub use self::copy::{copy_dir, copy_doc_dir}; -pub use self::github_updater::github_updater; -pub use self::release_activity_updater::update_release_activity; -pub use self::daemon::start_daemon; -pub use self::rustc_version::{parse_rustc_version, get_current_versions, command_result}; -pub use self::html::extract_head_and_body; - -mod github_updater; -mod build_doc; -mod copy; -mod release_activity_updater; -mod daemon; -mod pubsubhubbub; -mod rustc_version; -mod html; diff --git a/src/utils/pubsubhubbub.rs b/src/utils/pubsubhubbub.rs deleted file mode 100644 index 6437dbcec..000000000 --- a/src/utils/pubsubhubbub.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::collections::HashMap; - -use reqwest::*; - -fn ping_hub(url: &str) -> Result { - let mut params = HashMap::new(); - params.insert("hub.mode", "publish"); - params.insert("hub.url", "https://docs.rs/releases/feed"); - let client = Client::new(); - client.post(url).form(¶ms).send() -} - -/// Ping the two predefined hubs. Return either the number of successfully -/// pinged hubs, or the first error. -pub fn ping_hubs() -> Result { - vec!["https://pubsubhubbub.appspot.com", - "https://pubsubhubbub.superfeedr.com"] - .into_iter() - .map(ping_hub) - .collect::>>() - .map(|v| v.len()) -} diff --git a/src/utils/release_activity_updater.rs b/src/utils/release_activity_updater.rs deleted file mode 100644 index cc9861f1c..000000000 --- a/src/utils/release_activity_updater.rs +++ /dev/null @@ -1,78 +0,0 @@ - -use db::connect_db; -use time::{now, Duration}; -use std::collections::BTreeMap; -use rustc_serialize::json::ToJson; -use error::Result; - - -pub fn update_release_activity() -> Result<()> { - - let conn = try!(connect_db()); - let mut dates = Vec::new(); - let mut crate_counts = Vec::new(); - let mut failure_counts = Vec::new(); - - for day in 0..30 { - let rows = try!(conn.query(&format!("SELECT COUNT(*) - FROM releases - WHERE release_time < NOW() - INTERVAL '{} day' AND - release_time > NOW() - INTERVAL '{} day'", - day, - day + 1), - &[])); - let failures_count_rows = try!(conn.query( - &format!("SELECT COUNT(*) - FROM releases - WHERE is_library = TRUE AND - build_status = FALSE AND - release_time < NOW() - INTERVAL '{} day' AND - release_time > NOW() - INTERVAL '{} day'", - day, - day + 1), - &[])); - let release_count: i64 = rows.get(0).get(0); - let failure_count: i64 = failures_count_rows.get(0).get(0); - let now = now(); - let date = now - Duration::days(day); - dates.push(format!("{}", date.strftime("%d %b").unwrap())); - // unwrap is fine here, ~~~~~~~~~~~~^ our date format is always valid - crate_counts.push(release_count); - failure_counts.push(failure_count); - } - - dates.reverse(); - crate_counts.reverse(); - failure_counts.reverse(); - - let map = { - let mut map = BTreeMap::new(); - map.insert("dates".to_owned(), dates.to_json()); - map.insert("counts".to_owned(), crate_counts.to_json()); - map.insert("failures".to_owned(), failure_counts.to_json()); - map.to_json() - }; - - try!(conn.query("INSERT INTO config (name, value) VALUES ('release_activity', $1)", - &[&map]) - .or_else(|_| { - conn.query("UPDATE config SET value = $1 WHERE name = 'release_activity'", - &[&map]) - })); - - Ok(()) -} - - -#[cfg(test)] -mod test { - extern crate env_logger; - use super::update_release_activity; - - #[test] - #[ignore] - fn test_update_release_activity() { - let _ = env_logger::try_init(); - assert!(update_release_activity().is_ok()); - } -} diff --git a/src/utils/rustc_version.rs b/src/utils/rustc_version.rs deleted file mode 100644 index b7fea0a04..000000000 --- a/src/utils/rustc_version.rs +++ /dev/null @@ -1,47 +0,0 @@ - -use std::process::{Command, Output}; -use regex::Regex; -use error::Result; -use failure::err_msg; - -/// Parses rustc commit hash from rustc version string -pub fn parse_rustc_version>(version: S) -> Result { - let version_regex = Regex::new(r" ([\w.-]+) \((\w+) (\d+)-(\d+)-(\d+)\)")?; - let captures = version_regex.captures(version.as_ref()) - .ok_or_else(|| err_msg("Failed to parse rustc version"))?; - - Ok(format!("{}{}{}-{}-{}", - captures.get(3).unwrap().as_str(), - captures.get(4).unwrap().as_str(), - captures.get(5).unwrap().as_str(), - captures.get(1).unwrap().as_str(), - captures.get(2).unwrap().as_str())) -} - - -/// Returns current version of rustc and cratesfyi -pub fn get_current_versions() -> Result<(String, String)> { - let rustc_version = command_result(Command::new("rustc").arg("--version").output()?)?; - let cratesfyi_version = command_result(Command::new("rustc").arg("--version").output()?)?; - - Ok((rustc_version, cratesfyi_version)) -} - - -pub fn command_result(output: Output) -> Result { - let mut command_out = String::from_utf8_lossy(&output.stdout).into_owned(); - command_out.push_str(&String::from_utf8_lossy(&output.stderr).into_owned()[..]); - match output.status.success() { - true => Ok(command_out), - false => Err(err_msg(command_out)), - } -} - - -#[test] -fn test_parse_rustc_version() { - assert_eq!(parse_rustc_version("rustc 1.10.0-nightly (57ef01513 2016-05-23)").unwrap(), - "20160523-1.10.0-nightly-57ef01513"); - assert_eq!(parse_rustc_version("cratesfyi 0.2.0 (ba9ae23 2016-05-26)").unwrap(), - "20160526-0.2.0-ba9ae23"); -} diff --git a/src/web/badge/Cargo.toml b/src/web/badge/Cargo.toml deleted file mode 100644 index 19d04e203..000000000 --- a/src/web/badge/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "badge" -version = "0.2.0" -description = "Simple badge generator" -authors = ["Onur Aslan "] -license-file = "LICENSE" -repository = "https://github.com/rust-lang/docs.rs" -documentation = "https://docs.rs/badge" - -[lib] -path = "badge.rs" - -[dependencies] -base64 = "0.9.0" -rusttype = "0.7" diff --git a/src/web/badge/DejaVuSans.ttf b/src/web/badge/DejaVuSans.ttf deleted file mode 100644 index de12789bb..000000000 Binary files a/src/web/badge/DejaVuSans.ttf and /dev/null differ diff --git a/src/web/badge/LICENSE b/src/web/badge/LICENSE deleted file mode 100644 index 347257a4f..000000000 --- a/src/web/badge/LICENSE +++ /dev/null @@ -1,70 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: badge -Source: https://github.com/rust-lang/docs.rs - -Files: * -Copyright: Copyright (c) 2016 Onur Aslan -License: Expat - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - . - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - . - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - -Files: DejaVuSans.ttf -Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. - Bitstream Vera is a trademark of Bitstream, Inc. - DejaVu changes are in public domain. -License: bitstream-vera - Permission is hereby granted, free of charge, to any person obtaining a copy - of the fonts accompanying this license ("Fonts") and associated - documentation files (the "Font Software"), to reproduce and distribute the - Font Software, including without limitation the rights to use, copy, merge, - publish, distribute, and/or sell copies of the Font Software, and to permit - persons to whom the Font Software is furnished to do so, subject to the - following conditions: - . - The above copyright and trademark notices and this permission notice shall - be included in all copies of one or more of the Font Software typefaces. - . - The Font Software may be modified, altered, or added to, and in particular - the designs of glyphs or characters in the Fonts may be modified and - additional glyphs or characters may be added to the Fonts, only if the fonts - are renamed to names not containing either the words "Bitstream" or the word - "Vera". - . - This License becomes null and void to the extent applicable to Fonts or Font - Software that has been modified and is distributed under the "Bitstream - Vera" names. - . - The Font Software may be sold as part of a larger software package but no - copy of one or more of the Font Software typefaces may be sold by itself. - . - THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, - TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME - FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING - ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE - FONT SOFTWARE. - . - Except as contained in this notice, the names of Gnome, the Gnome - Foundation, and Bitstream Inc., shall not be used in advertising or - otherwise to promote the sale, use or other dealings in this Font Software - without prior written authorization from the Gnome Foundation or Bitstream - Inc., respectively. For further information, contact: fonts at gnome dot - org. diff --git a/src/web/badge/badge.rs b/src/web/badge/badge.rs deleted file mode 100644 index 7e639ab2c..000000000 --- a/src/web/badge/badge.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! Simple badge generator - -extern crate base64; -extern crate rusttype; - - -use base64::display::Base64Display; -use rusttype::{Font, FontCollection, Scale, point, Point, PositionedGlyph}; - - -const FONT_DATA: &'static [u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), - "/DejaVuSans.ttf")); -const FONT_SIZE: f32 = 11.; - - -pub struct BadgeOptions { - /// Subject will be displayed on the left side of badge - pub subject: String, - /// Status will be displayed on the right side of badge - pub status: String, - /// HTML color of badge - pub color: String, -} - - -impl Default for BadgeOptions { - fn default() -> BadgeOptions { - BadgeOptions { - subject: "build".to_owned(), - status: "passing".to_owned(), - color: "#4c1".to_owned(), - } - } -} - - -pub struct Badge { - options: BadgeOptions, - font: Font<'static>, - scale: Scale, - offset: Point, -} - - -impl Badge { - pub fn new(options: BadgeOptions) -> Result { - let collection = FontCollection::from_bytes(FONT_DATA).expect("Failed to parse FONT_DATA"); - // this should never fail in practice - let font = try!(collection.into_font().map_err(|_| "Failed to load font data".to_owned())); - let scale = Scale { - x: FONT_SIZE, - y: FONT_SIZE, - }; - let v_metrics = font.v_metrics(scale); - let offset = point(0.0, v_metrics.ascent); - Ok(Badge { - options: options, - font: font, - scale: scale, - offset: offset, - }) - } - - - pub fn to_svg_data_uri(&self) -> String { - format!("data:image/svg+xml;base64,{}", - Base64Display::standard(self.to_svg().as_bytes())) - } - - - pub fn to_svg(&self) -> String { - let left_width = self.calculate_width(&self.options.subject) + 6; - let right_width = self.calculate_width(&self.options.status) + 6; - - let svg = format!(r###" - - - - - - - - - - - - - - - - - {} - {} - {} - {} - -"###, - left_width + right_width, - left_width + right_width, - left_width, - left_width, - right_width, - self.options.color, - left_width + right_width, - (left_width) / 2, - self.options.subject, - (left_width) / 2, - self.options.subject, - left_width + (right_width / 2), - self.options.status, - left_width + (right_width / 2), - self.options.status); - - svg - } - - - fn calculate_width(&self, text: &str) -> u32 { - let glyphs: Vec = - self.font.layout(text, self.scale, self.offset).collect(); - let width: u32 = glyphs.iter() - .rev() - .filter_map(|g| { - g.pixel_bounding_box() - .map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width) - }) - .next() - .unwrap_or(0.0) - .ceil() as u32; - width + ((text.len() as u32 - 1) * 2) - } -} - - - -#[cfg(test)] -mod tests { - use super::*; - - fn options() -> BadgeOptions { - BadgeOptions::default() - } - - - #[test] - fn test_new() { - assert!(Badge::new(options()).is_ok()); - } - - #[test] - fn test_calculate_width() { - let badge = Badge::new(options()).unwrap(); - assert_eq!(badge.calculate_width("build"), 31); - assert_eq!(badge.calculate_width("passing"), 48); - } - - #[test] - #[ignore] - fn test_to_svg() { - use std::fs::File; - use std::io::Write; - let mut file = File::create("test.svg").unwrap(); - let options = BadgeOptions { - subject: "build".to_owned(), - status: "passing".to_owned(), - ..BadgeOptions::default() - }; - let badge = Badge::new(options).unwrap(); - file.write_all(badge.to_svg().as_bytes()).unwrap(); - } -} diff --git a/src/web/builds.rs b/src/web/builds.rs deleted file mode 100644 index a0eb05530..000000000 --- a/src/web/builds.rs +++ /dev/null @@ -1,140 +0,0 @@ - - -use std::collections::BTreeMap; -use super::MetaData; -use super::pool::Pool; -use super::duration_to_str; -use super::page::Page; -use iron::prelude::*; -use time; -use router::Router; -use rustc_serialize::json::{Json, ToJson}; - - - -#[derive(Clone)] -struct Build { - id: i32, - rustc_version: String, - cratesfyi_version: String, - build_status: bool, - build_time: time::Timespec, - output: Option, -} - - -struct BuildsPage { - metadata: Option, - builds: Vec, - build_details: Option, -} - - -impl ToJson for Build { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("id".to_owned(), self.id.to_json()); - m.insert("rustc_version".to_owned(), self.rustc_version.to_json()); - m.insert("cratesfyi_version".to_owned(), - self.cratesfyi_version.to_json()); - m.insert("build_status".to_owned(), self.build_status.to_json()); - m.insert("build_time".to_owned(), - format!("{}", time::at(self.build_time).rfc3339()).to_json()); - m.insert("build_time_relative".to_owned(), - duration_to_str(self.build_time).to_json()); - m.insert("output".to_owned(), self.output.to_json()); - m.to_json() - } -} - - -impl ToJson for BuildsPage { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("metadata".to_owned(), self.metadata.to_json()); - m.insert("builds".to_owned(), self.builds.to_json()); - m.insert("build_details".to_owned(), self.build_details.to_json()); - m.to_json() - } -} - - -pub fn build_list_handler(req: &mut Request) -> IronResult { - - let router = extension!(req, Router); - let name = cexpect!(router.find("name")); - let version = cexpect!(router.find("version")); - let req_build_id: i32 = router.find("id").unwrap_or("0").parse().unwrap_or(0); - - let conn = extension!(req, Pool); - - let mut build_list: Vec = Vec::new(); - let mut build_details = None; - - // FIXME: getting builds.output may cause performance issues when release have tons of builds - for row in &ctry!(conn.query("SELECT crates.name, - releases.version, - releases.description, - releases.rustdoc_status, - releases.target_name, - builds.id, - builds.rustc_version, - builds.cratesfyi_version, - builds.build_status, - builds.build_time, - builds.output - FROM builds - INNER JOIN releases ON releases.id = builds.rid - INNER JOIN crates ON releases.crate_id = crates.id - WHERE crates.name = $1 AND releases.version = $2 - ORDER BY id DESC", - &[&name, &version])) { - - let id: i32 = row.get(5); - - let build = Build { - id: id, - rustc_version: row.get(6), - cratesfyi_version: row.get(7), - build_status: row.get(8), - build_time: row.get(9), - output: row.get(10), - }; - - if id == req_build_id { - build_details = Some(build.clone()); - } - - build_list.push(build); - } - - if req.url.path().join("/").ends_with(".json") { - use iron::status; - use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective, ContentType, - AccessControlAllowOrigin}; - - // Remove build output from build list for json output - for build in build_list.as_mut_slice() { - build.output = None; - } - - let mut resp = Response::with((status::Ok, build_list.to_json().to_string())); - resp.headers.set(ContentType("application/json".parse().unwrap())); - resp.headers.set(Expires(HttpDate(time::now()))); - resp.headers.set(CacheControl(vec![CacheDirective::NoCache, - CacheDirective::NoStore, - CacheDirective::MustRevalidate])); - resp.headers.set(AccessControlAllowOrigin::Any); - Ok(resp) - } else { - let builds_page = BuildsPage { - metadata: MetaData::from_crate(&conn, &name, &version), - builds: build_list, - build_details: build_details, - }; - Page::new(builds_page) - .set_true("show_package_navigation") - .set_true("package_navigation_builds_tab") - .to_resp("builds") - } -} diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs deleted file mode 100644 index 9c7b6aeb1..000000000 --- a/src/web/crate_details.rs +++ /dev/null @@ -1,242 +0,0 @@ - - - -use super::pool::Pool; -use super::{MetaData, duration_to_str, match_version, render_markdown}; -use super::error::Nope; -use super::page::Page; -use iron::prelude::*; -use iron::status; -use std::collections::BTreeMap; -use time; -use rustc_serialize::json::{Json, ToJson}; -use router::Router; -use postgres::Connection; -use semver; - - -// TODO: Add target name and versions - - -#[derive(Debug)] -pub struct CrateDetails { - name: String, - version: String, - description: Option, - authors: Vec<(String, String)>, - owners: Vec<(String, String)>, - authors_json: Option, - dependencies: Option, - readme: Option, - rustdoc: Option, // this is description_long in database - release_time: time::Timespec, - build_status: bool, - rustdoc_status: bool, - repository_url: Option, - homepage_url: Option, - keywords: Option, - have_examples: bool, // need to check this manually - target_name: Option, - pub versions: Vec, - github: bool, // is crate hosted in github - github_stars: Option, - github_forks: Option, - github_issues: Option, - metadata: MetaData, - is_library: bool, - doc_targets: Option, - license: Option, - documentation_url: Option, -} - - -impl ToJson for CrateDetails { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("name".to_string(), self.name.to_json()); - m.insert("version".to_string(), self.version.to_json()); - m.insert("description".to_string(), self.description.to_json()); - m.insert("authors".to_string(), self.authors.to_json()); - m.insert("owners".to_string(), self.owners.to_json()); - m.insert("authors_json".to_string(), self.authors_json.to_json()); - m.insert("dependencies".to_string(), self.dependencies.to_json()); - if let Some(ref readme) = self.readme { - m.insert("readme".to_string(), render_markdown(&readme).to_json()); - } - if let Some(ref rustdoc) = self.rustdoc { - m.insert("rustdoc".to_string(), render_markdown(&rustdoc).to_json()); - } - m.insert("release_time".to_string(), - duration_to_str(self.release_time).to_json()); - m.insert("build_status".to_string(), self.build_status.to_json()); - m.insert("rustdoc_status".to_string(), self.rustdoc_status.to_json()); - m.insert("repository_url".to_string(), self.repository_url.to_json()); - m.insert("homepage_url".to_string(), self.homepage_url.to_json()); - m.insert("keywords".to_string(), self.keywords.to_json()); - m.insert("have_examples".to_string(), self.have_examples.to_json()); - m.insert("target_name".to_string(), self.target_name.to_json()); - m.insert("versions".to_string(), self.versions.to_json()); - m.insert("github".to_string(), self.github.to_json()); - m.insert("github_stars".to_string(), self.github_stars.to_json()); - m.insert("github_forks".to_string(), self.github_forks.to_json()); - m.insert("github_issues".to_string(), self.github_issues.to_json()); - m.insert("metadata".to_string(), self.metadata.to_json()); - m.insert("is_library".to_string(), self.is_library.to_json()); - m.insert("doc_targets".to_string(), self.doc_targets.to_json()); - m.insert("license".to_string(), self.license.to_json()); - m.insert("documentation_url".to_string(), self.documentation_url.to_json()); - m.to_json() - } -} - - -impl CrateDetails { - pub fn new(conn: &Connection, name: &str, version: &str) -> Option { - - // get all stuff, I love you rustfmt - let query = "SELECT crates.id, - releases.id, - crates.name, - releases.version, - releases.description, - releases.authors, - releases.dependencies, - releases.readme, - releases.description_long, - releases.release_time, - releases.build_status, - releases.rustdoc_status, - releases.repository_url, - releases.homepage_url, - releases.keywords, - releases.have_examples, - releases.target_name, - crates.versions, - crates.github_stars, - crates.github_forks, - crates.github_issues, - releases.is_library, - releases.doc_targets, - releases.license, - releases.documentation_url - FROM releases - INNER JOIN crates ON releases.crate_id = crates.id - WHERE crates.name = $1 AND releases.version = $2;"; - - let rows = conn.query(query, &[&name, &version]).unwrap(); - - if rows.len() == 0 { - return None; - } - - let crate_id: i32 = rows.get(0).get(0); - let release_id: i32 = rows.get(0).get(1); - - // sort versions with semver - let versions = { - let mut versions: Vec = Vec::new(); - let versions_from_db: Json = rows.get(0).get(17); - - versions_from_db.as_array().map(|vers| { - for version in vers { - version.as_string().map(|version| { - if let Ok(sem_ver) = semver::Version::parse(&version) { - versions.push(sem_ver); - }; - }); - } - }); - - versions.sort(); - versions.reverse(); - versions.iter().map(|semver| format!("{}", semver)).collect() - }; - - let metadata = MetaData { - name: rows.get(0).get(2), - version: rows.get(0).get(3), - description: rows.get(0).get(4), - rustdoc_status: rows.get(0).get(11), - target_name: rows.get(0).get(16), - }; - - let mut crate_details = CrateDetails { - name: rows.get(0).get(2), - version: rows.get(0).get(3), - description: rows.get(0).get(4), - authors: Vec::new(), - owners: Vec::new(), - authors_json: rows.get(0).get(5), - dependencies: rows.get(0).get(6), - readme: rows.get(0).get(7), - rustdoc: rows.get(0).get(8), - release_time: rows.get(0).get(9), - build_status: rows.get(0).get(10), - rustdoc_status: rows.get(0).get(11), - repository_url: rows.get(0).get(12), - homepage_url: rows.get(0).get(13), - keywords: rows.get(0).get(14), - have_examples: rows.get(0).get(15), - target_name: rows.get(0).get(16), - versions: versions, - github: false, - github_stars: rows.get(0).get(18), - github_forks: rows.get(0).get(19), - github_issues: rows.get(0).get(20), - metadata: metadata, - is_library: rows.get(0).get(21), - doc_targets: rows.get(0).get(22), - license: rows.get(0).get(23), - documentation_url: rows.get(0).get(24), - }; - - if let Some(repository_url) = crate_details.repository_url.clone() { - crate_details.github = repository_url.starts_with("http://github.com") || - repository_url.starts_with("https://github.com"); - } - - // get authors - for row in &conn.query("SELECT name, slug - FROM authors - INNER JOIN author_rels ON author_rels.aid = authors.id - WHERE rid = $1", - &[&release_id]) - .unwrap() { - crate_details.authors.push((row.get(0), row.get(1))); - } - - // get owners - for row in &conn.query("SELECT login, avatar - FROM owners - INNER JOIN owner_rels ON owner_rels.oid = owners.id - WHERE cid = $1", - &[&crate_id]) - .unwrap() { - crate_details.owners.push((row.get(0), row.get(1))); - } - - Some(crate_details) - } -} - - - -pub fn crate_details_handler(req: &mut Request) -> IronResult { - let router = extension!(req, Router); - // this handler must always called with a crate name - let name = cexpect!(router.find("name")); - let req_version = router.find("version"); - - let conn = extension!(req, Pool); - - match_version(&conn, &name, req_version) - .and_then(|version| CrateDetails::new(&conn, &name, &version)) - .ok_or(IronError::new(Nope::CrateNotFound, status::NotFound)) - .and_then(|details| { - Page::new(details) - .set_true("show_package_navigation") - .set_true("javascript_highlightjs") - .set_true("package_navigation_crate_tab") - .to_resp("crate_details") - }) -} diff --git a/src/web/error.rs b/src/web/error.rs deleted file mode 100644 index f7ed1857b..000000000 --- a/src/web/error.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::error::Error; -use iron::prelude::*; -use iron::Handler; -use iron::status; -use web::page::Page; -use std::fmt; - -#[derive(Debug, Copy, Clone)] -pub enum Nope { - ResourceNotFound, - CrateNotFound, - NoResults, -} - -impl fmt::Display for Nope { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.description()) - } -} - -impl Error for Nope { - fn description(&self) -> &str { - match *self { - Nope::ResourceNotFound => "Requested resource not found", - Nope::CrateNotFound => "Requested crate not found", - Nope::NoResults => "Search yielded no results", - } - } -} - -impl Handler for Nope { - fn handle(&self, req: &mut Request) -> IronResult { - match *self { - Nope::ResourceNotFound => { - // user tried to navigate to a resource (doc page/file) that doesn't exist - Page::new("no such resource".to_owned()) - .set_status(status::NotFound) - .title("The requested resource does not exist") - .to_resp("error") - } - Nope::CrateNotFound => { - // user tried to navigate to a crate that doesn't exist - Page::new("no such crate".to_owned()) - .set_status(status::NotFound) - .title("The requested crate does not exist") - .to_resp("error") - } - Nope::NoResults => { - use params::{Params, Value}; - let params = req.get::().unwrap(); - if let Some(&Value::String(ref query)) = params.find(&["query"]) { - // this used to be a search - Page::new(Vec::::new()) - .set_status(status::NotFound) - .set("search_query", &query) - .title(&format!("No crates found matching '{}'", query)) - .to_resp("releases") - } else { - // user did a search with no search terms - Page::new(Vec::::new()) - .set_status(status::NotFound) - .title("No results given for empty search query") - .to_resp("releases") - } - } - } - } -} diff --git a/src/web/file.rs b/src/web/file.rs deleted file mode 100644 index 8cdbbca31..000000000 --- a/src/web/file.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Database based file handler - -use super::pool::Pool; -use time; -use postgres::Connection; -use iron::{Handler, Request, IronResult, Response, IronError}; -use iron::status; - - -pub struct File { - pub path: String, - pub mime: String, - pub date_added: time::Timespec, - pub date_updated: time::Timespec, - pub content: Vec, -} - - -impl File { - /// Gets file from database - pub fn from_path(conn: &Connection, path: &str) -> Option { - - let rows = conn.query("SELECT path, mime, date_added, date_updated, content - FROM files - WHERE path = $1", - &[&path]) - .unwrap(); - - if rows.len() == 0 { - None - } else { - let row = rows.get(0); - Some(File { - path: row.get(0), - mime: row.get(1), - date_added: row.get(2), - date_updated: row.get(3), - content: row.get(4), - }) - } - } - - - /// Consumes File and creates a iron response - pub fn serve(self) -> Response { - use iron::headers::{CacheControl, LastModified, CacheDirective, HttpDate, ContentType}; - - let mut response = Response::with((status::Ok, self.content)); - let cache = vec![CacheDirective::Public, - CacheDirective::MaxAge(super::STATIC_FILE_CACHE_DURATION as u32)]; - response.headers.set(ContentType(self.mime.parse().unwrap())); - response.headers.set(CacheControl(cache)); - response.headers.set(LastModified(HttpDate(time::at(self.date_updated)))); - response - } - - - /// Checks if mime type of file is "application/x-empty" - pub fn is_empty(&self) -> bool { - self.mime == "application/x-empty" - } -} - - -/// Database based file handler for iron -/// -/// This is similar to staticfile crate, but its using getting files from database. -pub struct DatabaseFileHandler; - -impl Handler for DatabaseFileHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let path = req.url.path().join("/"); - let conn = extension!(req, Pool); - if let Some(file) = File::from_path(&conn, &path) { - Ok(file.serve()) - } else { - Err(IronError::new(super::error::Nope::CrateNotFound, status::NotFound)) - } - } -} diff --git a/src/web/mod.rs b/src/web/mod.rs deleted file mode 100644 index 8de4021c3..000000000 --- a/src/web/mod.rs +++ /dev/null @@ -1,541 +0,0 @@ -//! Web interface of cratesfyi - - -pub mod page; - -/// ctry! (cratesfyitry) is extremely similar to try! and itry! -/// except it returns an error page response instead of plain Err. -macro_rules! ctry { - ($result:expr) => (match $result { - Ok(v) => v, - Err(e) => { - return super::page::Page::new(format!("{:?}", e)).title("An error has occured") - .set_status(::iron::status::BadRequest).to_resp("resp"); - } - }) -} - -/// cexpect will check an option and if it's not Some -/// it will return an error page response -macro_rules! cexpect { - ($option:expr) => (match $option { - Some(v) => v, - None => { - return super::page::Page::new("Resource not found".to_owned()) - .title("An error has occured") - .set_status(::iron::status::BadRequest).to_resp("resp"); - } - }) -} - -/// Gets an extension from Request -macro_rules! extension { - ($req:expr, $ext:ty) => ( - cexpect!($req.extensions.get::<$ext>()) - ) -} - -mod rustdoc; -mod releases; -mod crate_details; -mod source; -mod pool; -mod file; -mod builds; -mod error; -mod sitemap; - -use std::{env, fmt}; -use std::error::Error; -use std::time::Duration; -use std::path::PathBuf; -use iron::prelude::*; -use iron::{self, Handler, status}; -use iron::headers::{CacheControl, CacheDirective, ContentType}; -use router::{Router, NoRoute}; -use staticfile::Static; -use handlebars_iron::{HandlebarsEngine, DirectorySource}; -use time; -use postgres::Connection; -use semver::{Version, VersionReq}; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; - -/// Duration of static files for staticfile and DatabaseFileHandler (in seconds) -const STATIC_FILE_CACHE_DURATION: u64 = 60 * 60 * 24 * 30 * 12; // 12 months -const STYLE_CSS: &'static str = include_str!(concat!(env!("OUT_DIR"), "/style.css")); -const OPENSEARCH_XML: &'static [u8] = include_bytes!("opensearch.xml"); - - -struct CratesfyiHandler { - shared_resource_handler: Box, - router_handler: Box, - database_file_handler: Box, - static_handler: Box, -} - - -impl CratesfyiHandler { - fn chain(base: H) -> Chain { - // TODO: Use DocBuilderOptions for paths - let mut hbse = HandlebarsEngine::new(); - hbse.add(Box::new(DirectorySource::new("./templates", ".hbs"))); - - // load templates - if let Err(e) = hbse.reload() { - panic!("Failed to load handlebar templates: {}", e.description()); - } - - let mut chain = Chain::new(base); - chain.link_before(pool::Pool::new()); - chain.link_after(hbse); - chain - } - - pub fn new() -> CratesfyiHandler { - let mut router = Router::new(); - router.get("/", releases::home_page, "index"); - router.get("/style.css", style_css_handler, "style_css"); - router.get("/about", sitemap::about_handler, "about"); - router.get("/robots.txt", sitemap::robots_txt_handler, "robots_txt"); - router.get("/sitemap.xml", sitemap::sitemap_handler, "sitemap_xml"); - router.get("/opensearch.xml", opensearch_xml_handler, "opensearch_xml"); - router.get("/releases", releases::recent_releases_handler, "releases"); - router.get("/releases/feed", - releases::releases_feed_handler, - "releases_feed"); - router.get("/releases/recent/:page", - releases::recent_releases_handler, - "releases_recent_page"); - router.get("/releases/stars", releases::releases_by_stars_handler, "releases_stars"); - router.get("/releases/stars/:page", - releases::releases_by_stars_handler, - "releases_stars_page"); - router.get("/releases/recent-failures", releases::releases_recent_failures_handler, "releases_recent_failures"); - router.get("/releases/recent-failures/:page", - releases::releases_recent_failures_handler, - "releases_recent_failures_page"); - router.get("/releases/failures", releases::releases_failures_by_stars_handler, "releases_failures_by_stars"); - router.get("/releases/failures/:page", - releases::releases_failures_by_stars_handler, - "releases_failures_by_starts_page"); - router.get("/releases/:author", - releases::author_handler, - "releases_author"); - router.get("/releases/:author/:page", - releases::author_handler, - "releases_author_page"); - router.get("/releases/activity", - releases::activity_handler, - "releases_activity"); - router.get("/releases/search", - releases::search_handler, - "releases_search"); - router.get("/releases/queue", - releases::build_queue_handler, - "releases_queue"); - router.get("/crate/:name", - crate_details::crate_details_handler, - "crate_name"); - router.get("/crate/:name/", - crate_details::crate_details_handler, - "crate_name_"); - router.get("/crate/:name/:version", - crate_details::crate_details_handler, - "crate_name_version"); - router.get("/crate/:name/:version/", - crate_details::crate_details_handler, - "crate_name_version_"); - router.get("/crate/:name/:version/builds", - builds::build_list_handler, - "crate_name_version_builds"); - router.get("/crate/:name/:version/builds.json", - builds::build_list_handler, - "crate_name_version_builds_json"); - router.get("/crate/:name/:version/builds/:id", - builds::build_list_handler, - "crate_name_version_builds_id"); - router.get("/crate/:name/:version/source/", - source::source_browser_handler, - "crate_name_version_source"); - router.get("/crate/:name/:version/source/*", - source::source_browser_handler, - "crate_name_version_source_"); - router.get("/:crate", rustdoc::rustdoc_redirector_handler, "crate"); - router.get("/:crate/", rustdoc::rustdoc_redirector_handler, "crate_"); - router.get("/:crate/badge.svg", rustdoc::badge_handler, "crate_badge"); - router.get("/:crate/:version", - rustdoc::rustdoc_redirector_handler, - "crate_version"); - router.get("/:crate/:version/", - rustdoc::rustdoc_redirector_handler, - "crate_version_"); - router.get("/:crate/:version/search-index.js", - rustdoc::rustdoc_html_server_handler, - "crate_version_search_index_js"); - router.get("/:crate/:version/settings.html", - rustdoc::rustdoc_html_server_handler, - "crate_version_settings_html"); - router.get("/:crate/:version/all.html", - rustdoc::rustdoc_html_server_handler, - "crate_version_all_html"); - router.get("/:crate/:version/aliases.js", - rustdoc::rustdoc_html_server_handler, - "crate_version_aliases_js"); - router.get("/:crate/:version/source-files.js", - rustdoc::rustdoc_html_server_handler, - "crate_version_source_files_js"); - router.get("/:crate/:version/:target", - rustdoc::rustdoc_redirector_handler, - "crate_version_target"); - router.get("/:crate/:version/:target/", - rustdoc::rustdoc_html_server_handler, - "crate_version_target_"); - router.get("/:crate/:version/:target/*.html", - rustdoc::rustdoc_html_server_handler, - "crate_version_target_html"); - - let shared_resources = Self::chain(rustdoc::SharedResourceHandler); - let router_chain = Self::chain(router); - let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX").unwrap()).join("public_html"); - let static_handler = Static::new(prefix) - .cache(Duration::from_secs(STATIC_FILE_CACHE_DURATION)); - - CratesfyiHandler { - shared_resource_handler: Box::new(shared_resources), - router_handler: Box::new(router_chain), - database_file_handler: Box::new(file::DatabaseFileHandler), - static_handler: Box::new(static_handler), - } - } -} - - -impl Handler for CratesfyiHandler { - fn handle(&self, req: &mut Request) -> IronResult { - // try serving shared rustdoc resources first, then router, then db/static file handler - // return 404 if none of them return Ok - self.shared_resource_handler - .handle(req) - .or_else(|e| { - self.router_handler.handle(req).or(Err(e)) - }) - .or_else(|e| { - // if router fails try to serve files from database first - self.database_file_handler.handle(req).or(Err(e)) - }) - .or_else(|e| { - // and then try static handler. if all of them fails, return 404 - self.static_handler.handle(req).or(Err(e)) - }) - .or_else(|e| { - debug!("{}", e.description()); - let err = if let Some(err) = e.error.downcast::() { - *err - } else if e.error.downcast::().is_some() { - error::Nope::ResourceNotFound - } else { - panic!("all cratesfyi errors should be of type Nope"); - }; - - match err { - error::Nope::ResourceNotFound => { - // print the path of the URL that triggered a 404 error - struct DebugPath<'a>(&'a iron::Url); - impl<'a> fmt::Display for DebugPath<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for path_elem in self.0.path() { - write!(f, "/{}", path_elem)?; - } - - if let Some(query) = self.0.query() { - write!(f, "?{}", query)?; - } - - if let Some(hash) = self.0.fragment() { - write!(f, "#{}", hash)?; - } - - Ok(()) - } - } - - debug!("Path: {}", DebugPath(&req.url)); - } - _ => {} - } - - Self::chain(err).handle(req) - }) - } -} - - - -fn match_version(conn: &Connection, name: &str, version: Option<&str>) -> Option { - - // version is an Option<&str> from router::Router::get - // need to decode first - use url::percent_encoding::percent_decode; - let req_version = version.and_then(|v| { - match percent_decode(v.as_bytes()).decode_utf8() { - Ok(p) => Some(p.into_owned()), - Err(_) => None, - } - }) - .map(|v| if v == "newest" || v == "latest" { "*".to_owned() } else { v }) - .unwrap_or("*".to_string()); - - let versions = { - let mut versions = Vec::new(); - let rows = conn.query("SELECT versions FROM crates WHERE name = $1", &[&name]).unwrap(); - if rows.len() == 0 { - return None; - } - let versions_json: Json = rows.get(0).get(0); - for version in versions_json.as_array().unwrap() { - let version: String = version.as_string().unwrap().to_owned(); - versions.push(version); - } - - versions - }; - - // first check for exact match - // we can't expect users to use semver in query - for version in &versions { - if version == &req_version { - return Some(version.clone()); - } - } - - // Now try to match with semver - let req_sem_ver = match VersionReq::parse(&req_version) { - Ok(v) => v, - Err(_) => return None, - }; - - // we need to sort versions first - let versions_sem = { - let mut versions_sem: Vec = Vec::new(); - - for version in &versions { - // in theory a crate must always have a semver compatible version - // but check result just in case - let version = match Version::parse(&version) { - Ok(v) => v, - Err(_) => return None, - }; - versions_sem.push(version); - } - - versions_sem.sort(); - versions_sem.reverse(); - versions_sem - }; - - // semver is acting weird for '*' (any) range if a crate only have pre-release versions - // return first version if requested version is '*' - if req_version == "*" && !versions_sem.is_empty() { - return Some(format!("{}", versions_sem[0])); - } - - for version in &versions_sem { - if req_sem_ver.matches(&version) { - return Some(format!("{}", version)); - } - } - - None -} - - - - - -/// Wrapper around the Markdown parser and renderer to render markdown -fn render_markdown(text: &str) -> String { - use comrak::{markdown_to_html, ComrakOptions}; - - let options = { - let mut options = ComrakOptions::default(); - options.ext_superscript = true; - options.ext_table = true; - options.ext_autolink = true; - options.ext_tasklist = true; - options.ext_strikethrough = true; - options - }; - - markdown_to_html(text, &options) -} - - - -/// Returns latest version if required version is not the latest -/// req_version must be an exact version -fn latest_version(versions_json: &Vec, req_version: &str) -> Option { - let req_version = match Version::parse(req_version) { - Ok(v) => v, - Err(_) => return None, - }; - let versions = { - let mut versions: Vec = Vec::new(); - for version in versions_json { - let version = match Version::parse(&version) { - Ok(v) => v, - Err(_) => return None, - }; - versions.push(version); - } - - versions.sort(); - versions.reverse(); - versions - }; - - if req_version != versions[0] { - for i in 1..versions.len() { - if req_version == versions[i] { - return Some(format!("{}", versions[0])) - } - } - } - None -} - - - -/// Starts cratesfyi web server -pub fn start_web_server(sock_addr: Option<&str>) { - let cratesfyi = CratesfyiHandler::new(); - Iron::new(cratesfyi).http(sock_addr.unwrap_or("localhost:3000")).unwrap(); -} - - - -/// Converts Timespec to nice readable relative time string -fn duration_to_str(ts: time::Timespec) -> String { - - let tm = time::at(ts); - let delta = time::now() - tm; - - if delta.num_days() > 5 { - format!("{}", tm.strftime("%b %d, %Y").unwrap()) - } else if delta.num_days() > 1 { - format!("{} days ago", delta.num_days()) - } else if delta.num_days() == 1 { - "one day ago".to_string() - } else if delta.num_hours() > 1 { - format!("{} hours ago", delta.num_hours()) - } else if delta.num_hours() == 1 { - "an hour ago".to_string() - } else if delta.num_minutes() > 1 { - format!("{} minutes ago", delta.num_minutes()) - } else if delta.num_minutes() == 1 { - "one minute ago".to_string() - } else if delta.num_seconds() > 0 { - format!("{} seconds ago", delta.num_seconds()) - } else { - "just now".to_string() - } - -} - - - -fn style_css_handler(_: &mut Request) -> IronResult { - let mut response = Response::with((status::Ok, STYLE_CSS)); - let cache = vec![CacheDirective::Public, - CacheDirective::MaxAge(STATIC_FILE_CACHE_DURATION as u32)]; - response.headers.set(ContentType("text/css".parse().unwrap())); - response.headers.set(CacheControl(cache)); - Ok(response) -} - - -fn opensearch_xml_handler(_: &mut Request) -> IronResult { - let mut response = Response::with((status::Ok, OPENSEARCH_XML)); - let cache = vec![CacheDirective::Public, - CacheDirective::MaxAge(STATIC_FILE_CACHE_DURATION as u32)]; - response.headers.set(ContentType("application/opensearchdescription+xml".parse().unwrap())); - response.headers.set(CacheControl(cache)); - Ok(response) -} - -/// MetaData used in header -#[derive(Debug)] -pub struct MetaData { - pub name: String, - pub version: String, - pub description: Option, - pub target_name: Option, - pub rustdoc_status: bool, -} - - -impl MetaData { - pub fn from_crate(conn: &Connection, name: &str, version: &str) -> Option { - for row in &conn.query("SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.rustdoc_status - FROM releases - INNER JOIN crates ON crates.id = releases.crate_id - WHERE crates.name = $1 AND releases.version = $2", - &[&name, &version]) - .unwrap() { - - return Some(MetaData { - name: row.get(0), - version: row.get(1), - description: row.get(2), - target_name: row.get(3), - rustdoc_status: row.get(4), - }); - } - - None - } -} - - -impl ToJson for MetaData { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("name".to_owned(), self.name.to_json()); - m.insert("version".to_owned(), self.version.to_json()); - m.insert("description".to_owned(), self.description.to_json()); - m.insert("target_name".to_owned(), self.target_name.to_json()); - m.insert("rustdoc_status".to_owned(), self.rustdoc_status.to_json()); - m.to_json() - } -} - - -#[cfg(test)] -mod test { - extern crate env_logger; - use super::*; - - #[test] - #[ignore] - fn test_start_web_server() { - // FIXME: This test is doing nothing - let _ = env_logger::try_init(); - start_web_server(None); - } - - #[test] - fn test_latest_version() { - let versions = vec!["1.0.0".to_string(), - "1.1.0".to_string(), - "0.9.0".to_string(), - "0.9.1".to_string()]; - assert_eq!(latest_version(&versions, "1.1.0"), None); - assert_eq!(latest_version(&versions, "1.0.0"), Some("1.1.0".to_owned())); - assert_eq!(latest_version(&versions, "0.9.0"), Some("1.1.0".to_owned())); - assert_eq!(latest_version(&versions, "invalidversion"), None); - } -} diff --git a/src/web/opensearch.xml b/src/web/opensearch.xml deleted file mode 100644 index e12da194d..000000000 --- a/src/web/opensearch.xml +++ /dev/null @@ -1,6 +0,0 @@ - - Docs.rs - Search for crate documentation on docs.rs - https://docs.rs/favicon.ico - - diff --git a/src/web/page.rs b/src/web/page.rs deleted file mode 100644 index 6ccdb263c..000000000 --- a/src/web/page.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Generic page struct - -use std::collections::BTreeMap; -use rustc_serialize::json::{Json, ToJson}; -use iron::{IronResult, Set, status}; -use iron::response::Response; -use handlebars_iron::Template; - - -pub struct Page { - title: Option, - content: T, - status: status::Status, - varss: BTreeMap, - varsb: BTreeMap, - varsi: BTreeMap, -} - - -impl Page { - pub fn new(content: T) -> Page { - Page { - title: None, - content: content, - status: status::Ok, - varss: BTreeMap::new(), - varsb: BTreeMap::new(), - varsi: BTreeMap::new(), - } - } - - /// Sets a string variable - pub fn set(mut self, var: &str, val: &str) -> Page { - &self.varss.insert(var.to_owned(), val.to_owned()); - self - } - - - /// Sets a boolean variable - pub fn set_bool(mut self, var: &str, val: bool) -> Page { - &self.varsb.insert(var.to_owned(), val); - self - } - - - /// Sets a boolean variable to true - pub fn set_true(mut self, var: &str) -> Page { - &self.varsb.insert(var.to_owned(), true); - self - } - - - /// Sets an integer variable - pub fn set_int(mut self, var: &str, val: i64) -> Page { - &self.varsi.insert(var.to_owned(), val); - self - } - - - /// Sets title of page - pub fn title(mut self, title: &str) -> Page { - self.title = Some(title.to_owned()); - self - } - - - /// Sets status code for response - pub fn set_status(mut self, s: status::Status) -> Page { - self.status = s; - self - } - - - pub fn to_resp(self, template: &str) -> IronResult { - let mut resp = Response::new(); - let status = self.status; - let temp = Template::new(template, self); - resp.set_mut(temp).set_mut(status); - Ok(resp) - } -} - - -impl ToJson for Page { - fn to_json(&self) -> Json { - let mut tree = BTreeMap::new(); - - if let Some(ref title) = self.title { - tree.insert("title".to_owned(), title.to_json()); - } - - tree.insert("content".to_owned(), self.content.to_json()); - tree.insert("cratesfyi_version".to_owned(), ::BUILD_VERSION.to_json()); - tree.insert("cratesfyi_version_safe".to_owned(), - ::BUILD_VERSION.replace(" ", "-").replace("(", "").replace(")", "").to_json()); - tree.insert("varss".to_owned(), self.varss.to_json()); - tree.insert("varsb".to_owned(), self.varsb.to_json()); - tree.insert("varsi".to_owned(), self.varsi.to_json()); - Json::Object(tree) - } -} diff --git a/src/web/pool.rs b/src/web/pool.rs deleted file mode 100644 index cbd5c2b3b..000000000 --- a/src/web/pool.rs +++ /dev/null @@ -1,29 +0,0 @@ - - -use iron::prelude::*; -use iron::{BeforeMiddleware, typemap}; -use r2d2; -use r2d2_postgres; -use db::create_pool; - - -pub struct Pool { - pool: r2d2::Pool, -} - -impl typemap::Key for Pool { - type Value = r2d2::PooledConnection; -} - -impl Pool { - pub fn new() -> Pool { - Pool { pool: create_pool() } - } -} - -impl BeforeMiddleware for Pool { - fn before(&self, req: &mut Request) -> IronResult<()> { - req.extensions.insert::(self.pool.get().unwrap()); - Ok(()) - } -} diff --git a/src/web/releases.rs b/src/web/releases.rs deleted file mode 100644 index 1605e19c5..000000000 --- a/src/web/releases.rs +++ /dev/null @@ -1,581 +0,0 @@ -//! Releases web handlers - - -use super::{duration_to_str, match_version}; -use super::error::Nope; -use super::page::Page; -use super::pool::Pool; -use iron::prelude::*; -use iron::status; -use router::Router; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; -use time; -use postgres::Connection; - - -/// Number of release in home page -const RELEASES_IN_HOME: i64 = 15; -/// Releases in /releases page -const RELEASES_IN_RELEASES: i64 = 30; -/// Releases in recent releases feed -const RELEASES_IN_FEED: i64 = 150; - - -pub struct Release { - name: String, - version: String, - description: Option, - target_name: Option, - rustdoc_status: bool, - release_time: time::Timespec, - stars: i32, -} - - -impl Default for Release { - fn default() -> Release { - Release { - name: String::new(), - version: String::new(), - description: None, - target_name: None, - rustdoc_status: false, - release_time: time::get_time(), - stars: 0, - } - } -} - - -impl ToJson for Release { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("name".to_string(), self.name.to_json()); - m.insert("version".to_string(), self.version.to_json()); - m.insert("description".to_string(), self.description.to_json()); - m.insert("target_name".to_string(), self.target_name.to_json()); - m.insert("rustdoc_status".to_string(), self.rustdoc_status.to_json()); - m.insert("release_time".to_string(), - duration_to_str(self.release_time).to_json()); - m.insert("release_time_rfc3339".to_string(), - format!("{}", time::at(self.release_time).rfc3339()).to_json()); - m.insert("stars".to_string(), self.stars.to_json()); - m.to_json() - } -} - - -enum Order { - ReleaseTime, // this is default order - GithubStars, - RecentFailures, - FailuresByGithubStars, -} - - -fn get_releases(conn: &Connection, page: i64, limit: i64, order: Order) -> Vec { - - let offset = (page - 1) * limit; - - // TODO: This function changed so much during development and current version have code - // repeats for queries. There is definitely room for improvements. - let query = match order { - Order::ReleaseTime => { - "SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.release_time, - releases.rustdoc_status, - crates.github_stars - FROM crates - INNER JOIN releases ON crates.id = releases.crate_id - ORDER BY releases.release_time DESC - LIMIT $1 OFFSET $2" - } - Order::GithubStars => { - "SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.release_time, - releases.rustdoc_status, - crates.github_stars - FROM crates - INNER JOIN releases ON releases.id = crates.latest_version_id - ORDER BY crates.github_stars DESC - LIMIT $1 OFFSET $2" - } - Order::RecentFailures => { - "SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.release_time, - releases.rustdoc_status, - crates.github_stars - FROM crates - INNER JOIN releases ON crates.id = releases.crate_id - WHERE releases.build_status = FALSE AND releases.is_library = TRUE - ORDER BY releases.release_time DESC - LIMIT $1 OFFSET $2" - } - Order::FailuresByGithubStars => { - "SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.release_time, - releases.rustdoc_status, - crates.github_stars - FROM crates - INNER JOIN releases ON releases.id = crates.latest_version_id - WHERE releases.build_status = FALSE AND releases.is_library = TRUE - ORDER BY crates.github_stars DESC - LIMIT $1 OFFSET $2" - } - }; - - let mut packages = Vec::new(); - for row in &conn.query(&query, &[&limit, &offset]).unwrap() { - let package = Release { - name: row.get(0), - version: row.get(1), - description: row.get(2), - target_name: row.get(3), - release_time: row.get(4), - rustdoc_status: row.get(5), - stars: row.get(6), - }; - - packages.push(package); - } - - packages -} - - - -fn get_releases_by_author(conn: &Connection, - page: i64, - limit: i64, - author: &str) - -> (String, Vec) { - - let offset = (page - 1) * limit; - - let query = "SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.release_time, - releases.rustdoc_status, - crates.github_stars, - authors.name - FROM crates - INNER JOIN releases ON releases.id = crates.latest_version_id - INNER JOIN author_rels ON releases.id = author_rels.rid - INNER JOIN authors ON authors.id = author_rels.aid - WHERE authors.slug = $1 - ORDER BY crates.github_stars DESC - LIMIT $2 OFFSET $3"; - - let mut author_name = String::new(); - let mut packages = Vec::new(); - for row in &conn.query(&query, &[&author, &limit, &offset]).unwrap() { - let package = Release { - name: row.get(0), - version: row.get(1), - description: row.get(2), - target_name: row.get(3), - release_time: row.get(4), - rustdoc_status: row.get(5), - stars: row.get(6), - }; - - author_name = row.get(7); - packages.push(package); - } - - (author_name, packages) -} - - - -fn get_releases_by_owner(conn: &Connection, - page: i64, - limit: i64, - author: &str) - -> (String, Vec) { - - let offset = (page - 1) * limit; - - let query = "SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.release_time, - releases.rustdoc_status, - crates.github_stars, - owners.name, - owners.login - FROM crates - INNER JOIN releases ON releases.id = crates.latest_version_id - INNER JOIN owner_rels ON owner_rels.cid = crates.id - INNER JOIN owners ON owners.id = owner_rels.oid - WHERE owners.login = $1 - ORDER BY crates.github_stars DESC - LIMIT $2 OFFSET $3"; - - let mut author_name = String::new(); - let mut packages = Vec::new(); - for row in &conn.query(&query, &[&author, &limit, &offset]).unwrap() { - let package = Release { - name: row.get(0), - version: row.get(1), - description: row.get(2), - target_name: row.get(3), - release_time: row.get(4), - rustdoc_status: row.get(5), - stars: row.get(6), - }; - - author_name = if !row.get::(7).is_empty() { - row.get(7) - } else { - row.get(8) - }; - packages.push(package); - } - - (author_name, packages) -} - - - -fn get_search_results(conn: &Connection, - query: &str, - page: i64, - limit: i64) - -> Option<(i64, Vec)> { - - let offset = (page - 1) * limit; - let mut packages = Vec::new(); - - let rows = match conn.query("SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.release_time, - releases.rustdoc_status, - ts_rank_cd(crates.content, to_tsquery($1)) AS rank - FROM crates - INNER JOIN releases ON crates.latest_version_id = releases.id - WHERE crates.name LIKE concat('%', $1, '%') - OR crates.content @@ to_tsquery($1) - ORDER BY crates.name = $1 DESC, - crates.name LIKE concat('%', $1, '%') DESC, - rank DESC - LIMIT $2 OFFSET $3", - &[&query, &limit, &offset]) { - Ok(r) => r, - Err(_) => return None, - }; - - for row in &rows { - let package = Release { - name: row.get(0), - version: row.get(1), - description: row.get(2), - target_name: row.get(3), - release_time: row.get(4), - rustdoc_status: row.get(5), - ..Release::default() - }; - - packages.push(package); - } - - if !packages.is_empty() { - // get count of total results - let rows = conn.query("SELECT COUNT(*) FROM crates WHERE content @@ to_tsquery($1)", - &[&query]) - .unwrap(); - - Some((rows.get(0).get(0), packages)) - } else { - None - } -} - - - -pub fn home_page(req: &mut Request) -> IronResult { - let conn = extension!(req, Pool); - let packages = get_releases(conn, 1, RELEASES_IN_HOME, Order::ReleaseTime); - Page::new(packages) - .set_true("show_search_form") - .set_true("hide_package_navigation") - .to_resp("releases") -} - - -pub fn releases_feed_handler(req: &mut Request) -> IronResult { - let conn = extension!(req, Pool); - let packages = get_releases(conn, 1, RELEASES_IN_FEED, Order::ReleaseTime); - let mut resp = ctry!(Page::new(packages).to_resp("releases_feed")); - resp.headers.set(::iron::headers::ContentType("application/atom+xml".parse().unwrap())); - Ok(resp) -} - - -pub fn releases_handler(packages: Vec, - page_number: i64, - release_type: &str, - tab: &str, - title: &str) -> IronResult { - if packages.is_empty() { - return Err(IronError::new(Nope::CrateNotFound, status::NotFound)); - } - - // Show next and previous page buttons - // This is a temporary solution to avoid expensive COUNT(*) - let (show_next_page, show_previous_page) = (packages.len() == RELEASES_IN_RELEASES as usize, - page_number != 1); - - Page::new(packages) - .title("Releases") - .set("description", title) - .set("release_type", release_type) - .set_true("show_releases_navigation") - .set_true(tab) - .set_bool("show_next_page_button", show_next_page) - .set_int("next_page", page_number + 1) - .set_bool("show_previous_page_button", show_previous_page) - .set_int("previous_page", page_number - 1) - .to_resp("releases") -} - - -// Following functions caused a code repeat due to design of our /releases/ URL routes -pub fn recent_releases_handler(req: &mut Request) -> IronResult { - let page_number: i64 = extension!(req, Router).find("page").unwrap_or("1").parse().unwrap_or(1); - let conn = extension!(req, Pool); - let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::ReleaseTime); - releases_handler(packages, page_number, "recent", "releases_navigation_recent_tab", "Recently uploaded crates") -} - - -pub fn releases_by_stars_handler(req: &mut Request) -> IronResult { - let page_number: i64 = extension!(req, Router).find("page").unwrap_or("1").parse().unwrap_or(1); - let conn = extension!(req, Pool); - let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::GithubStars); - releases_handler(packages, page_number, "stars", "releases_navigation_stars_tab", "Crates with most stars") -} - - -pub fn releases_recent_failures_handler(req: &mut Request) -> IronResult { - let page_number: i64 = extension!(req, Router).find("page").unwrap_or("1").parse().unwrap_or(1); - let conn = extension!(req, Pool); - let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::RecentFailures); - releases_handler(packages, page_number, "recent-failures", "releases_navigation_recent_failures_tab", "Recent crates failed to build") -} - - -pub fn releases_failures_by_stars_handler(req: &mut Request) -> IronResult { - let page_number: i64 = extension!(req, Router).find("page").unwrap_or("1").parse().unwrap_or(1); - let conn = extension!(req, Pool); - let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::FailuresByGithubStars); - releases_handler(packages, page_number, "failures", "releases_navigation_failures_by_stars_tab", "Crates with most stars failed to build") -} - - -pub fn author_handler(req: &mut Request) -> IronResult { - let router = extension!(req, Router); - // page number of releases - let page_number: i64 = router.find("page").unwrap_or("1").parse().unwrap_or(1); - - let conn = extension!(req, Pool); - let author = ctry!(router.find("author") - .ok_or(IronError::new(Nope::CrateNotFound, status::NotFound))); - - let (author_name, packages) = if author.starts_with("@") { - let mut author = author.clone().split("@"); - get_releases_by_owner(conn, - page_number, - RELEASES_IN_RELEASES, - cexpect!(author.nth(1))) - } else { - get_releases_by_author(conn, page_number, RELEASES_IN_RELEASES, author) - }; - - if packages.is_empty() { - return Err(IronError::new(Nope::CrateNotFound, status::NotFound)); - } - - // Show next and previous page buttons - // This is a temporary solution to avoid expensive COUNT(*) - let (show_next_page, show_previous_page) = (packages.len() == RELEASES_IN_RELEASES as usize, - page_number != 1); - Page::new(packages) - .title("Releases") - .set("description", &format!("Crates from {}", author_name)) - .set("author", &author_name) - .set("release_type", author) - .set_true("show_releases_navigation") - .set_true("show_stars") - .set_bool("show_next_page_button", show_next_page) - .set_int("next_page", page_number + 1) - .set_bool("show_previous_page_button", show_previous_page) - .set_int("previous_page", page_number - 1) - .to_resp("releases") -} - - -pub fn search_handler(req: &mut Request) -> IronResult { - use params::{Params, Value}; - - let params = ctry!(req.get::()); - let query = params.find(&["query"]); - - let conn = extension!(req, Pool); - if let Some(&Value::String(ref query)) = query { - - // check if I am feeling lucky button pressed and redirect user to crate page - // if there is a match - // TODO: Redirecting to latest doc might be more useful - if params.find(&["i-am-feeling-lucky"]).is_some() { - - use iron::Url; - use iron::modifiers::Redirect; - - // redirect to a random crate if query is empty - if query.is_empty() { - let rows = ctry!(conn.query("SELECT crates.name, - releases.version, - releases.target_name - FROM crates - INNER JOIN releases - ON crates.latest_version_id = releases.id - WHERE github_stars >= 100 AND rustdoc_status = true - OFFSET FLOOR(RANDOM() * 280) LIMIT 1", - &[])); - // ~~~~~~^ - // FIXME: This is a fast query but using a constant - // There are currently 280 crates with docs and 100+ - // starts. This should be fine for a while. - let name: String = rows.get(0).get(0); - let version: String = rows.get(0).get(1); - let target_name: String = rows.get(0).get(2); - let url = ctry!(Url::parse(&format!("{}://{}:{}/{}/{}/{}", - req.url.scheme(), - req.url.host(), - req.url.port(), - name, - version, - target_name))); - - let mut resp = Response::with((status::Found, Redirect(url))); - use iron::headers::{Expires, HttpDate}; - use time; - resp.headers.set(Expires(HttpDate(time::now()))); - return Ok(resp); - } - - - if let Some(version) = match_version(&conn, &query, None) { - // FIXME: This is a super dirty way to check if crate have rustdocs generated. - // match_version should handle this instead of this code block. - // This block is introduced to fix #163 - let rustdoc_status = { - let rows = ctry!(conn.query("SELECT rustdoc_status - FROM releases - INNER JOIN crates - ON crates.id = releases.crate_id - WHERE crates.name = $1 AND releases.version = $2", - &[query, &version])); - if rows.is_empty() { - false - } else { - rows.get(0).get(0) - } - }; - let url = if rustdoc_status { - ctry!(Url::parse(&format!("{}://{}:{}/{}/{}", - req.url.scheme(), - req.url.host(), - req.url.port(), - query, - version)[..])) - } else { - ctry!(Url::parse(&format!("{}://{}:{}/crate/{}/{}", - req.url.scheme(), - req.url.host(), - req.url.port(), - query, - version)[..])) - }; - let mut resp = Response::with((status::Found, Redirect(url))); - - use iron::headers::{Expires, HttpDate}; - use time; - resp.headers.set(Expires(HttpDate(time::now()))); - return Ok(resp); - } - } - - - let search_query = query.replace(" ", " & "); - get_search_results(&conn, &search_query, 1, RELEASES_IN_RELEASES) - .ok_or(IronError::new(Nope::NoResults, status::NotFound)) - .and_then(|(_, results)| { - // FIXME: There is no pagination - Page::new(results) - .set("search_query", &query) - .title(&format!("Search results for '{}'", query)) - .to_resp("releases") - }) - } else { - Err(IronError::new(Nope::NoResults, status::NotFound)) - } -} - - -pub fn activity_handler(req: &mut Request) -> IronResult { - let conn = extension!(req, Pool); - let release_activity_data: Json = - ctry!(conn.query("SELECT value FROM config WHERE name = 'release_activity'", - &[])) - .get(0) - .get(0); - Page::new(release_activity_data) - .title("Releases") - .set("description", "Monthly release activity") - .set_true("show_releases_navigation") - .set_true("releases_navigation_activity_tab") - .set_true("javascript_highchartjs") - .to_resp("releases_activity") -} - - -pub fn build_queue_handler(req: &mut Request) -> IronResult { - let conn = extension!(req, Pool); - let mut crates: Vec<(String, String)> = Vec::new(); - for krate in &conn.query("SELECT name, version - FROM queue - WHERE attempt < 5 - ORDER BY id ASC", - &[]) - .unwrap() { - crates.push((krate.get(0), krate.get(1))); - } - let is_empty = crates.is_empty(); - Page::new(crates) - .title("Build queue") - .set("description", "List of crates scheduled to build") - .set_bool("queue_empty", is_empty) - .set_true("show_releases_navigation") - .set_true("releases_queue_tab") - .to_resp("releases_queue") -} diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs deleted file mode 100644 index 033e0c80d..000000000 --- a/src/web/rustdoc.rs +++ /dev/null @@ -1,273 +0,0 @@ -//! rustdoc handler - - -use super::pool::Pool; -use super::file::File; -use super::latest_version; -use super::crate_details::CrateDetails; -use iron::prelude::*; -use iron::{status, Url}; -use iron::modifiers::Redirect; -use router::Router; -use super::match_version; -use super::error::Nope; -use super::page::Page; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; -use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective}; -use time; -use iron::Handler; -use utils; - - -#[derive(Debug)] -struct RustdocPage { - pub head: String, - pub body: String, - pub body_class: String, - pub name: String, - pub full: String, - pub version: String, - pub description: Option, - pub crate_details: Option, -} - - -impl Default for RustdocPage { - fn default() -> RustdocPage { - RustdocPage { - head: String::new(), - body: String::new(), - body_class: String::new(), - name: String::new(), - full: String::new(), - version: String::new(), - description: None, - crate_details: None, - } - } -} - - -impl ToJson for RustdocPage { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("rustdoc_head".to_string(), self.head.to_json()); - m.insert("rustdoc_body".to_string(), self.body.to_json()); - m.insert("rustdoc_body_class".to_string(), self.body_class.to_json()); - m.insert("rustdoc_full".to_string(), self.full.to_json()); - m.insert("rustdoc_status".to_string(), true.to_json()); - m.insert("name".to_string(), self.name.to_json()); - m.insert("version".to_string(), self.version.to_json()); - m.insert("description".to_string(), self.description.to_json()); - m.insert("crate_details".to_string(), self.crate_details.to_json()); - m.to_json() - } -} - - - -pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult { - - fn redirect_to_doc(req: &Request, - name: &str, - vers: &str, - target_name: &str) - -> IronResult { - let url = ctry!(Url::parse(&format!("{}://{}:{}/{}/{}/{}/", - req.url.scheme(), - req.url.host(), - req.url.port(), - name, - vers, - target_name)[..])); - let mut resp = Response::with((status::Found, Redirect(url))); - resp.headers.set(Expires(HttpDate(time::now()))); - - Ok(resp) - } - - let router = extension!(req, Router); - // this handler should never called without crate pattern - let crate_name = cexpect!(router.find("crate")); - let req_version = router.find("version"); - - let conn = extension!(req, Pool); - - let version = match match_version(&conn, &crate_name, req_version) { - Some(v) => v, - None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)), - }; - - // get target name - // FIXME: This is a bit inefficient but allowing us to use less code in general - let target_name: String = - ctry!(conn.query("SELECT target_name - FROM releases - INNER JOIN crates ON crates.id = releases.crate_id - WHERE crates.name = $1 AND releases.version = $2", - &[&crate_name, &version])) - .get(0) - .get(0); - - redirect_to_doc(req, &crate_name, &version, &target_name) -} - - -/// Serves documentation generated by rustdoc. -/// -/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is -/// also crate-specific. -pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult { - - let router = extension!(req, Router); - let name = router.find("crate").unwrap_or("").to_string(); - let version = router.find("version"); - let conn = extension!(req, Pool); - let version = try!(match_version(&conn, &name, version) - .ok_or(IronError::new(Nope::ResourceNotFound, status::NotFound))); - let mut req_path = req.url.path(); - - // remove name and version from path - for _ in 0..2 { - req_path.remove(0); - } - - // docs have "rustdoc" prefix in database - req_path.insert(0, "rustdoc"); - - // add crate name and version - req_path.insert(1, &name); - req_path.insert(2, &version); - - let path = { - let mut path = req_path.join("/"); - if path.ends_with("/") { - path.push_str("index.html"); - req_path.push("index.html"); - } - path - }; - - let file = match File::from_path(&conn, &path) { - Some(f) => f, - None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)), - }; - - // serve file directly if it's not html - if !path.ends_with(".html") { - return Ok(file.serve()); - } - - let mut content = RustdocPage::default(); - - let file_content = ctry!(String::from_utf8(file.content)); - - let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content)); - content.head = head; - content.body = body; - - if body_class.is_empty() { - body_class = "rustdoc container-rustdoc".to_string(); - } else { - // rustdoc adds its own "rustdoc" class to the body - body_class.push_str(" container-rustdoc"); - } - content.body_class = body_class; - - content.full = file_content; - let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version)); - let latest_version = latest_version(&crate_details.versions, &version); - - content.crate_details = Some(crate_details); - - Page::new(content) - .set_true("show_package_navigation") - .set_true("package_navigation_documentation_tab") - .set_true("package_navigation_show_platforms_tab") - .set_bool("is_latest_version", latest_version.is_none()) - .set("latest_version", &latest_version.unwrap_or(String::new())) - .to_resp("rustdoc") -} - - - -pub fn badge_handler(req: &mut Request) -> IronResult { - use iron::headers::ContentType; - use params::{Params, Value}; - use badge::{Badge, BadgeOptions}; - - let version = { - let params = ctry!(req.get_ref::()); - match params.find(&["version"]) { - Some(&Value::String(ref version)) => version.clone(), - _ => "*".to_owned(), - } - }; - - let name = cexpect!(extension!(req, Router).find("crate")); - let conn = extension!(req, Pool); - - let options = match match_version(&conn, &name, Some(&version)) { - Some(version) => { - let rows = ctry!(conn.query("SELECT rustdoc_status - FROM releases - INNER JOIN crates ON crates.id = releases.crate_id - WHERE crates.name = $1 AND releases.version = $2", - &[&name, &version])); - if rows.len() > 0 && rows.get(0).get(0) { - BadgeOptions { - subject: "docs".to_owned(), - status: version, - color: "#4d76ae".to_owned(), - } - } else { - BadgeOptions { - subject: "docs".to_owned(), - status: version, - color: "#e05d44".to_owned(), - } - } - } - None => { - BadgeOptions { - subject: "docs".to_owned(), - status: "no builds".to_owned(), - color: "#e05d44".to_owned(), - } - } - }; - - let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg())); - resp.headers.set(ContentType("image/svg+xml".parse().unwrap())); - resp.headers.set(Expires(HttpDate(time::now()))); - resp.headers.set(CacheControl(vec![CacheDirective::NoCache, - CacheDirective::NoStore, - CacheDirective::MustRevalidate])); - Ok(resp) -} - -/// Serves shared web resources used by rustdoc-generated documentation. -/// -/// This includes common `css` and `js` files that only change when the compiler is updated, but are -/// otherwise the same for all crates documented with that compiler. Those have a custom handler to -/// deduplicate them and save space. -pub struct SharedResourceHandler; - -impl Handler for SharedResourceHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let path = req.url.path(); - let filename = path.last().unwrap(); // unwrap is fine: vector is non-empty - let suffix = filename.split('.').last().unwrap(); // unwrap is fine: split always works - if ["js", "css", "woff", "svg"].contains(&suffix) { - let conn = extension!(req, Pool); - - if let Some(file) = File::from_path(conn, filename) { - return Ok(file.serve()); - } - } - - // Just always return a 404 here - the main handler will then try the other handlers - Err(IronError::new(Nope::ResourceNotFound, status::NotFound)) - } -} diff --git a/src/web/sitemap.rs b/src/web/sitemap.rs deleted file mode 100644 index 4bab4fadc..000000000 --- a/src/web/sitemap.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::collections::BTreeMap; -use iron::prelude::*; -use iron::headers::ContentType; -use rustc_serialize::json::Json; -use super::page::Page; -use super::pool::Pool; -use time; - -pub fn sitemap_handler(req: &mut Request) -> IronResult { - let conn = extension!(req, Pool); - let mut releases: Vec<(String, String)> = Vec::new(); - for row in &conn.query("SELECT DISTINCT ON (crates.name) - crates.name, - releases.release_time - FROM crates - INNER JOIN releases ON releases.crate_id = crates.id - WHERE rustdoc_status = true", - &[]) - .unwrap() { - releases.push((row.get(0), format!("{}", time::at(row.get(1)).rfc3339()))); - } - let mut resp = ctry!(Page::new(releases).to_resp("sitemap")); - resp.headers.set(ContentType("application/xml".parse().unwrap())); - Ok(resp) -} - - -pub fn robots_txt_handler(_: &mut Request) -> IronResult { - let mut resp = Response::with("Sitemap: https://docs.rs/sitemap.xml"); - resp.headers.set(ContentType("text/plain".parse().unwrap())); - Ok(resp) -} - -pub fn about_handler(req: &mut Request) -> IronResult { - let mut content = BTreeMap::new(); - - let conn = extension!(req, Pool); - let res = ctry!(conn.query("SELECT value FROM config WHERE name = 'rustc_version'", &[])); - - if let Some(row) = res.iter().next() { - if let Some(Ok::(res)) = row.get_opt(0) { - if let Some(vers) = res.as_string() { - content.insert("rustc_version".to_string(), vers.to_string()); - } - } - } - - Page::new(content).title("About Docs.rs").to_resp("about") -} diff --git a/src/web/source.rs b/src/web/source.rs deleted file mode 100644 index ea8679610..000000000 --- a/src/web/source.rs +++ /dev/null @@ -1,251 +0,0 @@ -//! Source code browser - - -use std::collections::BTreeMap; -use std::cmp::Ordering; -use super::MetaData; -use super::page::Page; -use super::pool::Pool; -use super::file::File as DbFile; -use iron::prelude::*; -use router::Router; -use rustc_serialize::json::{Json, ToJson}; -use postgres::Connection; - - -#[derive(PartialEq, PartialOrd)] -enum FileType { - Dir, - Text, - Binary, - RustSource, -} - - -#[derive(PartialEq, PartialOrd)] -struct File { - name: String, - file_type: FileType, -} - - -struct FileList { - metadata: MetaData, - files: Vec, -} - - -impl ToJson for FileList { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - - m.insert("metadata".to_string(), self.metadata.to_json()); - - let mut file_vec: Vec = Vec::new(); - - for file in &self.files { - let mut file_m: BTreeMap = BTreeMap::new(); - file_m.insert("name".to_string(), file.name.to_json()); - - file_m.insert(match file.file_type { - FileType::Dir => "file_type_dir".to_string(), - FileType::Text => "file_type_text".to_string(), - FileType::Binary => "file_type_binary".to_string(), - FileType::RustSource => "file_type_rust_source".to_string(), - }, - true.to_json()); - - file_vec.push(file_m.to_json()); - } - - m.insert("files".to_string(), file_vec.to_json()); - m.to_json() - } -} - - -impl FileList { - /// Gets FileList from a request path - /// - /// All paths stored in database have this format: - /// - /// ```text - /// [ - /// ["text/plain",".gitignore"], - /// ["text/x-c","src/reseeding.rs"], - /// ["text/x-c","src/lib.rs"], - /// ["text/x-c","README.md"], - /// ... - /// ] - /// ``` - /// - /// This function is only returning FileList for requested directory. If is empty, - /// it will return list of files (and dirs) for root directory. req_path must be a - /// directory or empty for root directory. - pub fn from_path(conn: &Connection, - name: &str, - version: &str, - req_path: &str) - -> Option { - - let rows = conn.query("SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.rustdoc_status, - releases.files - FROM releases - LEFT OUTER JOIN crates ON crates.id = releases.crate_id - WHERE crates.name = $1 AND releases.version = $2", - &[&name, &version]) - .unwrap(); - - if rows.len() == 0 { - return None; - } - - let files: Json = rows.get(0).get(5); - - let mut file_list: Vec = Vec::new(); - - files.as_array().map(|files| { - for file in files { - file.as_array().map(|file| { - let mime = file[0].as_string().unwrap(); - let path = file[1].as_string().unwrap(); - - // skip .cargo-ok generated by cargo - if path == ".cargo-ok" { - return; - } - - // look only files for req_path - if path.starts_with(&req_path) { - // remove req_path from path to reach files in this directory - let path = path.replace(&req_path, ""); - let path_splited: Vec<&str> = path.split("/").collect(); - - // if path have '/' it is a directory - let ftype = if path_splited.len() > 1 { - FileType::Dir - } else if mime.starts_with("text") && - path_splited[0].ends_with(".rs") { - FileType::RustSource - } else if mime.starts_with("text") { - FileType::Text - } else { - FileType::Binary - }; - - let file = File { - name: path_splited[0].to_owned(), - file_type: ftype, - }; - - // avoid adding duplicates, a directory may occur more than once - if !file_list.contains(&file) { - file_list.push(file); - } - } - }); - } - }); - - if file_list.is_empty() { - return None; - } - - file_list.sort_by(|a, b| { - // directories must be listed first - if a.file_type == FileType::Dir && b.file_type != FileType::Dir { - Ordering::Less - } else if a.file_type != FileType::Dir && b.file_type == FileType::Dir { - Ordering::Greater - } else { - a.name.to_lowercase().cmp(&b.name.to_lowercase()) - } - }); - - Some(FileList { - metadata: MetaData { - name: rows.get(0).get(0), - version: rows.get(0).get(1), - description: rows.get(0).get(2), - target_name: rows.get(0).get(3), - rustdoc_status: rows.get(0).get(4), - }, - files: file_list, - }) - } -} - - -pub fn source_browser_handler(req: &mut Request) -> IronResult { - let router = extension!(req, Router); - let name = cexpect!(router.find("name")); - let version = cexpect!(router.find("version")); - - // get path (req_path) for FileList::from_path and actual path for super::file::File::from_path - let (req_path, file_path) = { - let mut req_path = req.url.path(); - // remove first elements from path which is /crate/:name/:version/source - for _ in 0..4 { - req_path.remove(0); - } - let file_path = format!("sources/{}/{}/{}", name, version, req_path.join("/")); - - // FileList::from_path is only working for directories - // remove file name if it's not a directory - req_path.last_mut().map(|last| { - if !last.is_empty() { - *last = ""; - } - }); - - // remove crate name and version from req_path - let path = req_path.join("/").replace(&format!("{}/{}/", name, version), ""); - - (path, file_path) - }; - - - let conn = extension!(req, Pool); - - // try to get actual file first - // skip if request is a directory - let file = if !file_path.ends_with("/") { - DbFile::from_path(&conn, &file_path) - } else { - None - }; - - - let (content, is_rust_source) = if let Some(file) = file { - // serve the file with DatabaseFileHandler if file isn't text and not empty - if !file.mime.starts_with("text") && !file.is_empty() { - return Ok(file.serve()); - } else if file.mime.starts_with("text") && !file.is_empty() { - (String::from_utf8(file.content).ok(), file.path.ends_with(".rs")) - } else { - (None, false) - } - } else { - (None, false) - }; - - let list = FileList::from_path(&conn, &name, &version, &req_path); - - let page = Page::new(list) - .set_bool("show_parent_link", !req_path.is_empty()) - .set_true("javascript_highlightjs") - .set_true("show_package_navigation") - .set_true("package_source_tab"); - - if let Some(content) = content { - page.set("file_content", &content) - .set_bool("file_content_rust_source", is_rust_source) - .to_resp("source") - } else { - page.to_resp("source") - } -} diff --git a/templates/about.hbs b/templates/about.hbs deleted file mode 100644 index df740b6df..000000000 --- a/templates/about.hbs +++ /dev/null @@ -1,130 +0,0 @@ -{{> header}} - -
-

- Docs.rs (formerly cratesfyi) is an open source project to host - documentation of crates for the Rust Programming Language. -

- -

- Docs.rs automatically builds crates' documentation released on - crates.io - using the nightly release of the Rust compiler. - {{#if content.rustc_version}} - The current version of the Rust compiler in use is {{content.rustc_version}}. - If you need a newer version of this compiler, check the - issues page - and file a new issue if you don't see an existing request. - {{/if}} -

- -

- The source code of Docs.rs is available on - GitHub. If - you ever encounter an issue, don't hesitate to report it! (And - thanks in advance!) -

- -

- The README of a crate is taken from the readme field defined in - Cargo.toml. If a crate doesn't have this field, - no README will be displayed. -

- -

Redirections

- -

- Docs.rs is using semver to parse URLs. You can use this feature to access - crates' documentation easily. Example of URL redirections for - clap crate: -

- - - - - - - - - - - - - - - - - - - - - - - - - - -
URLRedirects to documentation of
docs.rs/clapLatest version of clap
docs.rs/clap/~22.* version
docs.rs/clap/~2.92.9.* version
docs.rs/clap/2.9.32.9.3 version (you don't need = unlike semver)
- -

Badges

-

- You can use badges to show state of your documentation to your users. - The default badge will be pointed at the latest version of a crate. - You can use version parameter to show status of documentation for - any version you want. -

-

- Badge will display in blue if docs.rs is successfully hosting your crate - documentation, and red if building documentation failing. -

-

Example badges for mio crate:

- - - - - - - - - - - - - - - - - - - - - -
URLBadge
Latest version: https://docs.rs/mio/badge.svgmio
Version 0.4.4: https://docs.rs/mio/badge.svg?version=0.4.4mio
Version 0.1.0: https://docs.rs/mio/badge.svg?version=0.1.0mio
- -

Metadata for custom builds

- -

You can customize docs.rs builds by defining [package.metadata.docs.rs] table in your crates' `Cargo.toml`.

- -

An example metadata:

- -
[package]
-name = "test"
-
-[package.metadata.docs.rs]
-features = [ "feature1", "feature2" ]
-all-features = true
-no-default-features = true
-default-target = "x86_64-unknown-linux-gnu"
-rustc-args = [ "--example-rustc-arg" ]
-rustdoc-args = [ "--example-rustdoc-arg" ]
-dependencies = [ "example-system-dependency" ]
- -

Version

-

Currently running Docs.rs version is: {{cratesfyi_version}} - -

Contact

-

Docs.rs is run and maintaned by Rustdoc team. You can find us in #rustdoc on Discord.

- -
- -{{> footer}} diff --git a/templates/builds.hbs b/templates/builds.hbs deleted file mode 100644 index c32fac506..000000000 --- a/templates/builds.hbs +++ /dev/null @@ -1,43 +0,0 @@ -{{> header}} - -{{#with content}} -
-
- - {{#if build_details}} -
- Build #{{build_details.id}} {{build_details.build_time}} -
-
-$ rustc --version
-{{build_details.rustc_version}}
-$ cratesfyi --version
-{{build_details.cratesfyi_version}}
-$ cratesfyi ...
-{{build_details.output}}
-    
- {{/if}} - -
- Builds -
- - -
-
-{{/with}} - -{{> footer}} diff --git a/templates/crate_details.hbs b/templates/crate_details.hbs deleted file mode 100644 index c6f8058f3..000000000 --- a/templates/crate_details.hbs +++ /dev/null @@ -1,78 +0,0 @@ -{{> header}} - - -{{#with content}} -
-
-
-
- -
-
-
- {{#unless is_library}} -
{{name}}-{{version}} is not a library.
- {{else}} - {{#unless build_status}} -
docs.rs failed to build {{name}}-{{version}}
Please check build logs and if you believe this is docs.rs' fault, report into this issue report.
- {{else}} - {{#unless rustdoc_status}} -
{{name}}-{{version}} doesn't have any documentation.
- {{/unless}} - {{/unless}} - {{/unless}} - {{#if readme}} - {{{readme}}} - {{else}} - {{{rustdoc}}} - {{/if}} -
-
- -
-{{/with}} - - -{{> footer}} diff --git a/templates/error.hbs b/templates/error.hbs deleted file mode 100644 index bf2fd7d93..000000000 --- a/templates/error.hbs +++ /dev/null @@ -1,2 +0,0 @@ -{{> header}} -{{> footer}} diff --git a/templates/footer.hbs b/templates/footer.hbs deleted file mode 100644 index aca7519a0..000000000 --- a/templates/footer.hbs +++ /dev/null @@ -1,3 +0,0 @@ -{{#if varsb.javascript_highlightjs}}{{/if}} - - diff --git a/templates/header.hbs b/templates/header.hbs deleted file mode 100644 index eea0c851d..000000000 --- a/templates/header.hbs +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - {{#if varsb.javascript_highlightjs}} - - - - {{/if}} - {{#if varsb.javascript_highchartjs}} - - {{/if}} - {{#if title}}{{title}} - {{/if}}{{#if content.metadata.name}}{{content.metadata.name}} {{content.metadata.version}} - {{/if}}Docs.rs - - - - {{> navigation}} diff --git a/templates/navigation.hbs b/templates/navigation.hbs deleted file mode 100644 index baddbe883..000000000 --- a/templates/navigation.hbs +++ /dev/null @@ -1,82 +0,0 @@ - - - {{#unless varsb.hide_package_navigation}} -
-
-

{{#if title}}{{title}}{{else}}{{content.metadata.name}} {{content.metadata.version}}{{/if}}

-
{{#if content.metadata.description }}{{content.metadata.description}}{{else}}{{varss.description}}{{/if}}
- - {{#if ../varsb.show_package_navigation}} -
- {{#if ../varsb.package_navigation_show_platforms_tab}} - - {{/if}} - {{#with content.metadata}} - - {{/with}} -
- {{/if}} - - {{#if varsb.show_releases_navigation}} -
- -
- {{/if}} -
-
- {{/unless}} diff --git a/templates/navigation_rustdoc.hbs b/templates/navigation_rustdoc.hbs deleted file mode 100644 index 329d65269..000000000 --- a/templates/navigation_rustdoc.hbs +++ /dev/null @@ -1,102 +0,0 @@ - diff --git a/templates/releases.hbs b/templates/releases.hbs deleted file mode 100644 index be5b371ba..000000000 --- a/templates/releases.hbs +++ /dev/null @@ -1,66 +0,0 @@ -{{> header}} - -{{#if varsb.show_search_form}} -
-

Docs.rs

- -
-
-
- - -
-
- -
-{{/if}} - -
-
- {{#if varsb.show_search_form}} - - {{/if}} - - - {{#unless varsb.show_search_form}} - - {{/unless}} -
-
- -{{> footer}} diff --git a/templates/releases_activity.hbs b/templates/releases_activity.hbs deleted file mode 100644 index c82617b1a..000000000 --- a/templates/releases_activity.hbs +++ /dev/null @@ -1,41 +0,0 @@ -{{> header}} -{{#with content}} - -
-
-
- - -{{/with}} -{{> footer}} diff --git a/templates/releases_feed.hbs b/templates/releases_feed.hbs deleted file mode 100644 index f3666fc7b..000000000 --- a/templates/releases_feed.hbs +++ /dev/null @@ -1,21 +0,0 @@ - - -Docs.rs -Recent Rust crates - - - - -urn:docs-rs:{{cratesfyi_version_safe}} -{{content[0].release_time_rfc3339}} -{{#each content}} - -{{name}}-{{version}} - -urn:docs-rs:{{name}}:{{version}} -{{release_time_rfc3339}} -{{#if description}}{{description}}{{else}}-{{/if}} -docs.rs - -{{/each}} - diff --git a/templates/releases_queue.hbs b/templates/releases_queue.hbs deleted file mode 100644 index 9ed6f10c9..000000000 --- a/templates/releases_queue.hbs +++ /dev/null @@ -1,22 +0,0 @@ -{{> header}} - -
-
- -
- {{#if varsb.queue_empty}} - There is nothing in queue - {{else}} - Queue - {{/if}} -
- -
    - {{#each content}} -
  1. {{this.[0]}}-{{this.[1]}}
  2. - {{/each}} -
-
-
- -{{> footer}} diff --git a/templates/rustdoc.hbs b/templates/rustdoc.hbs deleted file mode 100644 index 600825d46..000000000 --- a/templates/rustdoc.hbs +++ /dev/null @@ -1,17 +0,0 @@ - - - - {{{content.rustdoc_head}}} - - - - - - - -{{> navigation_rustdoc}} -
- {{{content.rustdoc_body}}} -
- - diff --git a/templates/sitemap.hbs b/templates/sitemap.hbs deleted file mode 100644 index a4d131285..000000000 --- a/templates/sitemap.hbs +++ /dev/null @@ -1,9 +0,0 @@ - - - {{#each content}} - - https://docs.rs/{{this.[0]}} - {{this.[1]}} - - {{/each}} - diff --git a/templates/source.hbs b/templates/source.hbs deleted file mode 100644 index 8ab5a72ad..000000000 --- a/templates/source.hbs +++ /dev/null @@ -1,38 +0,0 @@ -{{> header}} - - -{{#with content}} -
-
- - {{#if ../varss.file_content}} -
-
{{ ../varss.file_content }}
-
- {{/if}} -
-
-{{/with}} - -{{> footer}} diff --git a/templates/style.scss b/templates/style.scss deleted file mode 100644 index c0eb87222..000000000 --- a/templates/style.scss +++ /dev/null @@ -1,728 +0,0 @@ - -// FONTS -$font-family-sans: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; -$font-family-serif: "Source Serif Pro",Georgia,Times,"Times New Roman",serif; -$font-family-mono: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace; - - -// COLORS - Guess what? -$color-standard: #000; // pure black -$color-url: #4d76ae; // blue -$color-macro: #068000; // green -$color-struct: #df3600; // red -$color-enum: #5e9766; // light green -$color-type: #e57300; // orange -$color-keyword: #8959A8; // purple -$color-string: #718C00; // greenish -$color-macro-in-code: #3E999F; // blueish -$color-lifetime-incode: #B76514; // orangish -$color-comment-in-code: #8E908C; // light gray -$color-background-code: #F5F5F5; // lighter gray -$color-border: #ddd; // gray - - - -// pure compatible media queries -$media-sm: "screen and (min-width: 35.5em)"; -$media-md: "screen and (min-width: 48em)"; -$media-lg: "screen and (min-width: 64em)"; -$media-xl: "screen and (min-width: 80em)"; -// usage: -// @media #{$media-sm} { ... } - - -html, button, input, select, textarea, -.pure-g [class *= "pure-u"] { - font-family: $font-family-sans; - color: $color-standard; -} - -.pure-button-normal { - background-color: #fff; - box-sizing: border-box !important; - border: 1px solid $color-border; -} - -.description { - font-family: $font-family-serif; -} - -// rustdoc overrides -div.rustdoc { - font-family: $font-family-serif; - padding: 10px 15px 20px 15px; - - .sidebar { - padding-top: 32px; - .block > ul > li { - margin-right: -10px; - } - } - - // this is actual fix for docs.rs navigation and rustdoc sidebar - position: absolute; - left: 0; - right: 0; - top: 32px; -} - -body { - padding: 0; - margin: 0; -} - - -// this is a super nasty override for help dialog in rustdocs -// see #52 for details -body.blur > :not(#help) { - filter: none; - -webkit-filter: none; -} - -body.blur > div.nav-container > *, -body.blur > div.cratesfyi-package-container > *, -body.blur > div.rustdoc > :not(#help) { - filter: blur(8px); - -webkit-filter: blur(8px); - opacity: .7; -} - - -// rustdocs have 200px sidebar and -// max-width 960px main pane -// BUT I really want to make the website centered - -body { - text-align: center; - font: 16px/1.4 $font-family-sans; -} - -pre { - overflow: auto; - white-space: pre; -} - -div.container { - max-width: 1160px; - margin: 0 auto; - text-align: left; -} - -div.container-rustdoc { - max-width: 1200px; - text-align: left; -} - -div.nav-container { - height: 32px; - border-bottom: 1px solid $color-border; - background-color: #fff; - - li { - border-left: 1px solid $color-border; - } - - .pure-menu-has-children>.pure-menu-link:after { - font-size: 0.8em; - } - - a { - font-size: 0.8em; - font-weight: 400; - } - - .pure-menu-link:hover { - color: $color-standard; - background-color: inherit; - } - - form.landing-search-form-nav { - input.search-input-nav { - float: right; - max-width: 200px; - border: none; - margin: 0 1em 0 0; - font-size: 0.8em; - text-align: right; - box-shadow: none; - height: 31px; - display: none; - @media #{$media-sm} { - display: block; - } - } - input.search-input-nav:focus { - outline: unset; - } - } - - .pure-menu-children { - border: 1px solid $color-border; - border-radius: 0 0 2px 2px; - margin-left: -1px; - li { - border-left: none; - } - } - - // used for latest version warning - .warn { - color: $color-type; - } - - .warn:hover { - color: darken($color-type, 10%); - } - - div.rustdoc-navigation { - span.title { - display: none; - @media #{$media-sm} { - display: inline; - } - } - - div.package-details-menu { - width: 350px; - - p.description { - font-family: $font-family-sans; - font-size: 0.8em; - color: #777; // color from pure - padding: .5em 1em; - margin: 0; - } - - ul.pure-menu-list { - width: 100%; - } - - div.right-border { - border-right: 1px solid $color-border; - } - - a.pure-menu-link { - word-wrap: normal; - white-space: normal; - } - - div.sub-menu { - max-height: 150px; - overflow-y: auto; - - ul.pure-menu-list { - border-top: none; - } - - li.pure-menu-item:last-child { - border-bottom: none; - } - } - } - } -} - -div.nav-container-rustdoc { - position: absolute; - left: 0; - right: 0; - top: 0; - z-index: 999; -} - -div.landing { - text-align: center; - padding-top: 30px; - padding-bottom: 60px; - - h1.brand { - font-size: 3em; - margin-bottom: 10px; - } - - form.landing-search-form { - max-width: 500px; - margin: 0 auto; - padding: .4em 1em; - - div.buttons { - margin-top: 30px; - } - } - -} - - - -div.recent-releases-container { - text-align: left; - margin-bottom: 50px; - - ul, li { - list-style-type: none; - margin: 0; - padding: 0; - } - - ol.queue-list li { - list-style-type: decimal; - margin-left: 20px; - a { - color: $color-url; - } - } - - strong { - font-weight: 500; - } - - pre { - font-size: 0.8rem; - white-space: pre-wrap; - } - - .release { - display: block; - border-bottom: 1px solid $color-border; - padding: .4em 1em; - - @media #{$media-lg} { - padding: .4em 0; - margin: 0 1em; - } - } - - .release:hover { - background-color: $color-background-code; - } - - li:last-child .release { - border-bottom: none; - } - - .name { - color: $color-url; - font-weight: 500; - white-space: nowrap; - @media #{$media-sm} { - text-overflow: ellipsis; - overflow: hidden; - } - } - - .name:hover { - overflow: visible; - white-space: normal; - } - - .build { - font-weight: 500; - i.fa-check { - color: $color-macro; - } - i.fa-close { - color: $color-struct; - - } - } - - .description { - font-family: $font-family-serif; - font-weight: normal; - @media #{$media-sm} { - font-size: 1em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - - .description:hover { - @media #{$media-sm} { - overflow: visible; - white-space: normal; - } - } - - .date { - font-weight: normal; - @media #{$media-sm} { - text-align: right; - } - } - - div.pagination { - text-align: center; - margin: 1em; - - .pure-button { - margin: 0; - } - } -} - - -div.package-container { - background-color: $color-url; - color: $color-background-code;; - - h1 { - margin: 0; - padding: 20px 0 0 16px; - } - p { - margin: 0; - padding: 0 0 20px 16px; - } - - .pure-menu { - - .pure-menu-link { - background-color: #fff; - border-top: 1px solid $color-border; - border-left: 1px solid $color-border; - border-right: 1px solid $color-border; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom: 2px solid $color-border; - padding: .4em 1em; - } - - .pure-menu-active { - border-bottom: 2px solid #fff; - color: $color-standard; - } - - .pure-menu-link:hover { - color: $color-standard; - } - } -} - - -div.package-sheet-container { - margin-top: 10px; - margin-bottom: 20px; - - .pure-menu-link { - border-radius: 4px; - padding: .2em .8em; - font-weight: 400; - } - - .build-success { - color: $color-macro; - } - - .build-fail { - color: $color-struct; - } -} - -div.package-page-container { - div.package-menu { - padding: 0 10px; - margin-bottom: 50px; - - li.pure-menu-heading { - font-size: 1.3em; - color: #000; - font-weight: 500; - text-align: center; - border-bottom: 1px solid lighten($color-border, 5%); - text-transform: none; - padding-bottom: 6px; - margin: 20px 5px 15px 5px; - } - - li.pure-menu-heading:first-child { - margin-top: 0; - } - - li i.fa { - display: inline-block; - width: 20px; - } - - a.pure-menu-link { - font-size: 14px; - color: $color-standard; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - padding: 7px 8px; - } - - a.pure-menu-link:hover { - background-color: $color-background-code; - } - - div.sub-menu { - max-height: 135px; - overflow-y: auto; - - ul.pure-menu-list { - border-top: none; - } - - li.pure-menu-item:last-child { - border-bottom: none; - } - } - - img.owner { - max-width: 32px; - max-height: 32px; - border-radius: 2px; - } - } - - div.package-details { - padding: 0 1em; - - font-family: $font-family-serif; - - a { - color: $color-url; - } - - a:hover { - text-decoration: underline; - } - - h1, h2, h3, h4, h5, h6 { - font-family: $font-family-sans; - } - - h1:first-child, - h2:first-child, - h3:first-child, - h4:first-child, - h5:first-child, - h6:first-child { - margin-top: 0; - } - - table { - // most of this stuff is taken from pure tables.css - border-collapse: collapse; - border-spacing: 0; - empty-cells: show; - border: 1px solid #cbcbcb; - margin-bottom: 15px; - - td, th { - border-left: 1px solid #cbcbcb; - border-width: 0 0 0 1px; - font-size: inherit; - margin: 0; - overflow: visible; - padding: 0.5em 1em; - } - - th { - font-family: $font-family-sans; - font-weight: 500; - } - - td { - border-bottom: 1px solid #cbcbcb; - } - - tbody > tr:last-child > td { - border-bottom-width: 0; - } - - thead { - background-color: #e0e0e0; - color: #000; - text-align: left; - vertical-align: bottom; - } - - } - } - - pre { - background-color: inherit; - padding: 0; - - code { - white-space: pre; - } - } -} - - - -div.cratesfyi-package-container { - text-align: left; - background-color: $color-background-code; - border-bottom: 1px solid $color-border; - margin-bottom: 20px; - - h1 { - margin: 0; - padding: 15px 0 0 14px; - } - div.description { - font-family: $font-family-serif; - margin: 0; - padding: 0 0 15px 14px; - - @media #{$media-sm} { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - div.description-in-rustdoc { - padding: 10px 0 10px 14px; - } - - .pure-menu { - margin-bottom: -1px; - padding-left: 14px; - - .pure-menu-link { - color: #666; - font-size: 14px; - padding: .4em 1em .3em 1em; - - .title { - display: none; - @media #{$media-sm} { - display: inline; - } - } - } - - .pure-menu-active { - color: $color-standard; - - background-color: #fff; - border-top: 1px solid $color-border; - border-left: 1px solid $color-border; - border-right: 1px solid $color-border; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom: 2px solid #fff; - } - - .pure-menu-active:hover { - background-color: #fff !important; - } - - .pure-menu-link:hover { - color: #000; - background-color: inherit; - } - } - - ul.platforms-menu { - float: right; - display: none; - ul.pure-menu-children { - left: auto; - right: 0; - border: 1px solid $color-border; - border-radius: 2px; - } - - .pure-menu-has-children>.pure-menu-link:after { - font-size: 14px; - } - - @media #{$media-sm} { - display: inline-block; - } - } -} - -div.cratesfyi-package-container-rustdoc { - margin-bottom: 10px; -} - - -div.warning { - font-family: $font-family-sans; - border-radius: 4px; - background-color: lighten($color-type, 45%); - padding: .4em 1em; - text-align: center; - margin-bottom: 10px; - a { - color: $color-url; - text-decoration: underline; - } -} - - -div.search-page-search-form { - padding: .4em 1em; - text-align: center; - - input.search-input { - display: inline-block; - max-width: 300px; - padding: .4em 1em; - } -} - -.menu-item-divided { - border-bottom: 1px solid $color-border; -} - -.rust-navigation-item { - background: url(/rust-logo.png) no-repeat; - background-position: 15px 45%; - background-size: 12px; - padding-left: 35px; -} - - -footer { - margin-top: 60px; - margin-bottom: 10px; - text-align: center; - ul { - list-style-type: none; - li { - list-style-type: none; - margin-bottom: 10px; - - a { - font-weight: 500; - color: $color-url; - } - } - li.hosting { - font-size: .8em; - } - } -} - - -.about { - font-family: $font-family-serif; - padding: .4em 1em; - a { - color: $color-url; - } - a:hover { - text-decoration: underline; - } - table { - margin-bottom: 10px; - } - thead tr th { - font-family: $font-family-sans; - font-weight: 500; - } - strong { - font-weight: bold; - } - pre code { - background-color: inherit; - } -}