vampus 0.4.5

A CLI tool for automated semantic version management across configurable file patterns.
use std::io;
use std::path::PathBuf;

use serde::{Deserialize, Serialize};
use tracing::error;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Replace {
    #[serde(default = "get_default_file")]
    pub file: String,
    #[serde(default = "get_default_pattern")]
    pub pattern: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    #[serde(default = "get_default_current_version")]
    pub current_version: String,
    #[serde(default = "get_default_replaces")]
    pub replaces: Vec<Replace>,
}

fn get_default_current_version() -> String {
    "0.1.0".to_string()
}
fn get_default_file() -> String {
    "Cargo.toml".to_string()
}
fn get_default_pattern() -> String {
    "^version\\s*=\\s*\"{{current_version}}\"$".to_string()
}
fn get_default_replaces() -> Vec<Replace> {
    vec![Replace {
        file: get_default_file(),
        pattern: get_default_pattern(),
    }]
}

impl Config {
    fn default() -> Self {
        Self {
            current_version: get_default_current_version(),
            replaces: get_default_replaces(),
        }
    }

    pub async fn write_default(file: &PathBuf) -> io::Result<()> {
        let default = Self::default();
        let yaml = serde_yaml::to_string(&default).expect("Config is always serializable");
        tokio::fs::write(file, yaml.as_bytes()).await
    }

    pub async fn read(file_path: &PathBuf) -> Option<Self> {
        let content = match tokio::fs::read_to_string(file_path).await {
            Ok(c) => c,
            Err(e) => {
                error!(
                    "Failed to read config file '{}': {}",
                    file_path.display(),
                    e
                );
                return None;
            }
        };
        match serde_yaml::from_str::<Self>(&content) {
            Ok(config) => Some(config),
            Err(e) => {
                error!(
                    "Failed to deserialize config file '{}': {}",
                    file_path.display(),
                    e
                );
                None
            }
        }
    }

    pub async fn write(&self, file: &PathBuf) -> io::Result<()> {
        let yaml = serde_yaml::to_string(self).expect("Config is always serializable");
        tokio::fs::write(file, yaml.as_bytes()).await
    }
}