├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "backtrace" 5 | version = "0.3.40" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 10 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 11 | "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 12 | ] 13 | 14 | [[package]] 15 | name = "backtrace-sys" 16 | version = "0.1.32" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | dependencies = [ 19 | "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", 20 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 21 | ] 22 | 23 | [[package]] 24 | name = "cargo-why" 25 | version = "0.2.0" 26 | dependencies = [ 27 | "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 28 | "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 29 | ] 30 | 31 | [[package]] 32 | name = "cargo_metadata" 33 | version = "0.9.1" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | dependencies = [ 36 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 37 | "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 38 | "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 39 | "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", 40 | ] 41 | 42 | [[package]] 43 | name = "cc" 44 | version = "1.0.48" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | 47 | [[package]] 48 | name = "cfg-if" 49 | version = "0.1.10" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | 52 | [[package]] 53 | name = "failure" 54 | version = "0.1.6" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | dependencies = [ 57 | "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 59 | ] 60 | 61 | [[package]] 62 | name = "failure_derive" 63 | version = "0.1.6" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | dependencies = [ 66 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 70 | ] 71 | 72 | [[package]] 73 | name = "itoa" 74 | version = "0.4.4" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | 77 | [[package]] 78 | name = "libc" 79 | version = "0.2.66" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | 82 | [[package]] 83 | name = "proc-macro2" 84 | version = "1.0.6" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | dependencies = [ 87 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 88 | ] 89 | 90 | [[package]] 91 | name = "quote" 92 | version = "1.0.2" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | dependencies = [ 95 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 96 | ] 97 | 98 | [[package]] 99 | name = "rustc-demangle" 100 | version = "0.1.16" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | 103 | [[package]] 104 | name = "ryu" 105 | version = "1.0.2" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | 108 | [[package]] 109 | name = "semver" 110 | version = "0.9.0" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | dependencies = [ 113 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 114 | "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 115 | ] 116 | 117 | [[package]] 118 | name = "semver-parser" 119 | version = "0.7.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | 122 | [[package]] 123 | name = "serde" 124 | version = "1.0.103" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | 127 | [[package]] 128 | name = "serde_derive" 129 | version = "1.0.103" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | dependencies = [ 132 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 133 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 134 | "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", 135 | ] 136 | 137 | [[package]] 138 | name = "serde_json" 139 | version = "1.0.44" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | dependencies = [ 142 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 143 | "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 145 | ] 146 | 147 | [[package]] 148 | name = "syn" 149 | version = "1.0.11" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | dependencies = [ 152 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 153 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 154 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 155 | ] 156 | 157 | [[package]] 158 | name = "synstructure" 159 | version = "0.12.3" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | dependencies = [ 162 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 163 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 164 | "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", 165 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 166 | ] 167 | 168 | [[package]] 169 | name = "unicode-xid" 170 | version = "0.2.0" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | 173 | [metadata] 174 | "checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" 175 | "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" 176 | "checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" 177 | "checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" 178 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 179 | "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" 180 | "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" 181 | "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 182 | "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" 183 | "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" 184 | "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 185 | "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 186 | "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" 187 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 188 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 189 | "checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" 190 | "checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" 191 | "checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" 192 | "checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" 193 | "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" 194 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 195 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-why" 3 | version = "0.2.0" 4 | authors = ["Melody Horn "] 5 | edition = "2018" 6 | license = "MIT" 7 | description = "traces dependency paths to show why a crate was required" 8 | repository = "https://github.com/boringcactus/cargo-why" 9 | readme = "README.md" 10 | keywords = ["cli", "cargo-subcommand", "dependencies", "crates", "cargo"] 11 | categories = ["development-tools::cargo-plugins"] 12 | 13 | [badges] 14 | maintenance = { status = "passively-maintained" } 15 | 16 | [dependencies] 17 | cargo_metadata = "0.9.1" 18 | failure = "0.1.6" 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Melody Horn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cargo-why 2 | 3 | traces dependency paths to show why a crate was required 4 | 5 | ## installation 6 | 7 | ``` 8 | cargo install cargo-why 9 | ``` 10 | 11 | ## usage 12 | 13 | ``` 14 | $ cargo why serde 15 | cargo-why -> cargo_metadata -> semver -> serde 16 | cargo-why -> cargo_metadata -> serde 17 | cargo-why -> cargo_metadata -> serde_json -> serde 18 | ``` 19 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use failure::Error; 5 | use cargo_metadata::{PackageId, Resolve}; 6 | 7 | fn main() -> Result<(), Error> { 8 | let (target, other_flags) = { 9 | let mut args = std::env::args(); 10 | let _ = args.next(); // we don't care about the name of the binary 11 | if args.next() != Some("why".to_string()) { 12 | usage(); 13 | ::std::process::exit(1); 14 | } 15 | let target = match args.next() { 16 | Some(target) => { 17 | if target == "-h" || target == "--help" { 18 | usage(); 19 | ::std::process::exit(1); 20 | } 21 | target 22 | } 23 | None => { 24 | usage(); 25 | ::std::process::exit(1); 26 | } 27 | }; 28 | let other_flags: Vec = args.collect(); 29 | (target, other_flags) 30 | }; 31 | let mut cmd = cargo_metadata::MetadataCommand::new(); 32 | cmd.other_options(other_flags); 33 | let metadata = cmd.exec()?; 34 | let resolve = match metadata.resolve { 35 | Some(x) => x, 36 | None => bail!("No dependency resolution found"), 37 | }; 38 | for root in metadata.workspace_members { 39 | search(vec![&root], &resolve, &target); 40 | } 41 | Ok(()) 42 | } 43 | 44 | fn usage() { 45 | eprintln!(concat!("cargo-why ", env!("CARGO_PKG_VERSION"), r#" 46 | 47 | USAGE: 48 | cargo why [other cargo flags (features, offline, etc)...] 49 | 50 | FLAGS: 51 | -h, --help Prints help information 52 | "#)); 53 | } 54 | 55 | fn search(history: Vec<&PackageId>, resolve: &Resolve, target: &str) { 56 | let curr = match history.last() { 57 | Some(&x) => x, 58 | None => return, 59 | }; 60 | if history[0..history.len() - 1].contains(&curr) { 61 | // avoid infinite recursion 62 | return; 63 | } 64 | let node = resolve.nodes.iter().find(|node| node.id == *curr); 65 | let node = match node { 66 | Some(x) => x, 67 | None => return, 68 | }; 69 | for dep in &node.dependencies { 70 | if dep.repr.contains(&format!("{} ", target)) { 71 | for pkg in &history { 72 | let pkg = pkg.repr.split(' ').nth(0).unwrap(); 73 | print!("{} -> ", pkg); 74 | } 75 | println!("{}", target); 76 | } else { 77 | let mut history = history.clone(); 78 | history.push(dep); 79 | search(history, resolve, target); 80 | } 81 | } 82 | } 83 | --------------------------------------------------------------------------------