From fac2aafa1171bfb664cfa9cd4ea429623199f4aa Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Sat, 12 Apr 2025 01:09:08 +0900 Subject: [PATCH] feat(build-dir): Added improved error message when template is invalid --- src/cargo/util/context/mod.rs | 21 +++++++++++++++++---- tests/testsuite/build_dir.rs | 4 ++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/cargo/util/context/mod.rs b/src/cargo/util/context/mod.rs index 9eec5d218..93f5e7d61 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -77,13 +77,14 @@ use crate::sources::CRATES_IO_REGISTRY; use crate::util::errors::CargoResult; use crate::util::network::http::configure_http_handle; use crate::util::network::http::http_handle; -use crate::util::{internal, CanonicalUrl}; +use crate::util::{closest_msg, internal, CanonicalUrl}; use crate::util::{Filesystem, IntoUrl, IntoUrlWithBase, Rustc}; use anyhow::{anyhow, bail, format_err, Context as _}; use cargo_credential::Secret; use cargo_util::paths; use cargo_util_schemas::manifest::RegistryName; use curl::easy::Easy; +use itertools::Itertools; use lazycell::LazyCell; use serde::de::IntoDeserializer as _; use serde::Deserialize; @@ -678,15 +679,27 @@ impl GlobalContext { }), ]; + let template_variables = replacements + .iter() + .map(|(key, _)| key[1..key.len() - 1].to_string()) + .collect_vec(); + let path = val .resolve_templated_path(self, replacements) .map_err(|e| match e { path::ResolveTemplateError::UnexpectedVariable { variable, raw_template, - } => anyhow!( - "unexpected variable `{variable}` in build.build-dir path `{raw_template}`" - ), + } => { + let mut suggestion = closest_msg(&variable, template_variables.iter(), |key| key, "template variable"); + if suggestion == "" { + let variables = template_variables.iter().map(|v| format!("`{{{v}}}`")).join(", "); + suggestion = format!("\n\nhelp: available template variables are {variables}"); + } + anyhow!( + "unexpected variable `{variable}` in build.build-dir path `{raw_template}`{suggestion}" + ) + }, path::ResolveTemplateError::UnexpectedBracket { bracket_type, raw_template } => { let (btype, literal) = match bracket_type { path::BracketType::Opening => ("opening", "{"), diff --git a/tests/testsuite/build_dir.rs b/tests/testsuite/build_dir.rs index c302e5074..5a0cd6f0a 100644 --- a/tests/testsuite/build_dir.rs +++ b/tests/testsuite/build_dir.rs @@ -512,6 +512,8 @@ fn template_should_error_for_invalid_variables() { .with_stderr_data(str![[r#" [ERROR] unexpected variable `fake` in build.build-dir path `{fake}/build-dir` +[HELP] available template variables are `{workspace-root}`, `{cargo-cache-home}`, `{workspace-path-hash}` + "#]]) .run(); } @@ -535,6 +537,8 @@ fn template_should_suggest_nearest_variable() { .with_stderr_data(str![[r#" [ERROR] unexpected variable `workspace-ro` in build.build-dir path `{workspace-ro}/build-dir` +[HELP] a template variable with a similar name exists: `workspace-root` + "#]]) .run(); }