Versioning
Topic | Rust Crates |
---|---|
Version Parsing and Comparison | semver ⮳ parses, compares, and manipulates SemVer (Semantic Versioning) strings. |
Version Bumping | cargo-bump is a tool to automate bumping versions in your Cargo.toml file according to SemVer rules. See Development Tools: Cargo Plugins. |
Dependency Management (with version constraints) | cargo uses SemVer for specifying dependencies in Cargo.toml . See the Cargo chapter for more details. |
Release Management | Often involves tagging Git releases. |
Changelog Generation | Often handled with tools outside of the Rust ecosystem, but some crates might assist with parsing commit messages, etc. |
Parse a Version String
Constructs a semver::Version
⮳ from a string literal using semver::Version::parse
⮳.
//! This example demonstrates how to parse a semantic version string. //! //! `semver` is a parser for Cargo’s flavor of Semantic Versioning. use anyhow::Result; use semver::Version; fn main() -> Result<()> { let parsed_version = Version::parse("0.2.6")?; // The parsed version is equal to the following: assert_eq!( parsed_version, Version { major: 0, minor: 2, patch: 6, pre: semver::Prerelease::EMPTY, build: semver::BuildMetadata::EMPTY, } ); println!("{:?}", parsed_version); Ok(()) }
Parse a Complex Version String
Constructs a semver::Version
⮳ from a complex version string using semver::Version::parse
⮳ The string contains pre-release and build metadata as defined in the semantic versioning specification`⮳.
Note that, in accordance with the SemVer Specification, build metadata is parsed but not considered when comparing versions. In other words, two versions may be equal even if their build strings differ.
//! Demonstrates parsing, comparing, and serializing complex semantic version //! strings. use anyhow::Result; use semver::BuildMetadata; use semver::Prerelease; use semver::Version; fn main() -> Result<()> { // Define a complex semantic version string. let version_str = "1.0.49-125+g72ee7853"; // Parse the version string into a Version struct. let parsed_version = Version::parse(version_str)?; assert_eq!( parsed_version, Version { major: 1, minor: 0, patch: 49, pre: Prerelease::new("125")?, build: BuildMetadata::new("g72ee7853")?, } ); // Serialize the parsed Version struct back into a string. let serialized_version = parsed_version.to_string(); assert_eq!(&serialized_version, version_str); println!("{}", serialized_version); Ok(()) }
Check if a Given Version is Pre-release
Given two versions, semver::Version
⮳ asserts that one is pre-release and the other is not.
//! Demonstrates how to work with pre-release versions using the `semver` crate. use anyhow::Result; use semver::Version; fn main() -> Result<()> { let version_1 = Version::parse("1.0.0-alpha")?; // Prints: Version { major: 1, minor: 0, patch: 0, pre: [Identifier(Alpha)], // build: [] } println!("{:?}", version_1); let version_2 = Version::parse("1.0.0")?; println!("{:?}", version_2); assert!(!version_1.pre.is_empty()); assert!(version_2.pre.is_empty()); Ok(()) }
Find the Latest Version Satisfying a Given Range
Given a list of version &strs, finds the latest semver::Version
⮳.
semver::VersionReq
⮳ filters the list with semver::VersionReq::matches
⮳ Also demonstrates semver
⮳ pre-release preferences.
//! This example demonstrates how to find the maximum matching version from a //! list of versions based on a given version requirement string, using the //! `semver` crate. //! //! The `find_max_matching_version` function takes a version requirement string //! and an iterable of version strings. It parses the version requirement and //! each version string, then filters the versions to find those that match the //! requirement. Finally, it returns the maximum matching version. use anyhow::Result; use semver::Version; use semver::VersionReq; /// Finds the maximum matching version from an iterable of version strings based /// on a version requirement string. fn find_max_matching_version<'a, I>( // The version requirement string (e.g., ">=1.0.0", "<2.0.0"). version_req_str: &str, iterable: I, ) -> Result<Option<Version>> where I: IntoIterator<Item = &'a str>, { // SemVer version requirement describing the intersection of some version // comparators, such as >=1.2.3, <1.8. let vreq = VersionReq::parse(version_req_str)?; Ok(iterable .into_iter() .filter_map(|s| Version::parse(s).ok()) .filter(|s| vreq.matches(s)) .max()) } fn main() -> Result<()> { let max_matching_version = find_max_matching_version("<= 1.0.0", vec!["0.9.0", "1.0.0", "1.0.1"])?; println!("Maximum matching version: {:?}", max_matching_version); assert_eq!(max_matching_version, Some(Version::parse("1.0.0")?)); assert_eq!( find_max_matching_version( ">1.2.3-alpha.3", vec![ "1.2.3-alpha.3", "1.2.3-alpha.4", "1.2.3-alpha.10", "1.2.3-beta.4", "3.4.5-alpha.9", ] )?, Some(Version::parse("1.2.3-beta.4")?) ); Ok(()) }
Check External Command Version for Compatibility
Runs git --version
using std::process::Command
⮳ then parses the version number into a
semver::Version
⮳ using semver::Version::parse
⮳ semver::VersionReq::matches
⮳ compares
semver::VersionReq
to the parsed version. The command output resembles "git version x.y.z".
use std::process::Command; use anyhow::Context; use anyhow::Result; use anyhow::anyhow; use anyhow::bail; use semver::Version; use semver::VersionReq; /// This example demonstrates how to check if a command line tool is installed /// and if it meets a minimum version requirement. /// /// It uses the `git` command as an example, but it can be adapted to any /// command line tool. /// /// It uses the `semver` crate to parse and compare versions. fn main() -> Result<()> { // Define the minimum required version. let version_constraint = "> 1.12.0"; let version_test = VersionReq::parse(version_constraint)?; // Execute the command and capture its output. let output = Command::new("git").arg("--version").output()?; if !output.status.success() { bail!("The command returned a failing error code."); } let stdout = String::from_utf8(output.stdout)?; let version = stdout .split(" ") .last() .ok_or_else(|| anyhow!("Invalid command output."))? .trim(); // Remove any extraneous newlines. // Parse the version string into a `semver::Version`. let parsed_version = Version::parse(version).context(format!("version: {}", version))?; // Check if the parsed version meets the required version constraint. if !version_test.matches(&parsed_version) { bail!( "Command version lower than minimum supported version (found {}, need {})", parsed_version, version_constraint ); } println!("{:?}", parsed_version); Ok(()) }