forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
1.7 KiB
1//! Git version detection. forge requires git 2.38.0 or newer.
2
3use crate::command::{GitCommand, GitEnv};
4use crate::error::{Error, Result};
5
6/// Parses `git version` output such as `git version 2.56.0` or `git version 2.39.2.windows.1`.
7pub fn parse_git_version(output: &str) -> Option<(u32, u32, u32)> {
8 let token = output
9 .split_whitespace()
10 .find(|t| t.starts_with(|c: char| c.is_ascii_digit()))?;
11 let mut parts = token.split('.');
12 let major = leading_number(parts.next()?)?;
13 let minor = leading_number(parts.next()?)?;
14 let patch = parts.next().and_then(leading_number).unwrap_or(0);
15 Some((major, minor, patch))
16}
17
18/// The number at the start of `s`, so `0-rc1` yields 0.
19fn leading_number(s: &str) -> Option<u32> {
20 let digits: String = s.chars().take_while(|c| c.is_ascii_digit()).collect();
21 digits.parse().ok()
22}
23
24fn fmt_version((major, minor, patch): (u32, u32, u32)) -> String {
25 format!("{major}.{minor}.{patch}")
26}
27
28/// Parses `git version` into (major, minor, patch).
29pub async fn git_version(env: &GitEnv) -> Result<(u32, u32, u32)> {
30 let out = GitCommand::new(env, "version").output().await?;
31 let text = String::from_utf8_lossy(&out);
32 parse_git_version(&text).ok_or_else(|| {
33 Error::Unavailable(format!("cannot parse git version from {:?}", text.trim()))
34 })
35}
36
37/// Fails with `Error::TooOld` if git is older than `min`.
38pub async fn require_min_version(env: &GitEnv, min: (u32, u32, u32)) -> Result<()> {
39 let found = git_version(env).await?;
40 if found < min {
41 return Err(Error::TooOld {
42 found: fmt_version(found),
43 required: fmt_version(min),
44 });
45 }
46 Ok(())
47}