From 624ab1c6cf4f18df31a33ca48e4c545f1e78e6c2 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Thu, 22 Jun 2023 15:07:42 +0900 Subject: [PATCH] feat: add version check for cargo-llvm-cov --- Cargo.lock | 1 + Cargo.toml | 1 + src/cargo.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 4 +++- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c6820e..7ccb817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,6 +534,7 @@ dependencies = [ "quote", "rayon", "rustc-demangle", + "semver", "serde", "serde_json", "syntect", diff --git a/Cargo.toml b/Cargo.toml index 7caab07..c8f6713 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ ignore = "0.4.20" minify-html = "0.11.1" rayon = "1.7.0" rustc-demangle = "0.1.23" +semver = "1.0.17" serde = { version = "1.0.164", features = ["derive"] } serde_json = "1.0.97" time = { version = "0.3.22", features = ["formatting", "local-offset", "macros"] } diff --git a/src/cargo.rs b/src/cargo.rs index 4ef4df9..c9d1b99 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -1,6 +1,6 @@ use std::process::Command; -use anyhow::{bail, Result}; +use anyhow::{bail, ensure, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use serde::Deserialize; @@ -67,3 +67,48 @@ fn find_target_dir(root: &Utf8Path) -> Result { .map(|data| data.target_directory) .map_err(Into::into) } + +/// Ensure the globally installed `cargo-llvm-cov` is a recent _known-to-be-working_ version, to +/// avoid possible errors due to different output in older versions. +pub fn check_version() -> Result<()> { + use semver::{Comparator, Op, Prerelease, Version}; + + static MIN_VERSION: Comparator = Comparator { + op: Op::GreaterEq, + major: 0, + minor: Some(5), + patch: None, + pre: Prerelease::EMPTY, + }; + + let output = Command::new("cargo-llvm-cov") + .args(["llvm-cov", "--version"]) + .output()?; + + if !output.status.success() { + bail!( + "failed running cargo-llvm-cov (llvm-cov --version):\n{}", + String::from_utf8_lossy(&output.stderr) + ); + } + + let output = String::from_utf8_lossy(&output.stdout); + let (name, version) = output + .trim() + .split_once(' ') + .context("no separator between name and version")?; + + ensure!( + name == "cargo-llvm-cov", + "program doesn't appear to be cargo-llvm-cov" + ); + + let version = version.parse::()?; + + ensure!( + MIN_VERSION.matches(&version), + "cargo-llvm-cov version {version} is too old, need at least {MIN_VERSION}" + ); + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 9be635a..a5b79d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use std::{ ops::RangeInclusive, }; -use anyhow::Result; +use anyhow::{Context, Result}; use askama::Template; use camino::{Utf8Path, Utf8PathBuf}; use rayon::iter::{IntoParallelIterator, IntoParallelRefMutIterator, ParallelIterator}; @@ -47,6 +47,8 @@ fn main() -> Result<()> { return Ok(()); } + cargo::check_version().context("failed checking cargo-llvm-cov version")?; + let JsonExport { data: [export], .. } = if let Some(input) = cli.input { let file = BufReader::new(File::open(input)?); serde_json::from_reader::<_, JsonExport>(file)?