Skip to main content

abbaye/version_extractors/
cargo.rs

1use std::path::PathBuf;
2
3use miette::{IntoDiagnostic, Result, miette};
4use serde::{Deserialize, Serialize};
5
6use super::{VersionExtractor, VersionInfo};
7
8/// Configuration for [`CargoVersion`].
9#[derive(Debug, Default, Clone, Deserialize, Serialize)]
10pub struct CargoVersionConfig {
11    /// Path to the `Cargo.toml` to read the version from.
12    /// Defaults to `Cargo.toml` in the current working directory.
13    pub manifest_path: Option<PathBuf>,
14}
15
16/// Extracts the package version by reading it directly from `Cargo.toml`.
17pub struct CargoVersion;
18
19// Internal types used only for TOML parsing.
20#[derive(Deserialize)]
21struct CargoManifest {
22    package: Option<CargoPackage>,
23}
24
25#[derive(Deserialize)]
26struct CargoPackage {
27    version: Option<String>,
28}
29
30impl VersionExtractor for CargoVersion {
31    type ConfigType = CargoVersionConfig;
32
33    async fn get_last_version(&self, config: Self::ConfigType) -> Result<VersionInfo> {
34        let path = config
35            .manifest_path
36            .unwrap_or_else(|| PathBuf::from("Cargo.toml"));
37
38        let content = tokio::fs::read_to_string(&path).await.into_diagnostic()?;
39
40        let manifest: CargoManifest = toml::from_str(&content).into_diagnostic()?;
41
42        let version = manifest
43            .package
44            .ok_or_else(|| miette!("{} has no [package] section", path.display()))?
45            .version
46            .ok_or_else(|| miette!("no version field in [package] in {}", path.display()))?;
47
48        // Cargo.toml carries no release date information.
49        Ok(VersionInfo {
50            version,
51            date: None,
52        })
53    }
54}