Abbaye

at 6297799

use std::path::PathBuf;

use miette::{IntoDiagnostic, Result, miette};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use super::{VersionExtractor, VersionInfo};

/// Configuration for [`CargoVersion`].
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema)]
pub struct CargoVersionConfig {
    /// Path to the `Cargo.toml` to read the version from.
    /// Defaults to `Cargo.toml` in the current working directory.
    pub manifest_path: Option<PathBuf>,
}

/// Extracts the package version by reading it directly from `Cargo.toml`.
pub struct CargoVersion;

// Internal types used only for TOML parsing.
#[derive(Deserialize)]
struct CargoManifest {
    package: Option<CargoPackage>,
}

#[derive(Deserialize)]
struct CargoPackage {
    version: Option<String>,
}

impl VersionExtractor for CargoVersion {
    type ConfigType = CargoVersionConfig;

    async fn get_last_version(&self, config: Self::ConfigType) -> Result<VersionInfo> {
        let path = config
            .manifest_path
            .unwrap_or_else(|| PathBuf::from("Cargo.toml"));

        let content = tokio::fs::read_to_string(&path).await.into_diagnostic()?;

        let manifest: CargoManifest = toml::from_str(&content).into_diagnostic()?;

        let version = manifest
            .package
            .ok_or_else(|| miette!("{} has no [package] section", path.display()))?
            .version
            .ok_or_else(|| miette!("no version field in [package] in {}", path.display()))?;

        // Cargo.toml carries no release date information.
        Ok(VersionInfo {
            version,
            date: None,
        })
    }
}