Skip to content

Instantly share code, notes, and snippets.

@qryxip
Last active November 18, 2019 03:54
Show Gist options
  • Select an option

  • Save qryxip/79cc4532d1022ce4fa5b07fb7b201b56 to your computer and use it in GitHub Desktop.

Select an option

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
//! 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