project_model/toolchain_info/
version.rs1use anyhow::Context;
4use rustc_hash::FxHashMap;
5use semver::Version;
6use toolchain::Tool;
7
8use crate::{toolchain_info::QueryConfig, utf8_stdout};
9
10pub(crate) fn get(
11 config: QueryConfig<'_>,
12 extra_env: &FxHashMap<String, Option<String>>,
13) -> Result<Option<Version>, anyhow::Error> {
14 let (mut cmd, prefix) = match config {
15 QueryConfig::Cargo(sysroot, cargo_toml, _) => {
16 (sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env), "cargo ")
17 }
18 QueryConfig::Rustc(sysroot, current_dir) => {
19 (sysroot.tool(Tool::Rustc, current_dir, extra_env), "rustc ")
20 }
21 };
22 cmd.arg("--version");
23 let out = utf8_stdout(&mut cmd).with_context(|| format!("Failed to query rust toolchain version via `{cmd:?}`, is your toolchain setup correctly?"))?;
24
25 let version =
26 out.strip_prefix(prefix).and_then(|it| Version::parse(it.split_whitespace().next()?).ok());
27 if version.is_none() {
28 tracing::warn!("Failed to parse `{cmd:?}` output `{out}` as a semver version");
29 }
30 anyhow::Ok(version)
31}
32
33#[cfg(test)]
34mod tests {
35 use paths::{AbsPathBuf, Utf8PathBuf};
36
37 use crate::{ManifestPath, Sysroot};
38
39 use super::*;
40
41 #[test]
42 fn cargo() {
43 let manifest_path = concat!(env!("CARGO_MANIFEST_DIR"), "/Cargo.toml");
44 let sysroot = Sysroot::empty();
45 let manifest_path =
46 ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
47 let cfg = QueryConfig::Cargo(&sysroot, &manifest_path, &None);
48 assert!(get(cfg, &FxHashMap::default()).is_ok());
49 }
50
51 #[test]
52 fn rustc() {
53 let sysroot = Sysroot::empty();
54 let cfg = QueryConfig::Rustc(&sysroot, env!("CARGO_MANIFEST_DIR").as_ref());
55 assert!(get(cfg, &FxHashMap::default()).is_ok());
56 }
57}