cargo-udeps 0.1.48

Find unused dependencies in Cargo.toml
Documentation
#![allow(dead_code)]

use std::ffi::OsString;
use std::path::PathBuf;
use std::process::{Command, Output};
use std::{env, fs, io, str};

use anyhow::Context;
use cargo::core::shell::Shell;
use cargo::{CargoResult, CliError};
use tempfile::TempDir;

static DEFAULT_TOOLCHAIN :&str = "nightly";

const SET_RUSTC_ENV :&str = "__CARGO_UDEPS_SET_RUSTC";

fn set_rustc_env() -> CargoResult<()> {
	let toolchain =
		env::var("CARGO_UDEPS_TEST_TOOLCHAIN").unwrap_or_else(|_| DEFAULT_TOOLCHAIN.to_owned());
	let Output { status, stdout, .. } = Command::new("rustup")
		.args(&["which", "rustc"])
		.env("RUSTUP_TOOLCHAIN", &toolchain)
		.output()?;
	if !status.success() {
		return Err(anyhow::anyhow!("{}", status))
			.with_context(|| format!("could not get the {} rustc", toolchain));
	}
	env::set_var("RUSTC", str::from_utf8(&stdout)?.trim());
	env::set_var(SET_RUSTC_ENV, "1");
	Ok(())
}

pub(crate) struct Runner {
	cwd :TempDir,
	cargo_home :PathBuf,
	args :Vec<OsString>,
}

impl Runner {
	pub(crate) fn new(prefix :&str) -> CargoResult<Self> {
		if env::var_os(SET_RUSTC_ENV).is_none() {
			set_rustc_env()?;
		}
		let cwd = tempfile::Builder::new().prefix(prefix).tempdir()?;
		let cargo_home = cargo::util::homedir(cwd.as_ref())
			.with_context(|| "couldn't find the \"Cargo home\"")?;
		let args = vec!["".into(), "udeps".into()];
		Ok(Self {
			cwd,
			cargo_home,
			args,
		})
	}

	pub(crate) fn cargo_toml(self, content :&str) -> io::Result<Self> {
		self.file("Cargo.toml", content)
	}

	pub(crate) fn file(self, file_name :&str, content :&str) -> io::Result<Self> {
		let path = self.cwd.path().join(file_name);
		fs::write(path, content)?;
		Ok(self)
	}

	pub(crate) fn dir(self, name :&str) -> io::Result<Self> {
		let path = self.cwd.path().join(name);
		fs::create_dir_all(path)?;
		Ok(self)
	}

	pub(crate) fn arg<S: Into<OsString>>(mut self, arg: S) -> Self {
		self.args.push(arg.into());
		self
	}

	pub(crate) fn run(self) -> CargoResult<(i32, String)> {
		let mut stdout = vec![];
		let stderr = if std::env::var("UDEPS_VERBOSE_TEST").is_ok() {
			Shell::new()
		} else {
			eprintln!("Please set the UDEPS_VERBOSE_TEST environment variable to enable more verbose logging");
			Shell::from_write(Box::new(vec![]))
		};
		let mut config = cargo::util::context::GlobalContext::new(stderr,
			self.cwd.path().to_owned(), self.cargo_home.clone());
		let code = match cargo_udeps::run(self.args.clone(), &mut config, &mut stdout) {
			Ok(()) => 0,
			Err(CliError {
				error, exit_code, ..
			}) => match error {
				None => exit_code,
				Some(error) => return Err(error),
			}
		};
		let cwd_lossy = self.cwd.path().to_string_lossy();
		let stdout = str::from_utf8(&stdout)?.replace(&*cwd_lossy, "██████████");
		Ok((code, stdout))
	}
}