Last active
November 18, 2019 03:54
-
-
Save qryxip/79cc4532d1022ce4fa5b07fb7b201b56 to your computer and use it in GitHub Desktop.
A cargo subcommand to list all of the "normal dependencies" in the dependency graph
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //! A cargo subcommand to list all of the "normal dependencies" in the dependency graph. | |
| //! | |
| //! Licensed under [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/). | |
| //! | |
| //! ```toml | |
| //! [package] | |
| //! edition = "2018" | |
| //! name = "cargo-normal-deps" | |
| //! version = "0.0.0" | |
| //! authors = ["Ryo Yamashita <[email protected]>"] | |
| //! description = 'A cargo subcommand to list all of the "normal dependencies" in the dependency graph' | |
| //! publish = false | |
| //! license = "CC0-1.0" | |
| //! | |
| //! [dependencies] | |
| //! cargo = "0.40.0" | |
| //! failure = "0.1.6" | |
| //! maplit = "1.0.2" | |
| //! serde_json = "1.0.41" | |
| //! ``` | |
| use cargo::core::compiler::{self, CompileMode, TargetInfo}; | |
| use cargo::core::dependency; | |
| use cargo::core::resolver::ResolveOpts; | |
| use cargo::core::shell::Shell; | |
| use cargo::ops::Packages; | |
| use cargo::util::command_prelude::{ | |
| opt, subcommand, App, AppExt as _, AppSettings, ArgMatches, ArgMatchesExt as _, | |
| }; | |
| use cargo::Config; | |
| use failure::Fallible; | |
| use maplit::btreeset; | |
| use std::env; | |
| use std::io::{self, Write}; | |
| fn main() { | |
| let args = app().get_matches(); | |
| let args = args.subcommand_matches("normal-deps").unwrap(); | |
| let mut config = | |
| Config::default().unwrap_or_else(|e| cargo::exit_with_error(e.into(), &mut Shell::new())); | |
| if let Err(err) = run(args, &mut config, io::stdout()) { | |
| cargo::exit_with_error(err.into(), &mut config.shell()); | |
| } | |
| } | |
| fn app() -> App { | |
| App::new("cargo-normal-deps") | |
| .settings(&[ | |
| AppSettings::DeriveDisplayOrder, | |
| AppSettings::SubcommandRequiredElseHelp, | |
| ]) | |
| .bin_name("cargo") | |
| .version(env!("CARGO_PKG_VERSION")) | |
| .author(env!("CARGO_PKG_AUTHORS")) | |
| .about(env!("CARGO_PKG_DESCRIPTION")) | |
| .subcommand( | |
| subcommand("normal-deps") | |
| .version(env!("CARGO_PKG_VERSION")) | |
| .author(env!("CARGO_PKG_AUTHORS")) | |
| .about(env!("CARGO_PKG_DESCRIPTION")) | |
| .arg_features() | |
| .arg_target_triple("Specify the target triple") | |
| .arg_manifest_path() | |
| .arg(opt("color", "Coloring: auto, always, never").value_name("WHEN")) | |
| .arg(opt("frozen", "Require Cargo.lock and cache are up to date")) | |
| .arg(opt("locked", "Require Cargo.lock is up to date")) | |
| .arg(opt("offline", "Run without accessing the network")), | |
| ) | |
| } | |
| fn run(args: &ArgMatches, config: &mut Config, mut stdout: impl Write) -> Fallible<()> { | |
| config.configure( | |
| 0, | |
| None, | |
| &args.value_of("color").map(ToOwned::to_owned), | |
| args.is_present("frozen"), | |
| args.is_present("locked"), | |
| args.is_present("offline"), | |
| &None, | |
| &[], | |
| )?; | |
| let ws = args.workspace(config)?; | |
| let current = ws.current()?.package_id(); | |
| let rustc = config.load_global_rustc(Some(&ws))?; | |
| let compile_opts = args.compile_options_for_single_package( | |
| config, | |
| CompileMode::Check { test: false }, | |
| Some(&ws), | |
| )?; | |
| let triple = compile_opts | |
| .build_config | |
| .requested_target | |
| .as_ref() | |
| .unwrap_or(&rustc.host); | |
| let target_info = TargetInfo::new( | |
| config, | |
| &compile_opts.build_config.requested_target, | |
| &rustc, | |
| if compile_opts.build_config.requested_target.is_some() { | |
| compiler::Kind::Target | |
| } else { | |
| compiler::Kind::Host | |
| }, | |
| )?; | |
| let (_, resolve) = cargo::ops::resolve_ws_with_opts( | |
| &ws, | |
| ResolveOpts::new( | |
| false, | |
| &args._values_of("features"), | |
| args.is_present("all-features"), | |
| !args.is_present("no-default-features"), | |
| ), | |
| &Packages::Default.to_package_id_specs(&ws)?, | |
| )?; | |
| let (mut normals, mut cur) = (btreeset!(current), btreeset!(current)); | |
| while !cur.is_empty() { | |
| let mut next = btreeset!(); | |
| for from in cur { | |
| for (to, deps) in resolve.deps(from) { | |
| for dep in deps { | |
| if dep.kind() == dependency::Kind::Normal | |
| && dep | |
| .platform() | |
| .as_ref() | |
| .map_or(true, |p| p.matches(triple, target_info.cfg())) | |
| && normals.insert(to) | |
| { | |
| next.insert(to); | |
| } | |
| } | |
| } | |
| } | |
| cur = next; | |
| } | |
| let output = serde_json::to_string(&normals).unwrap(); | |
| stdout.write_all(output.as_ref()).map_err(Into::into) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment