In Toast we do some Command
usage that calls out to node and requires features only available in node v14. To check the available node version and provide a useful error message we use the following code to parse node -v
and check the version using the Rust semver
crate.
use color_eyre::eyre::{eyre, Result, WrapErr};use semver::Version;use std::process::Command;fn check_node_version() -> Result<()> {let minimum_required_node_major_version = Version {major: 14,minor: 0,patch: 0,pre: vec![],build: vec![],};let mut cmd = Command::new("node");cmd.arg("-v");let output = cmd.output().wrap_err_with(|| "Failed to execute `node -v` Command and collect output")?;let version_string = std::str::from_utf8(&output.stdout).wrap_err_with(|| "Failed to create utf8 string from node -v Command output")?;let version_string_trimmed =version_string.trim_start_matches("v");let current_node_version_result =Version::parse(version_string_trimmed);match current_node_version_result {Ok(current_node_version) => {if current_node_version < minimum_required_node_major_version {Err(eyre!(format!("node version {} doesn't meet the minimum required version {}",current_node_version, minimum_required_node_major_version)))} else {Ok(())}}Err(e) => Err(eyre!(format!("Couldn't parse node version from trimmed version `{}`, original string is `{}`",version_string_trimmed, version_string))),}}
The error that shows when everything works is
Error:0: node version 11.15.0 doesn't meet the minimum required version 14.0.0
we get similar output if other things go wrong as well.
We build a Version
struct manually that in this case points to 14.0.0
.
let minimum_required_node_major_version = Version {major: 14,minor: 0,patch: 0,pre: vec![],build: vec![],}
We set up a Command
that runs node -v
and try to capture the output. This could fail so we use eyre's tools to wrap the error with additional context if it does.
let mut cmd = Command::new("node");cmd.arg("-v");let output = cmd.output().wrap_err_with(|| "Failed to execute `node -v` Command and collect output")?;
The Command
output brings stdout
in as a Vec[u8]
but we want a string so we run from_utf8
on it, which could fail.
let version_string = std::str::from_utf8(&output.stdout).wrap_err_with(|| "Failed to create utf8 string from node -v Command output")?;
The trimmed version string is because Rust's semver
package doesn't handle v
in the semver string like node.js does, so we need to remove it. The Version::parse
handles whitespace trimming for us though.
let version_string_trimmed =version_string.trim_start_matches("v");let current_node_version_result =Version::parse(version_string_trimmed);
Finally with all of the information we have we can do a comparison of the current node version against the minimum we support and relay relevant error messages regardless.
match current_node_version_result {Ok(current_node_version) => {if current_node_version < minimum_required_node_major_version {Err(eyre!(format!("node version {} doesn't meet the minimum required version {}",current_node_version, minimum_required_node_major_version)))} else {Ok(())}}Err(e) => Err(eyre!(format!("Couldn't parse node version from trimmed version `{}`, original string is `{}`",version_string_trimmed, version_string))),}