Skip to main content

abbaye/version_extractors/
cargo.rs

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