From 50f069af43280d3346957cf00b3c4a7d3c965223 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Mon, 27 Feb 2023 14:25:29 -0700 Subject: [PATCH] install: support config upgrade from serde_yaml v0.8 (#30535) --- Cargo.lock | 1 + install/Cargo.toml | 1 + install/src/config.rs | 47 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 961b65ca85..dbc2f909de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5675,6 +5675,7 @@ dependencies = [ "scopeguard", "semver 1.0.16", "serde", + "serde_yaml 0.8.26", "serde_yaml 0.9.13", "solana-clap-utils", "solana-config-program", diff --git a/install/Cargo.toml b/install/Cargo.toml index 9cdf713f9b..1a92f5cc53 100644 --- a/install/Cargo.toml +++ b/install/Cargo.toml @@ -27,6 +27,7 @@ scopeguard = { workspace = true } semver = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_yaml = { workspace = true } +serde_yaml_08 = { package = "serde_yaml", version = "0.8.26" } solana-clap-utils = { workspace = true } solana-config-program = { workspace = true } solana-logger = { workspace = true } diff --git a/install/src/config.rs b/install/src/config.rs index 42f151e0fb..ca431d45ea 100644 --- a/install/src/config.rs +++ b/install/src/config.rs @@ -26,6 +26,9 @@ pub struct Config { active_release_dir: PathBuf, } +const LEGACY_FMT_LOAD_ERR: &str = + "explicit_release: invalid type: map, expected a YAML tag starting with '!'"; + impl Config { pub fn new( data_dir: &str, @@ -46,9 +49,47 @@ impl Config { fn _load(config_file: &str) -> Result { let file = File::open(config_file)?; - let config = serde_yaml::from_reader(file) - .map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{err:?}")))?; - Ok(config) + serde_yaml::from_reader(file).or_else(|err| { + let err_string = format!("{err:?}"); + if err_string.contains(LEGACY_FMT_LOAD_ERR) { + // looks like a config written by serde_yaml <0.9.0. + // let's try to upgrade it + Self::try_migrate_08(config_file) + .map_err(|_| io::Error::new(io::ErrorKind::Other, err_string)) + } else { + Err(io::Error::new(io::ErrorKind::Other, err_string)) + } + }) + } + + fn try_migrate_08(config_file: &str) -> Result { + eprintln!("attempting to upgrade legacy config file"); + let bak_filename = config_file.to_string() + ".bak"; + std::fs::copy(config_file, &bak_filename)?; + let result = File::open(config_file).and_then(|file| { + serde_yaml_08::from_reader(file) + .map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{err:?}"))) + .and_then(|config_08: Self| { + let save = config_08._save(config_file).map(|_| config_08); + if save.is_ok() { + let _ = std::fs::remove_file(&bak_filename); + } + save + }) + }); + if result.is_err() { + eprintln!("config upgrade failed! restoring orignal"); + let restored = std::fs::copy(&bak_filename, config_file) + .and_then(|_| std::fs::remove_file(&bak_filename)); + if restored.is_err() { + eprintln!("restoration failed! original: `{bak_filename}`"); + } else { + eprintln!("restoration succeeded!"); + } + } else { + eprintln!("config upgrade succeeded!"); + } + result } pub fn load(config_file: &str) -> Result {