diff --git a/Cargo.lock b/Cargo.lock index ecd3584..95ff5c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,13 +2,32 @@ name = "cargo-outdated" version = "0.4.0" dependencies = [ - "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.26.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "tabwriter 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "advapi32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -22,10 +41,33 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "backtrace-sys" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" @@ -36,9 +78,58 @@ name = "bitflags" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cargo" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crates-io 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)", + "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cfg-if" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "clap" -version = "2.26.0" +version = "2.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -46,12 +137,19 @@ dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cmake" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "conv" version = "0.3.3" @@ -60,11 +158,194 @@ dependencies = [ "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crates-io" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "curl" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 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 = "curl-sys" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "custom_derive" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "dbghelp-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "docopt" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dtoa" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "env_logger" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "error-chain" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "filetime" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "flate2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fs2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gcc" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "git2" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "git2-curl" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "idna" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "jobserver" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -74,9 +355,57 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lazy_static" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" -version = "0.2.29" +version = "0.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libgit2-sys" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libz-sys" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -96,6 +425,111 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matches" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz-sys" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num_cpus" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl" +version = "0.9.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl-sys" +version = "0.9.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "percent-encoding" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pkg-config" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "psapi-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.3.15" @@ -106,34 +540,111 @@ name = "rand" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-demangle" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scoped-tls" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_ignored" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "shell-escape" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "socket2" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.6.0" @@ -165,6 +676,15 @@ dependencies = [ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tar" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempdir" version = "0.3.5" @@ -179,30 +699,55 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termcolor" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "textwrap" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "unicode-segmentation" -version = "1.2.0" +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -215,11 +760,44 @@ name = "unicode-xid" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "url" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vcpkg" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.2.8" @@ -230,34 +808,119 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.4" +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 = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] +"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" +"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" +"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0" +"checksum cargo 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e053e40f9e9ed856ca202a32898893a3f1173c4e4e8888de6c2affeb0f689628" +"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum clap 2.26.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7ab0425ad0840b5a452e5918f7e95acdf8398a3b5fa86d4e173e5bbef7f978ab" +"checksum cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8a6541a55bcd72d3de4faee2d101a5a66df29790282c7f797082a7228a9b3d" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" +"checksum crates-io 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "84b8ef70d98451b2d73bbbe50cb2b64c7a5765cad83ef3dec6ec943b96eac1c2" +"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" +"checksum curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7034c534a1d7d22f7971d6088aa9d281d219ef724026c3428092500f41ae9c2c" +"checksum curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d5481162dc4f424d088581db2f979fa7d4c238fe9794595de61d8d7522e277de" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" +"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" +"checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a" +"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" +"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" +"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" +"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423" +"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" +"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866" +"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" +"checksum git2 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1c0203d653f4140241da0c1375a404f0a397249ec818cd2076c6280c50f6fa" +"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" +"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" +"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum itoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ac17257442c2ed77dbc9fd555cf83c58b0c7f7d0e8f2ae08c0ac05c72842e1f6" +"checksum jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "443ae8bc0af6c106e6e8b77e04684faecc1a5ce94e058f4c2b0a037b0ea1b133" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" +"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" +"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" +"checksum libgit2-sys 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c00f6e5bc3fb2b5f87e75e8d0fd4ae6720d55f3ee23d389b7c6cae30f8db8db1" +"checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75" +"checksum libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd64ef8ee652185674455c1d450b83cbc8ad895625d543b5324d923f82e4d8" +"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" +"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" +"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" +"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" +"checksum openssl 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)" = "085aaedcc89a2fac1eb2bc19cd66f29d4ea99fec60f82a5f3a88a6be7dbd90b5" +"checksum openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98df0270d404ccd3c050a41d579c52d1db15375168bb3471e04ec0f5f378daf" +"checksum openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7e3a9845a4c9fdb321931868aae5549e96bb7b979bf9af7de03603d74691b5f3" +"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" +"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" -"checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" -"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" +"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" +"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" +"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" +"checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb6a7637a47663ee073391a139ed07851f27ed2532c2abc88c6bf27a16cdf34" +"checksum serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "812ff66056fd9a9a5b7c119714243b0862cf98340e7d4b5ee05a932c40d5ea6c" +"checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58" +"checksum serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c10e798e4405d7dcec3658989e35ee6706f730a9ed7c1184d5ebd84317e82f46" +"checksum serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d243424e06f9f9c39e3cd36147470fd340db785825e367625f79298a6ac6b7ac" +"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" +"checksum socket2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4daf80fcf54186fac4fe049e0b39d36a5cfde69a11a06413e61e77f553cccf9a" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum tabwriter 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3b7810162bc0a2eb2dc9a9bfd16ddb2d1f6022df3236d1478937bfadcb12385e" +"checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" -"checksum textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f728584ea33b0ad19318e20557cb0a39097751dbb07171419673502f848c7af6" -"checksum toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e5e16033aacf7eead46cbcb62d06cf9d1c2aa1b12faa4039072f7ae5921103b" -"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" +"checksum termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9065bced9c3e43453aa3d56f1e98590b8455b341d2fa191a1090c0dd0b242c75" +"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd" +"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" +"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a39ee4464208f6430992ff20154216ab2357772ac871d994c51628d60e58b8b0" +"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 index fed9043..49587ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,33 +1,29 @@ [package] -name = "cargo-outdated" -version = "0.4.0" authors = ["Kevin K. "] -exclude = ["*.png"] description = "Cargo subcommand for displaying when dependencies are out of date" -repository = "https://github.com/kbknapp/cargo-outdated.git" -readme = "README.md" -license = "MIT" +exclude = ["*.png"] keywords = ["cargo", "subcommand", "dependencies", "cargo-subcommand", "deps"] - +license = "MIT" +name = "cargo-outdated" +readme = "README.md" +repository = "https://github.com/kbknapp/cargo-outdated.git" +version = "0.4.0" [[bin]] name = "cargo-outdated" [dependencies] +cargo = "0.21.0" clap = "2.26.0" +env_logger = "0.4.3" +semver = "0.7.0" serde = "1.0.11" serde_derive = "1.0.11" -toml = "~0.4.3" tabwriter = "~1.0.3" tempdir = "~0.3.5" -ansi_term = {version = "0.9", optional = true} +toml = "~0.4.3" [features] -default = ["color"] -color = ["ansi_term"] debug = [] -nightly = [] -unstable = [] -travis = ["nightly"] - +default = [] [profile.release] lto = true diff --git a/README.md b/README.md index b58f546..374ffc0 100644 --- a/README.md +++ b/README.md @@ -15,19 +15,17 @@ Once installed (see below) running `cargo outdated` in a project directory looks ``` $ cargo outdated -Checking for SemVer compatible updates...Done -Checking for the latest updates...Done -The following dependencies have newer versions available: - - Name Project Ver SemVer Compat Latest Ver - regex->regex-syntax 0.2.1 0.2.2 0.2.2 - regex->memchr 0.1.5 0.1.6 0.1.6 - clap 1.2.3 1.2.5 1.4.7 - tabwriter 0.1.23 0.1.24 0.1.24 - clippy 0.0.11 0.0.22 0.0.22 - clap->ansi_term 0.6.3 -- 0.7.0 - regex->aho-corasick 0.3.0 0.3.4 0.4.0 - ansi_term 0.6.3 -- 0.7.0 +Name Project Compat Latest Kind Platform +clap 2.20.0 2.20.5 2.26.0 Normal --- +clap->bitflags 0.7.0 --- 0.9.1 Normal --- +clap->libc 0.2.18 0.2.29 Removed Normal --- +clap->term_size 0.2.1 0.2.3 0.3.0 Normal --- +clap->vec_map 0.6.0 --- 0.8.0 Normal --- +num_cpus 1.6.0 --- 1.6.2 Development --- +num_cpus->libc 0.2.18 0.2.29 0.2.29 Normal --- +pkg-config 0.3.8 0.3.9 0.3.9 Build --- +term 0.4.5 --- 0.4.6 Normal --- +term_size->libc 0.2.18 0.2.29 0.2.29 Normal cfg(not(target_os = "windows")) ``` ## Installing @@ -86,24 +84,29 @@ Otherwise, ensure you have the `cargo-outdated` binary in the directory which yo There are a few options for using `cargo-outdated` which should be somewhat self explanitory. ``` -cargo-outdated v0.3.0 -Displays information about project dependency versions - USAGE: cargo outdated [FLAGS] [OPTIONS] FLAGS: - -h, --help Prints help information - -R, --root-deps-only Only check root dependencies (Equivalent to --depth=1) - -V, --version Prints version information - -v, --verbose Print verbose output + --all-features Check outdated packages with all features enabled + -h, --help Prints help information + --no-default-features Do not include the `default` feature + -q, --quiet Coloring: auto, always, never + -R, --root-deps-only Only check root dependencies (Equivalent to --depth=1) + -V, --version Prints version information + -v, --verbose Use verbose output OPTIONS: - -d, --depth How deep in the dependency chain to search (Defaults to all dependencies when omitted) + --color Coloring: auto, always, never [default: auto] + [values: auto, always, never] + -d, --depth How deep in the dependency chain to search + (Defaults to all dependencies when omitted) --exit-code The exit code to return on new versions found [default: 0] - -l, --lockfile-path An absolute path to the Cargo.lock to use (Defaults to Cargo.lock in project root) - -m, --manifest-path An absolute path to the Cargo.toml file to use (Defaults to Cargo.toml in project root) - -p, --package ... Package to inspect for updates + --features Space-separated list of features + -m, --manifest-path An absolute path to the Cargo.toml file to use + (Defaults to Cargo.toml in project root) + -p, --packages ... Package to inspect for updates + -r, --root Package to treat as the root package ``` ## License diff --git a/src/cargo_files/dependency_tree.rs b/src/cargo_files/dependency_tree.rs deleted file mode 100644 index 47de45a..0000000 --- a/src/cargo_files/dependency_tree.rs +++ /dev/null @@ -1,221 +0,0 @@ -use std::cell::RefCell; -use std::rc::{Rc, Weak}; -use std::collections::HashMap; -use config::Config; -use super::lockfile::Lockfile; - -type PackageCell = RefCell; - -#[derive(Debug)] -pub struct Package { - pub name: String, - pub version: String, - pub dependencies: Option>>, -} - -impl Package { - pub fn new(name: &str, version: &str) -> Package { - Package { - name: name.to_owned(), - version: version.to_owned(), - dependencies: None, - } - } -} - -#[derive(Debug)] -pub struct DependencyTree { - pub root: Weak, - pub packages: HashMap>, -} - -impl DependencyTree { - pub fn from_lockfile( - lockfile: &mut Lockfile, - root: Option<&str>, - depth: i32, - ) -> DependencyTree { - lockfile - .package - .as_mut() - .unwrap() - .push(lockfile.root.clone()); - let root_package_nv = match root { - Some(r) => if r == lockfile.root.name { - format!("{} {}", r, lockfile.root.version) - } else { - Self::find_root(r, &lockfile.root.dependencies) - }, - None => lockfile.root.name.clone() + " " + &lockfile.root.version, - }; - - let packages = Rc::new(RefCell::new(HashMap::new())); - let root_package = Self::generate_tree(&root_package_nv, lockfile, packages.clone(), depth); - DependencyTree { - root: root_package, - packages: Rc::try_unwrap(packages).unwrap().into_inner(), - } - } - - pub fn print_list_to_vec( - tree_curr: &DependencyTree, - tree_comp: &DependencyTree, - tree_latest: &DependencyTree, - cfg: &Config, - ) -> Vec { - let mut lines = vec![]; - let root_curr = tree_curr.root.upgrade().unwrap(); - let root_comp = tree_comp.root.upgrade().unwrap(); - let root_latest = tree_latest.root.upgrade().unwrap(); - Self::print_list_to_vec_recursive( - root_curr, - Some(root_comp), - Some(root_latest), - "", - &mut lines, - true, - cfg, - ); - lines.sort(); - lines.dedup(); - lines - } - - fn print_list_to_vec_recursive( - curr: Rc, - comp: Option>, - latest: Option>, - parent: &str, - lines: &mut Vec, - curr_is_root: bool, - cfg: &Config, - ) { - if cfg.to_update.is_none() || - cfg.to_update - .as_ref() - .unwrap() - .contains(&curr.borrow().name.as_str()) - { - let name = if !(curr_is_root || parent.is_empty()) { - format!("{}->{}", parent, curr.borrow().name) - } else { - curr.borrow().name.clone() - }; - let updated_version = |updated: &Option>| -> Option { - match *updated { - Some(ref pac) if curr.borrow().version != pac.borrow().version => { - Some(pac.borrow().version.clone()) - } - Some(_) => None, - None => Some(" RM ".to_owned()), - } - }; - let comp_ver = updated_version(&comp); - let latest_ver = updated_version(&latest); - - if comp_ver.is_some() || latest_ver.is_some() { - lines.push(format!( - "{}\t {}\t {}\t {}\n", - name, - curr.borrow().version, - comp_ver.unwrap_or_else(|| " -- ".to_owned()), - latest_ver.unwrap_or_else(|| " -- ".to_owned()) - )); - } - } - - fn next_node(name: &str, next: &Option>) -> Option> { - match *next { - Some(ref pac) => if pac.borrow().dependencies.is_some() { - pac.borrow() - .dependencies - .as_ref() - .unwrap() - .get(name) - .map(|v| v.upgrade().unwrap()) - } else { - None - }, - None => None, - } - } - if let Some(ref deps) = curr.borrow().dependencies { - for next_curr in deps.values() { - let next_curr = next_curr.upgrade().unwrap(); - let next_comp = next_node(&next_curr.borrow().name, &comp); - let next_latest = next_node(&next_curr.borrow().name, &latest); - Self::print_list_to_vec_recursive( - next_curr, - next_comp, - next_latest, - &if curr_is_root { - "".to_owned() - } else { - curr.borrow().name.clone() - }, - lines, - false, - cfg, - ); - } - } - } - - fn find_root(root: &str, dependencies: &Option>) -> String { - if let Some(ref deps) = *dependencies { - for d in deps { - let splits_vec: Vec<_> = d.split(' ').collect(); - if splits_vec.len() > 1 && root == splits_vec[0] { - return format!("{} {}", root, splits_vec[1]); - } - } - } - panic!("Root is neither the package itself nor a direct dependency"); - } - - fn generate_tree( - root: &str, - lockfile: &Lockfile, - packages: Rc>>>, - depth: i32, - ) -> Weak { - if packages.borrow().contains_key(root) { - return Rc::downgrade(packages.borrow().get(root).unwrap()); - } - for raw_pac in lockfile.package.as_ref().unwrap() { - if root == raw_pac.name.clone() + " " + &raw_pac.version { - let mut package = Package::new(&raw_pac.name, &raw_pac.version); - if depth != 0 { - if let Some(ref deps) = raw_pac.dependencies { - package.dependencies = Some(HashMap::new()); - for d in deps { - let splits_vec: Vec<_> = d.split(' ').collect(); - if splits_vec.len() > 1 { - let next_pac = format!("{} {}", splits_vec[0], splits_vec[1]); - match package.dependencies.as_mut() { - Some(map) => { - let _ = map.insert( - splits_vec[0].to_string(), - Self::generate_tree( - &next_pac, - lockfile, - packages.clone(), - depth - 1, - ), - ); - } - _ => unreachable!(), - } - } - } - } - } - packages - .borrow_mut() - .insert(root.to_owned(), Rc::new(RefCell::new(package))); - return Rc::downgrade(packages.borrow().get(root).unwrap()); - } - } - panic!("Cannot find package {}", root); - } -} diff --git a/src/cargo_files/lockfile.rs b/src/cargo_files/lockfile.rs deleted file mode 100644 index ee19814..0000000 --- a/src/cargo_files/lockfile.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::io::Read; -use std::fs::File; -use std::path::Path; -use error::CliResult; - -#[derive(Debug, Deserialize, Clone)] -pub struct RawPackage { - pub name: String, - pub version: String, - pub dependencies: Option>, -} - -#[derive(Debug, Deserialize)] -pub struct Lockfile { - pub root: RawPackage, - pub package: Option>, -} - -impl Lockfile { - pub fn from_lockfile_path>(path: P) -> CliResult { - let mut lockfile = try!(File::open(path.as_ref())); - let mut lockfile_contents = String::new(); - let _ = try!(lockfile.read_to_string(&mut lockfile_contents)); - Ok(::toml::from_str(&lockfile_contents).expect(&format!( - "Cannot parse lockfile {}", - path.as_ref().to_str().unwrap() - ))) - } -} diff --git a/src/cargo_files/manifest.rs b/src/cargo_files/manifest.rs deleted file mode 100644 index 00dfb00..0000000 --- a/src/cargo_files/manifest.rs +++ /dev/null @@ -1,9 +0,0 @@ -use toml::value::Table; - -#[derive(Debug, Serialize, Deserialize)] -pub struct Manifest { - pub package: Table, - #[serde(serialize_with = "::toml::ser::tables_last")] - pub dependencies: Table, - pub bin: Option>, -} diff --git a/src/cargo_files/mod.rs b/src/cargo_files/mod.rs deleted file mode 100644 index 087a7fe..0000000 --- a/src/cargo_files/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod manifest; -mod lockfile; -mod dependency_tree; - -pub use self::manifest::Manifest; -pub use self::lockfile::Lockfile; -pub use self::dependency_tree::{DependencyTree, Package}; diff --git a/src/cargo_ops/elaborate_workspace.rs b/src/cargo_ops/elaborate_workspace.rs new file mode 100644 index 0000000..941ef00 --- /dev/null +++ b/src/cargo_ops/elaborate_workspace.rs @@ -0,0 +1,347 @@ +use std::io::{self, Write}; +use std::collections::{HashMap, HashSet}; + +use cargo::core::{Dependency, Package, PackageId, Workspace}; +use cargo::ops::{self, Packages}; +use cargo::util::{CargoError, CargoErrorKind, CargoResult, Config}; +use tabwriter::TabWriter; + +use super::Options; +use super::pkg_status::*; + +/// An elaborate workspace containing resolved dependencies and +/// the update status of packages +pub struct ElaborateWorkspace<'ela> { + /// Package which is treated as the root of the dependency tree + pub root: PackageId, + pub workspace: &'ela Workspace<'ela>, + pub pkgs: HashMap, + pub pkg_deps: HashMap>, + /// Map of package status + /// + /// Since the grandparent may specify desired features of parent, + /// which influence the status of current, a tuple of + /// `(grand, parent, current)` should be used as the unique id + pub pkg_status: HashMap<(Option, Option, PackageId), PkgStatus>, +} + +impl<'ela> ElaborateWorkspace<'ela> { + /// Elaborate a `Workspace` + pub fn from_workspace( + workspace: &'ela Workspace, + options: &Options, + ) -> CargoResult> { + let specs = Packages::All.into_package_id_specs(workspace)?; + let (packages, resolve) = ops::resolve_ws_precisely( + workspace, + None, + &options.flag_features, + options.flag_all_features, + options.flag_no_default_features, + &specs, + )?; + let mut pkgs = HashMap::new(); + let mut pkg_deps = HashMap::new(); + for pkg_id in packages.package_ids() { + let pkg = packages.get(pkg_id)?; + pkgs.insert(pkg_id.clone(), pkg.clone()); + let deps = pkg.dependencies(); + let mut dep_map = HashMap::new(); + for dep_id in resolve.deps(pkg_id) { + for d in deps { + if d.matches_id(dep_id) { + dep_map.insert(dep_id.clone(), d.clone()); + break; + } + } + } + pkg_deps.insert(pkg_id.clone(), dep_map); + } + + let root = { + let determine_root = || if let Some(ref root_name) = options.flag_root { + let workspace_root = workspace.current()?; + if root_name == workspace_root.name() { + Ok(workspace_root.package_id().clone()) + } else { + for direct_dep in pkg_deps[workspace_root.package_id()].keys() { + if pkgs[direct_dep].name() == root_name { + return Ok(direct_dep.clone()); + } + } + return Err(CargoError::from_kind(CargoErrorKind::Msg( + "Root is neither the workspace root nor a direct dependency".to_owned(), + ))); + } + } else { + Ok(workspace.current()?.package_id().clone()) + }; + + determine_root()? + }; + + Ok(ElaborateWorkspace { + root: root, + workspace: workspace, + pkgs: pkgs, + pkg_deps: pkg_deps, + pkg_status: HashMap::new(), + }) + } + + /// Resolve compatible and latest status from the corresponding `ElaborateWorkspace`s + pub fn resolve_status( + &mut self, + compat: &ElaborateWorkspace, + latest: &ElaborateWorkspace, + options: &Options, + config: &Config, + ) -> CargoResult<()> { + let root_parent = if &self.root == self.workspace.current()?.package_id() { + None + } else { + Some(self.workspace.current()?.package_id()) + }; + let root_id = self.root.clone(); + self.resolve_status_recursive( + None, + root_parent, + &root_id, + Some(&compat.root), + compat, + Some(&latest.root), + latest, + options.flag_depth, + config, + ) + } + + #[allow(unknown_lints)] + #[allow(too_many_arguments)] + fn resolve_status_recursive( + &mut self, + grand: Option<&PackageId>, + parent: Option<&PackageId>, + self_pkg: &PackageId, + compat_pkg: Option<&PackageId>, + compat: &ElaborateWorkspace, + latest_pkg: Option<&PackageId>, + latest: &ElaborateWorkspace, + depth: i32, + config: &Config, + ) -> CargoResult<()> { + let pkg_status_key = (grand.cloned(), parent.cloned(), self_pkg.clone()); + if self.pkg_status.contains_key(&pkg_status_key) { + return Ok(()); + } + let self_pkg = self.pkgs.get(self_pkg).cloned().unwrap(); + let pkg_status = PkgStatus { + compat: Status::from_versions( + self_pkg.version(), + compat_pkg + .and_then(|id| compat.pkgs.get(id)) + .map(|p| p.version()), + ), + latest: Status::from_versions( + self_pkg.version(), + latest_pkg + .and_then(|id| latest.pkgs.get(id)) + .map(|p| p.version()), + ), + }; + debug!( + config, + "UPDATE, self: {:?}, key: {:?}, status: {:?}\n", + self_pkg.package_id(), + pkg_status_key, + pkg_status + ); + self.pkg_status.insert(pkg_status_key, pkg_status); + + if depth == 0 { + return Ok(()); + } + + debug!( + config, + "LOOP, parent: {:?}, self: {:?}, compat: {:?}, latest: {:?}\n", + parent, + self_pkg.package_id(), + compat_pkg, + latest_pkg + ); + + let self_deps: Vec<_> = self.pkg_deps[self_pkg.package_id()] + .keys() + .cloned() + .collect(); + for next_self in self_deps { + let next_name = self.pkgs[&next_self].name().to_owned(); + let next_compat = compat_pkg.and_then(|id| compat.pkg_deps.get(id)).and_then( + |dep_map| { + for dep_id in dep_map.keys() { + let dep_name = compat.pkgs[dep_id].name(); + if dep_name == next_name { + return Some(dep_id); + } + } + None + }, + ); + let next_latest = latest_pkg.and_then(|id| latest.pkg_deps.get(id)).and_then( + |dep_map| { + for dep_id in dep_map.keys() { + let dep_name = latest.pkgs[dep_id].name(); + if dep_name == next_name { + return Some(dep_id); + } + } + None + }, + ); + debug!( + config, + "NEXT, next_self: {:?}, next_compat: {:?}, next_latest: {:?}\n", + next_self, + next_compat, + next_latest + ); + self.resolve_status_recursive( + parent, + Some(self_pkg.package_id()), + &next_self, + next_compat, + compat, + next_latest, + latest, + depth - 1, + config, + )?; + } + + Ok(()) + } + + /// Print package status to `TabWriter` + pub fn print_list(&self, options: &Options, config: &Config) -> CargoResult { + verbose!(config, "Printing...", "list format"); + let mut lines = vec![]; + let root_parent = if &self.root == self.workspace.current()?.package_id() { + None + } else { + Some(self.workspace.current()?.package_id()) + }; + { + let mut printed = HashSet::new(); + self.print_list_recursive( + options, + None, + root_parent, + &self.root, + options.flag_depth, + &mut lines, + &mut printed, + )?; + } + lines.sort(); + lines.dedup(); + let lines_len = lines.len(); + + verbose!(config, "Printing...", "with tab writer"); + if lines.is_empty() { + println!("All dependencies are up to date, yay!"); + } else { + let mut tw = TabWriter::new(vec![]); + write!(&mut tw, "Name\tProject\tCompat\tLatest\tKind\tPlatform\n")?; + for line in lines { + write!(&mut tw, "{}", line)?; + } + tw.flush()?; + write!( + io::stdout(), + "{}", + String::from_utf8(tw.into_inner().unwrap()).unwrap() + )?; + io::stdout().flush()?; + } + + Ok(lines_len as i32) + } + + #[allow(unknown_lints)] + #[allow(too_many_arguments)] + fn print_list_recursive( + &self, + options: &Options, + grand: Option<&PackageId>, + parent: Option<&PackageId>, + pkg_id: &PackageId, + depth: i32, + lines: &mut Vec, + printed: &mut HashSet<(Option, Option, PackageId)>, + ) -> CargoResult<()> { + let pkg_status_key = (grand.cloned(), parent.cloned(), pkg_id.clone()); + if printed.contains(&pkg_status_key) { + return Ok(()); + } + printed.insert(pkg_status_key.clone()); + + let pkg = &self.pkgs[pkg_id]; + let pkg_status = &self.pkg_status[&pkg_status_key]; + + if (pkg_status.compat.is_changed() || pkg_status.latest.is_changed()) && + (options.flag_packages.is_empty() || + options.flag_packages.contains(&pkg.name().to_string())) + { + // name version compatible latest kind platform + if let Some(parent) = parent { + let dependency = &self.pkg_deps[parent][pkg_id]; + let label = if parent == self.workspace.current()?.package_id() { + pkg.name().to_owned() + } else { + format!("{}->{}", self.pkgs[parent].name(), pkg.name()) + }; + let line = format!( + "{}\t{}\t{}\t{}\t{:?}\t{}\n", + label, + pkg.version(), + pkg_status.compat.to_string(), + pkg_status.latest.to_string(), + dependency.kind(), + dependency + .platform() + .map(|p| p.to_string()) + .unwrap_or_else(|| "---".to_owned()) + ); + lines.push(line); + } else { + let line = format!( + "{}\t{}\t{}\t{}\t---\t---\n", + pkg.name(), + pkg.version(), + pkg_status.compat.to_string(), + pkg_status.latest.to_string() + ); + lines.push(line); + } + } + + if depth == 0 { + return Ok(()); + } + + for dep in self.pkg_deps[pkg_id].keys() { + self.print_list_recursive( + options, + parent, + Some(pkg_id), + dep, + depth - 1, + lines, + printed, + )?; + } + + Ok(()) + } +} diff --git a/src/cargo_ops/mod.rs b/src/cargo_ops/mod.rs index 1ea51ae..f1ecc06 100644 --- a/src/cargo_ops/mod.rs +++ b/src/cargo_ops/mod.rs @@ -1,140 +1,40 @@ -use std::path::{Path, PathBuf}; -use std::fs::{self, File}; -use std::io::{self, Read, Write}; -use std::process; -use std::error::Error; - -use tempdir::TempDir; -use toml::Value; -use toml::value::Table; - -use error::{CliError, CliResult}; -use cargo_files::Manifest; - -#[derive(Debug)] -pub struct TempProject { - pub manifest: PathBuf, - pub lockfile: PathBuf, - parsed_manifest: Manifest, - temp_dir: TempDir, +use toml::value::{Table, Value}; +use super::Options; + +mod pkg_status; +mod temp_project; +mod elaborate_workspace; +pub use self::pkg_status::*; +pub use self::temp_project::TempProject; +pub use self::elaborate_workspace::ElaborateWorkspace; + +/// A continent struct for quick parsing and manipulating manifest +#[derive(Debug, Serialize, Deserialize)] +struct Manifest { + pub package: Value, + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "opt_tables_last")] + pub dependencies: Option, + #[serde(rename = "dev-dependencies", skip_serializing_if = "Option::is_none", + serialize_with = "opt_tables_last")] + pub dev_dependencies: Option
, + #[serde(rename = "build-dependencies", skip_serializing_if = "Option::is_none", + serialize_with = "opt_tables_last")] + pub build_dependencies: Option
, + pub lib: Option
, + pub bin: Option>, + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "opt_tables_last")] + pub workspace: Option
, + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "opt_tables_last")] + pub target: Option
, + pub features: Option, } -impl TempProject { - pub fn new>(orig_manifest: P, orig_lockfile: P) -> CliResult { - let temp_dir = try!(TempDir::new("cargo-outdated")); - let manifest = temp_dir.path().join("Cargo.toml"); - let lockfile = temp_dir.path().join("Cargo.lock"); - - let mut buf = String::new(); - let mut orig_manifest_file = try!(File::open(&orig_manifest)); - try!(orig_manifest_file.read_to_string(&mut buf)); - let parsed_manifest: Manifest = ::toml::from_str(&buf).expect("Cannot parse Cargo.toml"); - try!(fs::copy(&orig_lockfile, &lockfile)); - - Ok(TempProject { - manifest: manifest, - lockfile: lockfile, - parsed_manifest: parsed_manifest, - temp_dir: temp_dir, - }) - } - - pub fn cargo_update(&self) -> CliResult<()> { - if let Err(e) = process::Command::new("cargo") - .arg("update") - .arg("--manifest-path") - .arg( - self.manifest - .to_str() - .expect("failed to convert temp Cargo.toml path to string"), - ) - .output() - .and_then(|v| if v.status.success() { - Ok(v) - } else { - Err(io::Error::new( - io::ErrorKind::Other, - "did not exit successfully", - )) - }) { - return Err(CliError::Generic(format!( - "Failed to run 'cargo update' with error '{}'", - e.description() - ))); - } - Ok(()) - } - - fn write_manifest(&self, contents: &Manifest) -> CliResult<()> { - let mut file = try!(File::create(&self.manifest)); - let serialized = ::toml::to_string(contents).expect("Failed to serialized Cargo.toml"); - try!(write!(file, "{}", serialized)); - Ok(()) - } - - pub fn write_manifest_semver(&self) -> CliResult<()> { - let name = self.parsed_manifest - .package - .get("name") - .expect("Cannot find package name in Cargo.toml"); - let version = self.parsed_manifest - .package - .get("version") - .expect("Cannot find package version in Cargo.toml"); - let mut package = Table::new(); - package.insert("name".to_owned(), name.clone()); - package.insert("version".to_owned(), version.clone()); - let mut bin = Table::new(); - bin.insert("name".to_owned(), Value::String("test".to_owned())); - bin.insert("path".to_owned(), Value::String("test.rs".to_owned())); - - let manifest_semver = Manifest { - package: package, - dependencies: self.parsed_manifest.dependencies.clone(), - bin: Some(vec![bin]), - }; - try!(self.write_manifest(&manifest_semver)); - - Ok(()) - } - - pub fn write_manifest_latest(&self) -> CliResult<()> { - let name = self.parsed_manifest - .package - .get("name") - .expect("Cannot find package name in Cargo.toml"); - let version = self.parsed_manifest - .package - .get("version") - .expect("Cannot find package version in Cargo.toml"); - let mut package = Table::new(); - package.insert("name".to_owned(), name.clone()); - package.insert("version".to_owned(), version.clone()); - let mut dependencies = Table::new(); - for (dep_name, dep_pac) in &self.parsed_manifest.dependencies { - match *dep_pac { - Value::Table(ref t) => { - let mut t = t.clone(); - t.insert("version".to_owned(), Value::String("*".to_owned())); - let _ = dependencies.insert(dep_name.clone(), Value::Table(t)); - } - Value::String(_) => { - let _ = dependencies.insert(dep_name.clone(), Value::String("*".to_owned())); - } - _ => unreachable!(), - } - } - let mut bin = Table::new(); - bin.insert("name".to_owned(), Value::String("test".to_owned())); - bin.insert("path".to_owned(), Value::String("test.rs".to_owned())); - - let manifest_semver = Manifest { - package: package, - dependencies: dependencies, - bin: Some(vec![bin]), - }; - try!(self.write_manifest(&manifest_semver)); - - Ok(()) +pub fn opt_tables_last(data: &Option
, serializer: S) -> Result +where + S: ::serde::ser::Serializer, +{ + match *data { + Some(ref d) => ::toml::ser::tables_last(d, serializer), + None => unreachable!(), } } diff --git a/src/cargo_ops/pkg_status.rs b/src/cargo_ops/pkg_status.rs new file mode 100644 index 0000000..4df5c9e --- /dev/null +++ b/src/cargo_ops/pkg_status.rs @@ -0,0 +1,45 @@ +use semver::Version; + +#[derive(Debug)] +pub enum Status { + Unchanged, + Removed, + Version(Version), +} + +impl Status { + pub fn from_versions(from: &Version, to: Option<&Version>) -> Status { + if let Some(to) = to { + if from == to { + Status::Unchanged + } else { + Status::Version(to.clone()) + } + } else { + Status::Removed + } + } + + pub fn is_changed(&self) -> bool { + match *self { + Status::Unchanged => false, + _ => true, + } + } +} + +impl ::std::string::ToString for Status { + fn to_string(&self) -> String { + match *self { + Status::Unchanged => "---".to_owned(), + Status::Removed => "Removed".to_owned(), + Status::Version(ref v) => v.to_string(), + } + } +} + +#[derive(Debug)] +pub struct PkgStatus { + pub compat: Status, + pub latest: Status, +} diff --git a/src/cargo_ops/temp_project.rs b/src/cargo_ops/temp_project.rs new file mode 100644 index 0000000..d89691c --- /dev/null +++ b/src/cargo_ops/temp_project.rs @@ -0,0 +1,384 @@ +use std::path::{Path, PathBuf}; +use std::fs::{self, File}; +use std::io::{Read, Write}; +use std::collections::HashSet; +use std::env; +use std::rc::Rc; +use std::cell::RefCell; + +use tempdir::TempDir; +use toml::Value; +use toml::value::Table; +use cargo::util::errors::CargoResultExt; +use cargo::core::{PackageId, Workspace}; +use cargo::util::{CargoError, CargoErrorKind, CargoResult, Config}; +use cargo::ops::{update_lockfile, UpdateOptions}; + +use Options; +use super::{ElaborateWorkspace, Manifest}; + +/// A temporary project +pub struct TempProject<'tmp> { + pub workspace: Rc>>>, + pub temp_dir: TempDir, + manifest_paths: Vec, + config: Config, + relative_manifest: String, +} + +impl<'tmp> TempProject<'tmp> { + /// Copy needed manifest and lock files from an existing workspace + pub fn from_workspace( + orig_workspace: &ElaborateWorkspace, + orig_manifest: &str, + options: &Options, + ) -> CargoResult> { + // e.g. /path/to/project + let workspace_root = orig_workspace.workspace.root().to_str().ok_or_else(|| { + CargoError::from_kind(CargoErrorKind::Msg(format!( + "Invalid character found in path {}", + orig_workspace.workspace.root().to_string_lossy() + ))) + })?; + + let temp_dir = TempDir::new("cargo-outdated")?; + let manifest_paths = manifest_paths(orig_workspace)?; + let mut tmp_manifest_paths = vec![]; + for from in &manifest_paths { + // e.g. /path/to/project/src/sub + let mut from_dir = from.clone(); + from_dir.pop(); + let from_dir = from_dir.to_string_lossy(); + // e.g. /tmp/cargo.xxx/src/sub + let mut dest = PathBuf::from(format!( + "{}/{}", + temp_dir.path().to_string_lossy(), + &from_dir[workspace_root.len()..] + )); + fs::create_dir_all(&dest)?; + // e.g. /tmp/cargo.xxx/src/sub/Cargo.toml + dest.push("Cargo.toml"); + tmp_manifest_paths.push(dest.clone()); + fs::copy(from, &dest)?; + let lockfile = PathBuf::from(format!("{}/Cargo.lock", from_dir)); + if lockfile.is_file() { + dest.pop(); + dest.push("Cargo.lock"); + fs::copy(lockfile, dest)?; + } + } + Self::write_manifest_semver_with_paths( + &tmp_manifest_paths, + workspace_root, + &temp_dir.path().to_string_lossy(), + )?; + + // virtual root + let mut virtual_root = PathBuf::from(format!("{}/Cargo.toml", workspace_root)); + if !manifest_paths.contains(&virtual_root) && virtual_root.is_file() { + fs::copy( + &virtual_root, + format!("{}/Cargo.toml", temp_dir.path().to_string_lossy()), + )?; + virtual_root.pop(); + virtual_root.push("Cargo.lock"); + if virtual_root.is_file() { + fs::copy( + &virtual_root, + format!("{}/Cargo.lock", temp_dir.path().to_string_lossy()), + )?; + } + } + + let relative_manifest = String::from( + &orig_manifest[orig_workspace.workspace.root().to_string_lossy().len()..], + ); + let config = Self::generate_config( + &temp_dir.path().to_string_lossy(), + &relative_manifest, + options, + )?; + Ok(TempProject { + // workspace: Workspace::new(Path::new(&root_manifest), config)?, + workspace: Rc::new(RefCell::new(None)), + temp_dir: temp_dir, + manifest_paths: tmp_manifest_paths, + config: config, + relative_manifest: relative_manifest, + }) + } + + fn generate_config( + root: &str, + relative_manifest: &str, + options: &Options, + ) -> CargoResult { + let shell = ::cargo::core::Shell::new(); + let cwd = env::current_dir() + .chain_err(|| "Cargo couldn't get the current directory of the process")?; + + let homedir = ::cargo::util::homedir(&cwd).ok_or_else(|| { + "Cargo couldn't find your home directory. \ + This probably means that $HOME was not set." + })?; + let mut cwd = PathBuf::from(format!("{}/{}", root, relative_manifest)); + cwd.pop(); + let config = Config::new(shell, cwd, homedir); + config.configure( + 0, + if options.flag_verbose > 0 { + None + } else { + Some(true) + }, + &options.flag_color, + options.flag_frozen, + options.flag_locked, + )?; + Ok(config) + } + + /// Run `cargo update` against the temporary project + pub fn cargo_update(&self) -> CargoResult<()> { + let update_opts = UpdateOptions { + aggressive: false, + precise: None, + to_update: &[], + config: &self.config, + }; + update_lockfile(self.workspace.borrow().as_ref().unwrap(), &update_opts)?; + Ok(()) + } + + fn write_manifest>(manifest: &Manifest, path: P) -> CargoResult<()> { + let mut file = try!(File::create(path)); + let serialized = ::toml::to_string(manifest).expect("Failed to serialized Cargo.toml"); + try!(write!(file, "{}", serialized)); + Ok(()) + } + + fn manipulate_dependencies(manifest: &mut Manifest, f: &Fn(&mut Table)) { + manifest.dependencies.as_mut().map(f); + manifest.dev_dependencies.as_mut().map(f); + manifest.build_dependencies.as_mut().map(f); + manifest + .target + .as_mut() + .map(|ref mut t| for target in t.values_mut() { + if let Value::Table(ref mut target) = *target { + for dependency_tables in + &["dependencies", "dev-dependencies", "build-dependencies"] + { + target.get_mut(*dependency_tables).map(|dep_table| { + if let Value::Table(ref mut dep_table) = *dep_table { + f(dep_table); + } + }); + } + } + }); + } + + /// Write manifests with SemVer requirements + pub fn write_manifest_semver(&'tmp self) -> CargoResult<()> { + let root_manifest = format!( + "{}/{}", + self.temp_dir.path().to_string_lossy(), + self.relative_manifest + ); + *self.workspace.borrow_mut() = + Some(Workspace::new(Path::new(&root_manifest), &self.config)?); + Ok(()) + } + + fn write_manifest_semver_with_paths>( + manifest_paths: &[PathBuf], + orig_root: P, + tmp_root: P, + ) -> CargoResult<()> { + let bin = { + let mut bin = Table::new(); + bin.insert("name".to_owned(), Value::String("test".to_owned())); + bin.insert("path".to_owned(), Value::String("test.rs".to_owned())); + bin + }; + for manifest_path in manifest_paths { + let mut manifest: Manifest = { + let mut buf = String::new(); + let mut file = File::open(manifest_path)?; + file.read_to_string(&mut buf)?; + ::toml::from_str(&buf)? + }; + manifest.bin = Some(vec![bin.clone()]); + // provide lib.path + manifest.lib.as_mut().map(|lib| { + lib.insert("path".to_owned(), Value::String("test_lib.rs".to_owned())); + }); + Self::manipulate_dependencies(&mut manifest, &|deps| { + Self::replace_path_with_absolute( + deps, + orig_root.as_ref(), + tmp_root.as_ref(), + manifest_path, + ) + }); + Self::write_manifest(&manifest, manifest_path)?; + } + + Ok(()) + } + + /// Write manifests with wildcard requirements + pub fn write_manifest_latest(&'tmp self) -> CargoResult<()> { + let bin = { + let mut bin = Table::new(); + bin.insert("name".to_owned(), Value::String("test".to_owned())); + bin.insert("path".to_owned(), Value::String("test.rs".to_owned())); + bin + }; + for manifest_path in &self.manifest_paths { + let mut manifest: Manifest = { + let mut buf = String::new(); + let mut file = File::open(manifest_path)?; + file.read_to_string(&mut buf)?; + ::toml::from_str(&buf)? + }; + manifest.bin = Some(vec![bin.clone()]); + // provide lib.path + manifest.lib.as_mut().map(|lib| { + lib.insert("path".to_owned(), Value::String("test_lib.rs".to_owned())); + }); + Self::manipulate_dependencies(&mut manifest, &Self::replace_version_with_wildcard); + Self::write_manifest(&manifest, manifest_path)?; + } + + let root_manifest = format!( + "{}/{}", + self.temp_dir.path().to_string_lossy(), + self.relative_manifest + ); + *self.workspace.borrow_mut() = + Some(Workspace::new(Path::new(&root_manifest), &self.config)?); + Ok(()) + } + + fn replace_version_with_wildcard(dependencies: &mut Table) { + let dep_names: Vec<_> = dependencies.keys().cloned().collect(); + for name in dep_names { + let original = dependencies.get(&name).cloned().unwrap(); + match original { + Value::String(_) => { + dependencies.insert(name, Value::String("*".to_owned())); + } + Value::Table(ref t) => { + if t.contains_key("path") { + continue; + } + let mut replaced = t.clone(); + if replaced.contains_key("version") { + replaced.insert("version".to_owned(), Value::String("*".to_owned())); + } + dependencies.insert(name, Value::Table(replaced)); + } + _ => panic!("Dependency spec is neither a string nor a table {}", name), + } + } + } + + fn replace_path_with_absolute( + dependencies: &mut Table, + orig_root: &Path, + tmp_root: &Path, + tmp_manifest: &Path, + ) { + let dep_names: Vec<_> = dependencies.keys().cloned().collect(); + for name in dep_names { + let original = dependencies.get(&name).cloned().unwrap(); + match original { + Value::Table(ref t) if t.contains_key("path") => { + if let Value::String(ref orig_path) = t["path"] { + let orig_path = Path::new(orig_path); + if orig_path.is_relative() { + let relative = { + let delimiter: &[_] = &['/', '\\']; + let relative = &tmp_manifest.to_string_lossy() + [tmp_root.to_string_lossy().len()..]; + let mut relative = + PathBuf::from(relative.trim_left_matches(delimiter)); + relative.pop(); + relative.join(orig_path) + }; + if !tmp_root.join(&relative).join("Cargo.toml").exists() { + let mut replaced = t.clone(); + replaced.insert( + "path".to_owned(), + Value::String( + fs::canonicalize(orig_root.join(relative)) + .unwrap() + .to_string_lossy() + .to_string(), + ), + ); + dependencies.insert(name, Value::Table(replaced)); + } + } + } + } + _ => {} + } + } + } +} + +fn manifest_paths(elab: &ElaborateWorkspace) -> CargoResult> { + let mut visited: HashSet = HashSet::new(); + let mut manifest_paths = vec![]; + let workspace_members: HashSet<_> = elab.workspace + .members() + .map(|pkg| pkg.package_id()) + .collect(); + for member in &workspace_members { + manifest_paths.push(elab.pkgs[member].manifest_path().to_owned()); + } + let root_pkg = elab.workspace.current()?.package_id(); + // e.g. /path/to/project + let workspace_path = elab.workspace.current()?.root().to_string_lossy(); + + fn manifest_paths_recursive( + pkg_id: &PackageId, + elab: &ElaborateWorkspace, + workspace_path: &str, + members: &HashSet<&PackageId>, + visited: &mut HashSet, + manifest_paths: &mut Vec, + ) -> CargoResult<()> { + if visited.contains(pkg_id) { + return Ok(()); + } + visited.insert(pkg_id.clone()); + if !members.contains(pkg_id) { + let pkg = &elab.pkgs[pkg_id]; + let pkg_path = pkg.root().to_string_lossy(); + if pkg_path.starts_with(workspace_path) { + manifest_paths.push(pkg.manifest_path().to_owned()); + } + } + + for dep in elab.pkg_deps[pkg_id].keys() { + manifest_paths_recursive(dep, elab, workspace_path, members, visited, manifest_paths)?; + } + + Ok(()) + }; + manifest_paths_recursive( + root_pkg, + elab, + &workspace_path, + &workspace_members, + &mut visited, + &mut manifest_paths, + )?; + + + Ok(manifest_paths) +} diff --git a/src/config.rs b/src/config.rs deleted file mode 100644 index 109430a..0000000 --- a/src/config.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::path::PathBuf; - -use clap::ArgMatches; - -use fmt::Format; -use util; -use error::CliResult; - -#[derive(Debug)] -pub struct Config<'tu> { - pub to_update: Option>, - pub root: Option<&'tu str>, - pub depth: i32, - pub verbose: bool, - pub exit_code: i32, - pub manifest: PathBuf, - pub lockfile: PathBuf, -} - -impl<'tu> Config<'tu> { - pub fn from_matches(m: &'tu ArgMatches) -> CliResult { - debugln!("Config:from_matches"); - let depth = match m.value_of("depth") { - Some(d_str) => { - match d_str.parse::() { - Ok(num) => num, - Err(..) => { - wlnerr!("{} Couldn't parse '{}' as a valid depth (Valid depths are 0 (infinite) to ~4,000,000,000)", - Format::Error("error:"), - d_str); - ::std::process::exit(1); - } - } - } - None => if m.is_present("root-deps-only") { 1 } else { -1 }, - }; - - let cfg = Config { - to_update: m.values_of("package").map(|v| v.collect()), - root: m.value_of("root"), - depth: depth, - verbose: m.is_present("verbose"), - exit_code: { - debugln!("Config:from_matches:exit-code={:?}", m.value_of("exit-code")); - value_t!(m, "exit-code", i32).unwrap_or(0) - }, - manifest: try!(util::find_file(m.value_of("manifest-path").unwrap_or("Cargo.toml"), m.is_present("manifest-path"))), - lockfile: try!(util::find_file(m.value_of("lockfile-path").unwrap_or("Cargo.lock"), m.is_present("lockfile-path"))), - }; - debugln!("Config:from_matches:cfg={:#?}", cfg); - Ok(cfg) - } -} diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index db09449..0000000 --- a/src/error.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::error::Error; -use std::fmt::{Display, Formatter}; -use std::fmt::Result as FmtResult; -use std::io; - -use fmt::Format; - -/// Convenience type to return a result or a `CliError` -pub type CliResult = Result; - -#[derive(Debug)] -#[allow(dead_code)] -pub enum CliError { - Generic(String), - FileOpen(String), - TomlTableRoot, - NoRootDeps, - NoNonRootDeps, - Unknown, - Io(String), -} - -// Copies clog::error::Error; -impl CliError { - /// Return whether this was a fatal error or not. - #[allow(dead_code)] - pub fn is_fatal(&self) -> bool { - // For now all errors are fatal - true - } - - /// Print this error and immediately exit the program. - /// - /// If the error is non-fatal then the error is printed to stdout and the - /// exit status will be `0`. Otherwise, when the error is fatal, the error - /// is printed to stderr and the exit status will be `1`. - pub fn exit(&self) -> ! { - if self.is_fatal() { - wlnerr!("{}", self); - ::std::process::exit(1) - } else { - println!("{}", self); - ::std::process::exit(0) - } - } -} - -impl Display for CliError { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - write!(f, "{} {}", Format::Error("error:"), self.description()) - } -} - -impl Error for CliError { - #[cfg_attr(feature = "lints", allow(match_same_arms))] - fn description(&self) -> &str { - match *self { - CliError::Generic(ref d) | CliError::FileOpen(ref d) | CliError::Io(ref d) => &*d, - CliError::TomlTableRoot => "couldn't find '[root]' table in Cargo.lock", - CliError::NoRootDeps => "No root dependencies", - CliError::NoNonRootDeps => "No non root dependencies", - CliError::Unknown => { - "An unknown fatal error has occurred, please consider filing a bug-report!" - } - } - } - - fn cause(&self) -> Option<&Error> { None } -} - -impl From for CliError { - fn from(e: io::Error) -> Self { CliError::Io(e.description().to_string()) } -} diff --git a/src/fmt.rs b/src/fmt.rs deleted file mode 100644 index 5d3b4ae..0000000 --- a/src/fmt.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::fmt; - -#[cfg(all(feature = "color", not(target_os = "windows")))] -use ansi_term::Colour::{Green, Red, Yellow}; -#[cfg(all(feature = "color", not(target_os = "windows")))] -use ansi_term::ANSIString; - -#[allow(dead_code)] -pub enum Format { - Error(T), - Warning(T), - Good(T), -} - -#[cfg(all(feature = "color", not(target_os = "windows")))] -impl> Format { - fn format(&self) -> ANSIString { - match *self { - Format::Error(ref e) => Red.bold().paint(e.as_ref()), - Format::Warning(ref e) => Yellow.paint(e.as_ref()), - Format::Good(ref e) => Green.paint(e.as_ref()), - } - } -} - -#[cfg(all(feature = "color", not(target_os = "windows")))] -impl> fmt::Display for Format { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) } -} - -#[cfg(any(not(feature = "color"), target_os = "windows"))] -impl Format { - fn format(&self) -> &T { - match *self { - Format::Error(ref e) => e, - Format::Warning(ref e) => e, - Format::Good(ref e) => e, - } - } -} - -#[cfg(any(not(feature = "color"), target_os = "windows"))] -impl fmt::Display for Format { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) } -} diff --git a/src/macros.rs b/src/macros.rs index 0fe371b..ffafe03 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,57 +1,25 @@ -macro_rules! wlnerr( - ($($arg:tt)*) => ({ - use std::io::{Write, stderr}; - writeln!(&mut stderr(), $($arg)*).ok(); - }) -); - -#[allow(unused_macros)] -macro_rules! werr( - ($($arg:tt)*) => ({ - use std::io::{Write, stderr}; - write!(&mut stderr(), $($arg)*).ok(); - }) -); - -macro_rules! verbose( - ($cfg:ident, $($arg:tt)*) => ({ - if $cfg.verbose { - use std::io::{Write, stdout}; - write!(&mut stdout(), $($arg)*).ok(); - } - }) -); - -macro_rules! verboseln( - ($cfg:ident, $($arg:tt)*) => ({ - if $cfg.verbose { - use std::io::{Write, stdout}; - writeln!(&mut stdout(), $($arg)*).ok(); - } - }) -); - -#[cfg(feature = "debug")] -macro_rules! debugln { - ($fmt:expr) => (println!(concat!("*DEBUG:cargo-outdated:", $fmt))); - ($fmt:expr, $($arg:tt)*) => (println!(concat!("*DEBUG:cargo-outdated:",$fmt), $($arg)*)); +macro_rules! verbose { + ($config: expr, $status: expr, $message: expr) => ( + $config + .shell() + .verbose( + |sh| -> CargoResult<()> { sh.status($status, $message) }, + )? + ) } #[cfg(feature = "debug")] macro_rules! debug { - ($fmt:expr) => (print!(concat!("*DEBUG:cargo-outdated:", $fmt))); - ($fmt:expr, $($arg:tt)*) => (println!(concat!("*DEBUG:cargo-outdated:",$fmt), $($arg)*)); -} - -#[cfg(not(feature = "debug"))] -macro_rules! debugln { - ($fmt:expr) => (); - ($fmt:expr, $($arg:tt)*) => (); + ($config: expr, $message: expr) => ( + $config.shell().say($message, ::term::color::WHITE)? + ); + ($config: expr, $($arg: tt)*) => ( + $config.shell().say(format!($($arg)*), ::term::color::WHITE)? + ); } -#[allow(unused_macros)] #[cfg(not(feature = "debug"))] macro_rules! debug { - ($fmt:expr) => (); - ($fmt:expr, $($arg:tt)*) => (); + ($config: expr, $message: expr) => (); + ($config: expr, $($arg: tt)*) => (); } diff --git a/src/main.rs b/src/main.rs index 4872a28..3617748 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,255 +1,303 @@ -//! A cargo subcommand for checking the latest version on crates.io of a particular dependency -//! -//! ## About -//! -//! `cargo-outdated` is a very early proof-of-concept for displaying when dependencies have newer versions available. -//! -//! ## Compiling -//! -//! Follow these instructions to compile `cargo-outdated`, then skip down to Installation. -//! -//! 1. Ensure you have current version of `cargo` and [Rust](https://www.rust-lang.org) installed -//! 2. Clone the project `$ git clone https://github.com/kbknapp/cargo-outdated && cd cargo-outdated` -//! 3. Build the project `$ cargo build --release` -//! 4. Once complete, the binary will be located at `target/release/cargo-outdated` -//! -//! ## Installation and Usage -//! -//! All you need to do is place `cargo-outdated` somewhere in your `$PATH`. Then run `cargo outdated` anywhere in your project directory. For full details see below. -//! -//! ### Linux / OS X -//! -//! You have two options, place `cargo-outdated` into a directory that is already located in your `$PATH` variable (To see which directories those are, open a terminal and type `echo "${PATH//:/\n}"`, the quotation marks are important), or you can add a custom directory to your `$PATH` -//! -//! **Option 1** -//! If you have write permission to a directory listed in your `$PATH` or you have root permission (or via `sudo`), simply copy the `cargo-outdated` to that directory `# sudo cp cargo-outdated /usr/local/bin` -//! -//! **Option 2** -//! If you do not have root, `sudo`, or write permission to any directory already in `$PATH` you can create a directory inside your home directory, and add that. Many people use `$HOME/.bin` to keep it hidden (and not clutter your home directory), or `$HOME/bin` if you want it to be always visible. Here is an example to make the directory, add it to `$PATH`, and copy `cargo-outdated` there. -//! -//! Simply change `bin` to whatever you'd like to name the directory, and `.bashrc` to whatever your shell startup file is (usually `.bashrc`, `.bash_profile`, or `.zshrc`) -//! -//! ```ignore -//! $ mkdir ~/bin -//! $ echo "export PATH=$PATH:$HOME/bin" >> ~/.bashrc -//! $ cp cargo-outdated ~/bin -//! $ source ~/.bashrc -//! ``` -//! -//! ### Windows -//! -//! On Windows 7/8 you can add directory to the `PATH` variable by opening a command line as an administrator and running -//! -//! ```ignore -//! C:\> setx path "%path%;C:\path\to\cargo-outdated\binary" -//! ``` -//! -//! Otherwise, ensure you have the `cargo-outdated` binary in the directory which you operating in the command line from, because Windows automatically adds your current directory to PATH (i.e. if you open a command line to `C:\my_project\` to use `cargo-outdated` ensure `cargo-outdated.exe` is inside that directory as well). -//! -//! -//! ### Options -//! -//! There are a few options for using `cargo-outdated` which should be somewhat self explanitory. -//! -//! ```ignore -//! USAGE: -//! cargo outdated [FLAGS] [OPTIONS] -//! -//! FLAGS: -//! -h, --help Prints help information -//! -R, --root-deps-only Only check root dependencies (Equivalent to --depth=1) -//! -V, --version Prints version information -//! -v, --verbose Print verbose output -//! -//! OPTIONS: -//! -d, --depth How deep in the dependency chain to search (Defaults to all dependencies when omitted) -//! --exit-code The exit code to return on new versions found [default: 0] -//! -l, --lockfile-path An absolute path to the Cargo.lock to use (Defaults to Cargo.lock in project root) -//! -m, --manifest-path An absolute path to the Cargo.toml to use (Defaults to Cargo.toml in project root) -//! -p, --package ... Package to inspect for updates -//! -r, --root Package to treat as the root package -//! ``` -//! -//! ## License -//! -//! `cargo-outdated` is released under the terms of the MIT license. See the LICENSE-MIT file for the details. - +/// Displays information about project dependency versions +/// +/// USAGE: +/// cargo outdated [FLAGS] [OPTIONS] +/// +/// FLAGS: +/// --all-features Check outdated packages with all features enabled +/// -h, --help Prints help information +/// --no-default-features Do not include the `default` feature +/// -R, --root-deps-only Only check root dependencies (Equivalent to --depth=1) +/// -V, --version Prints version information +/// -v, --verbose Use verbose output +/// +/// OPTIONS: +/// --color Coloring: auto, always, never [default: auto] +/// [values: auto, always, never] +/// -d, --depth How deep in the dependency chain to search +/// (Defaults to all dependencies when omitted) +/// --exit-code The exit code to return on new versions found [default: 0] +/// --features Space-separated list of features +/// -m, --manifest-path An absolute path to the Cargo.toml file to use +/// (Defaults to Cargo.toml in project root) +/// -p, --packages ... Package to inspect for updates +/// -r, --root Package to treat as the root package +extern crate cargo; #[macro_use] extern crate clap; -extern crate toml; -extern crate tempdir; -#[cfg(feature = "color")] -extern crate ansi_term; -extern crate tabwriter; +extern crate env_logger; +extern crate semver; extern crate serde; #[macro_use] extern crate serde_derive; +extern crate tabwriter; +extern crate tempdir; +extern crate toml; #[macro_use] mod macros; -mod config; -mod error; -mod fmt; -mod util; -mod cargo_files; mod cargo_ops; +use cargo_ops::{ElaborateWorkspace, TempProject}; -use std::io::{Write, stdout}; use std::path::Path; -#[cfg(feature="debug")] -use std::env; -use std::process; -use clap::{App, AppSettings, Arg, SubCommand, ArgMatches}; -use tabwriter::TabWriter; +use cargo::core::Workspace; +use cargo::util::important_paths::find_root_manifest_for_wd; +use cargo::util::{CargoResult, CliError, Config}; +use cargo::core::shell::Verbosity; +use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; -use config::Config; -use error::{CliResult, CliError}; -use fmt::Format; +/// Options from CLI arguments +#[derive(Deserialize, Debug)] +pub struct Options { + flag_color: Option, + flag_features: Vec, + flag_all_features: bool, + flag_no_default_features: bool, + flag_manifest_path: Option, + flag_quiet: Option, + flag_verbose: u32, + flag_frozen: bool, + flag_locked: bool, + flag_exit_code: i32, + flag_packages: Vec, + flag_root: Option, + flag_depth: i32, +} + +impl Options { + fn from_matches(m: &ArgMatches) -> Options { + Options { + flag_color: m.value_of("color").map(String::from), + flag_features: m.values_of("features") + .map(|vals| vals.into_iter().map(String::from).collect()) + .unwrap_or_default(), + flag_all_features: m.is_present("all-features"), + flag_no_default_features: m.is_present("no-default-features"), + flag_manifest_path: m.value_of("manifest-path").map(String::from), + flag_quiet: None, + flag_verbose: m.occurrences_of("verbose") as u32, + flag_frozen: false, + flag_locked: false, + flag_exit_code: m.value_of("exit-code") + .and_then(|v| v.parse().ok()) + .unwrap_or_else(|| 0_i32), + flag_packages: m.values_of("packages") + .map(|vals| vals.into_iter().map(String::from).collect()) + .unwrap_or_default(), + flag_root: m.value_of("root").map(String::from), + flag_depth: if m.is_present("root-deps-only") { + 1 + } else { + m.value_of("depth") + .as_ref() + .and_then(|v| v.parse::().ok()) + .unwrap_or_else(|| -1_i32) + }, + } + } +} fn main() { - debugln!("main:args={:?}", env::args().collect::>()); + env_logger::init().unwrap(); + + let config = match Config::default() { + Ok(cfg) => cfg, + Err(e) => { + let mut shell = cargo::core::Shell::new(); + cargo::exit_with_error(e.into(), &mut shell) + } + }; + let m = App::new("cargo-outdated") .author("Kevin K. ") .about("Displays information about project dependency versions") .version(concat!("v", crate_version!())) - // We have to lie about our binary name since this will be a third party - // subcommand for cargo .bin_name("cargo") - // Global version uses the version we supplied (Cargo.toml) for all subcommands - // as well - .settings(&[AppSettings::GlobalVersion, - AppSettings::SubcommandRequired]) - // We use a subcommand because parsed after `cargo` is sent to the third party - // plugin - // which will be interpreted as a subcommand/positional arg by clap - .subcommand(SubCommand::with_name("outdated") - .about("Displays information about project dependency versions") - .args_from_usage( - "-p, --package [PKG]... 'Package to inspect for updates' - -r, --root [ROOT] 'Package to treat as the root package' - -v, --verbose 'Print verbose output' - -d, --depth [NUM] 'How deep in the dependency chain to search \ - (Defaults to all dependencies when omitted)'") - .args(&[ - Arg::from_usage("--exit-code [NUM] 'The exit code to return on new versions found'") - .default_value("0"), - Arg::from_usage( - "-R, --root-deps-only 'Only check root dependencies (Equivalent to --depth=1)'") - .conflicts_with("depth"), - Arg::from_usage("-m, --manifest-path [PATH] 'An absolute path to the Cargo.toml file to use \ - (Defaults to Cargo.toml in project root)'") - .validator(is_file), - Arg::from_usage("-l, --lockfile-path [PATH] 'An absolute path to the Cargo.lock to use \ - (Defaults to Cargo.lock in project root)'") - .validator(is_file)])) + .settings(&[ + AppSettings::GlobalVersion, + AppSettings::SubcommandRequired, + ]) + .subcommand( + SubCommand::with_name("outdated") + .about("Displays information about project dependency versions") + .arg( + Arg::with_name("color") + .long("color") + .help("Coloring: auto, always, never") + .takes_value(true) + .number_of_values(1) + .possible_values(&["auto", "always", "never"]) + .default_value("auto"), + ) + .arg( + Arg::with_name("features") + .long("features") + .help("Space-separated list of features") + .takes_value(true) + .value_name("FEATURE") + .value_delimiter(" ") + .conflicts_with_all(&["all-features", "no-default-features"]), + ) + .arg( + Arg::with_name("all-features") + .long("all-features") + .help("Check outdated packages with all features enabled") + .conflicts_with_all(&["features", "no-default-features"]), + ) + .arg( + Arg::with_name("no-default-features") + .long("no-default-features") + .help("Do not include the `default` feature") + .conflicts_with_all(&["features", "all-features"]), + ) + .arg( + Arg::with_name("packages") + .long("packages") + .short("p") + .help("Package to inspect for updates") + .takes_value(true) + .value_name("PKG") + .value_delimiter(" ") + .multiple(true), + ) + .arg( + Arg::with_name("root") + .long("root") + .short("r") + .help("Package to treat as the root package") + .takes_value(true) + .value_name("ROOT") + .number_of_values(1), + ) + .arg( + Arg::with_name("verbose") + .long("verbose") + .short("v") + .help("Use verbose output") + .multiple(true), + ) + .arg( + Arg::with_name("depth") + .long("depth") + .short("d") + .long_help( + "How deep in the dependency chain to search \ + (Defaults to all dependencies when omitted)", + ) + .takes_value(true) + .value_name("NUM") + .number_of_values(1), + ) + .arg( + Arg::with_name("exit-code") + .long("exit-code") + .help("The exit code to return on new versions found") + .takes_value(true) + .value_name("NUM") + .number_of_values(1) + .default_value("0"), + ) + .arg( + Arg::with_name("root-deps-only") + .long("root-deps-only") + .short("R") + .help("Only check root dependencies (Equivalent to --depth=1)") + .conflicts_with("depth"), + ) + .arg( + Arg::with_name("manifest-path") + .long("manifest-path") + .short("m") + .long_help( + "An absolute path to the Cargo.toml file to use \ + (Defaults to Cargo.toml in project root)", + ) + .takes_value(true) + .value_name("PATH") + .number_of_values(1) + .validator(is_file), + ), + ) .get_matches(); - - if let Some(m) = m.subcommand_matches("outdated") { - match execute(m) { - Ok(code) => { - debugln!("main:exit_code={}", code); - process::exit(code) - } - Err(e) => e.exit(), + let m = m.subcommand_matches("outdated") + .expect("Subcommand outdated not found"); + let options = Options::from_matches(m); + let exit_code = options.flag_exit_code; + let result = execute(options, &config); + match result { + Err(e) => { + let cli_error = CliError::new(e, 1); + cargo::exit_with_error(cli_error, &mut *config.shell()) } + Ok(i) => if i > 0 { + std::process::exit(exit_code); + } else { + std::process::exit(0); + }, } } -fn execute(m: &ArgMatches) -> CliResult { - debugln!("execute:m={:#?}", m); - let cfg = try!(Config::from_matches(m)); +#[allow(unknown_lints)] +#[allow(needless_pass_by_value)] +pub fn execute(options: Options, config: &Config) -> CargoResult { + config.configure( + options.flag_verbose, + options.flag_quiet, + &options.flag_color, + options.flag_frozen, + options.flag_locked, + )?; + debug!(config, format!("options: {:?}", options)); - // parse original lockfile - verbose!( - cfg, - "Parsing {}...", - Format::Warning(cfg.lockfile.to_string_lossy()) - ); - let dep_tree_curr = { - let mut parsed_lock = cargo_files::Lockfile::from_lockfile_path(&cfg.lockfile)?; - if parsed_lock.package.is_none() { - return Err(CliError::NoRootDeps); - } - parsed_lock - .package - .as_mut() - .unwrap() - .push(parsed_lock.root.clone()); - cargo_files::DependencyTree::from_lockfile(&mut parsed_lock, cfg.root, cfg.depth) - }; - verboseln!(cfg, "{}", Format::Good("Done")); - // create a temp project in tmp - let tmp_proj = cargo_ops::TempProject::new(&cfg.manifest, &cfg.lockfile)?; - // write semver to the tmp Cargo.toml - tmp_proj.write_manifest_semver()?; - // update it - tmp_proj.cargo_update()?; - // parse lockfile with semver compatible dependencies - verbose!( - cfg, - "Parsing semver compatible lockfile {}...", - Format::Warning(tmp_proj.lockfile.to_string_lossy()) - ); - let dep_tree_compat = { - let mut parsed_lock = cargo_files::Lockfile::from_lockfile_path(&tmp_proj.lockfile)?; - parsed_lock - .package - .as_mut() - .unwrap() - .push(parsed_lock.root.clone()); - cargo_files::DependencyTree::from_lockfile(&mut parsed_lock, cfg.root, -1) - }; - verboseln!(cfg, "{}", Format::Good("Done")); - // rewrite the manifest with "*" semver dependencies - tmp_proj.write_manifest_latest()?; - // update it - tmp_proj.cargo_update()?; - // parse lockfile with latest dependencies - verbose!( - cfg, - "Parsing latest lockfile {}...", - Format::Warning(tmp_proj.lockfile.to_string_lossy()) - ); - let dep_tree_latest = { - let mut parsed_lock = cargo_files::Lockfile::from_lockfile_path(&tmp_proj.lockfile)?; - parsed_lock - .package - .as_mut() - .unwrap() - .push(parsed_lock.root.clone()); - cargo_files::DependencyTree::from_lockfile(&mut parsed_lock, cfg.root, -1) - }; - verboseln!(cfg, "{}", Format::Good("Done")); - - let mut tw = TabWriter::new(vec![]); - write!(&mut tw, "Name\tProject Ver\tSemVer Compat\tLatest Ver\n") - .unwrap_or_else(|e| panic!("write! error: {}", e)); - let lines = cargo_files::DependencyTree::print_list_to_vec( - &dep_tree_curr, - &dep_tree_compat, - &dep_tree_latest, - &cfg, - ); - if lines.is_empty() { - println!("All dependencies are up to date, yay!"); - return Ok(0); + verbose!(config, "Parsing...", "current workspace"); + // the Cargo.toml that we are actually working on + let curr_manifest = + find_root_manifest_for_wd(options.flag_manifest_path.clone(), config.cwd())?; + let curr_workspace = Workspace::new(&curr_manifest, config)?; + verbose!(config, "Resolving...", "current workspace"); + if options.flag_verbose == 0 { + config.shell().set_verbosity(Verbosity::Quiet); } - for l in lines { - try!(write!(&mut tw, "{}", l)); + let mut ela_curr = ElaborateWorkspace::from_workspace(&curr_workspace, &options)?; + if options.flag_verbose > 0 { + config.shell().set_verbosity(Verbosity::Verbose); + } else { + config.shell().set_verbosity(Verbosity::Normal); } - tw.flush() - .unwrap_or_else(|e| panic!("failed to flush TabWriter: {}", e)); - write!( - stdout(), - "{}", - String::from_utf8(tw.into_inner().unwrap()) - .unwrap_or_else(|e| panic!("from_utf8 error: {}", e)) - ).unwrap_or_else(|e| panic!("write! error: {}", e)); - Ok(cfg.exit_code) + verbose!(config, "Parsing...", "compat workspace"); + let compat_proj = + TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?; + compat_proj.write_manifest_semver()?; + verbose!(config, "Updating...", "compat workspace"); + compat_proj.cargo_update()?; + verbose!(config, "Resolving...", "compat workspace"); + let compat_workspace = compat_proj.workspace.borrow(); + let ela_compat = + ElaborateWorkspace::from_workspace(compat_workspace.as_ref().unwrap(), &options)?; + + verbose!(config, "Parsing...", "latest workspace"); + let latest_proj = + TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?; + latest_proj.write_manifest_latest()?; + verbose!(config, "Updating...", "latest workspace"); + latest_proj.cargo_update()?; + verbose!(config, "Resolving...", "latest workspace"); + let latest_workspace = latest_proj.workspace.borrow(); + let ela_latest = + ElaborateWorkspace::from_workspace(latest_workspace.as_ref().unwrap(), &options)?; + + verbose!(config, "Resolving...", "package status"); + ela_curr.resolve_status(&ela_compat, &ela_latest, &options, config)?; + + let count = ela_curr.print_list(&options, config)?; + + Ok(count) } +#[allow(unknown_lints)] +#[allow(needless_pass_by_value)] fn is_file(s: String) -> Result<(), String> { let p = Path::new(&*s); if p.file_name().is_none() { diff --git a/src/util.rs b/src/util.rs deleted file mode 100644 index 36ce2ac..0000000 --- a/src/util.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::env; -use std::path::{Path, PathBuf}; -use std::fs; - -use error::{CliError, CliResult}; - -pub fn find_file(file: &str, usr_override: bool) -> CliResult { - debugln!("util:find_file;file={:?};usr_override={:?}", file, usr_override); - if usr_override { - return Ok(Path::new(file).to_path_buf()); - } - let cwd = try!(env::current_dir()); - let mut pwd = cwd.as_path(); - - loop { - let ret = pwd.join(file); - if let Ok(metadata) = fs::metadata(&ret) { - if metadata.is_file() { - return Ok(ret); - } - } - - match pwd.parent() { - Some(p) => pwd = p, - None => break, - } - } - - Err(CliError::Generic(format!("Could not find `{}` in `{}` or any parent directory", - file, - pwd.display()))) -}