use std::{ collections::HashMap, env, fs, io::{self, Read}, }; use yaml_rust::{Yaml, YamlLoader}; pub(super) fn run(version: super::ConfigVersion) -> Result<(), Error> { match version { super::ConfigVersion::V20240701 => migrate_20240701(), } } #[derive(thiserror::Error, Debug)] pub(crate) enum Error { #[error("failed to parse the old config file (.config/default.yml)")] ReadOldConfig(#[from] ReadYamlConfigError), } #[derive(thiserror::Error, Debug)] pub(crate) enum ReadYamlConfigError { #[error(transparent)] ReadFile(#[from] io::Error), #[error(transparent)] Yaml(#[from] yaml_rust::ScanError), #[error("invalid config file ({0})")] InvalidConfig(String), } fn read_default_yml() -> Result, ReadYamlConfigError> { let cwd = env::current_dir()?; let mut default_yml = fs::File::open(cwd.join(".config/default.yml"))?; let mut buffer = String::new(); default_yml.read_to_string(&mut buffer)?; let content = YamlLoader::load_from_str(&buffer)?; if content.is_empty() { return Err(ReadYamlConfigError::InvalidConfig( "file is empty".to_string(), )); } if content.len() > 2 || content[0].is_array() { return Err(ReadYamlConfigError::InvalidConfig( "top-level should not be an array".to_string(), )); } let content = content[0] .clone() .into_hash() .ok_or(ReadYamlConfigError::InvalidConfig( "invalid format".to_string(), ))?; let mut res = HashMap::new(); for (key, val) in content { let Some(key) = key.as_str() else { return Err(ReadYamlConfigError::InvalidConfig(format!( "non-string key found: {:?}", key ))); }; res.insert(key.to_owned(), val); } Ok(res) } fn migrate_20240701() -> Result<(), Error> { let old_config = read_default_yml()?; for (k, v) in old_config { println!("{}:\n {:?}", k, v); } Ok(()) }