diff --git a/cargo-dist/src/errors.rs b/cargo-dist/src/errors.rs index 9ca422e96..68db075e7 100644 --- a/cargo-dist/src/errors.rs +++ b/cargo-dist/src/errors.rs @@ -362,9 +362,12 @@ pub enum DistError { }, /// One or more required tools are missing. - #[error("One or more required tools are missing.")] + #[error("The following tools are required to run this task, but are missing:\n{tools:#?}")] #[diagnostic(help("Please install the tools mentioned above and try again."))] - EnvToolsMissing {}, + EnvToolsMissing { + /// the names of the missing tools + tools: Vec, + }, /// Unknown target requested #[error( diff --git a/cargo-dist/src/lib.rs b/cargo-dist/src/lib.rs index ec872ffc5..6d6184dc9 100644 --- a/cargo-dist/src/lib.rs +++ b/cargo-dist/src/lib.rs @@ -57,14 +57,6 @@ pub mod tasks; #[cfg(test)] mod tests; -fn tool_status(tool: Result<&Tool, DistError>) -> Result { - match tool { - Ok(tool) => Ok(format!("✅ located {}", tool.cmd)), - Err(DistError::ToolMissing { tool: ref name }) => Err(format!("🗙 missing {}", name)), - Err(_) => unreachable!("tool_status() was given a DistError that wasn't DistError::ToolMissing. This is a bug in dist."), - } -} - /// dist env test -- make sure we have everything we need for a build. pub fn do_env_test(cfg: &Config) -> DistResult<()> { let (dist, mut manifest) = tasks::gather_work(cfg)?; @@ -96,29 +88,40 @@ pub fn do_env_test(cfg: &Config) -> DistResult<()> { */ } - let commands: Vec> = vec![ + // These are all of the tools we can check for. + // + // bool::then(f) returns an Option, so we start with a + // Vec>>. + let all_tools: Vec>> = vec![ need_cargo_auditable.then(|| tools.cargo_auditable()), need_cargo_cyclonedx.then(|| tools.cargo_cyclonedx()), need_omnibor.then(|| tools.omnibor()), need_xwin.then(|| tools.cargo_xwin()), need_zigbuild.then(|| tools.cargo_zigbuild()), - ] - .into_iter() - .filter_map(|t| t) - .filter(|t| t.is_err()) - .map(|t| tool_status(t)) - .filter(|t| t.is_err()) - .collect(); - - let mut okay = true; - for command in commands { - if let Err(s) = command { - okay = false; - println!("{}", s); - } - } + ]; + + // Drop `None`s, then extract the values from the remaining `Option`s. + let needed_tools = all_tools.into_iter().flatten(); + + // For each tool we need, + let missing: Vec = needed_tools + .filter_map(|t| match t { + // The tool was found. + Ok(_) => None, + // The tool is missing + Err(DistError::ToolMissing { tool: ref name }) => Some(name.to_owned()), + // This should never happen, but I can't find a way to enforce + // it at the type system level. ;~; -@duckinator + Err(_) => unreachable!( + "do_env_test() got an Err that wasn't DistError::ToolMissing. This is a dist bug." + ), + }) + .collect(); - okay.then(|| ()).ok_or(DistError::EnvToolsMissing {}) + missing + .is_empty() + .then_some(()) + .ok_or(DistError::EnvToolsMissing { tools: missing }) } /// dist build -- actually build binaries and installers!