//! `config update` subcommand mod v1; use crate::{ command::config::{current_revision, RevisionCheckError}, config::{Revision, CLIENT_CONFIG_PATH, SERVER_CONFIG_PATH}, }; use chrono::Local; use color_print::cprintln; use enum_iterator::Sequence; use std::{fs, io}; /// Errors that happen in `config update` subcommand #[derive(thiserror::Error, Debug)] pub(crate) enum UpdateError { #[error(transparent)] RevisionCheck(#[from] RevisionCheckError), #[error(transparent)] FileOperation(#[from] io::Error), #[error(transparent)] V1(#[from] v1::Error), } pub(super) async fn run(revision: Option<Revision>) -> Result<(), UpdateError> { let current_revision = current_revision()?; if current_revision.next().is_none() { println!("Your config files are already up-to-date! (as of this fishctl release)"); return Ok(()); } if current_revision != Revision::V0 { take_backup()?; } match revision { Some(revision) => update_to(revision).await, None => update_to_latest_from(current_revision).await, } } fn take_backup() -> Result<(), UpdateError> { let current_time = Local::now().format("%Y%m%d%H%M%S").to_string(); let server_backup_filename = format!("{}-backup-{}", SERVER_CONFIG_PATH, current_time); let client_backup_filename = format!("{}-backup-{}", CLIENT_CONFIG_PATH, current_time); cprintln!( "Saving server config backup as <bold>{}</>...", server_backup_filename ); fs::copy(SERVER_CONFIG_PATH, server_backup_filename)?; cprintln!( "Saving client config backup as <bold>{}</>...", client_backup_filename ); fs::copy(CLIENT_CONFIG_PATH, client_backup_filename)?; Ok(()) } async fn update_to_latest_from(mut current_revision: Revision) -> Result<(), UpdateError> { while let Some(next_revision) = current_revision.next() { update_to(next_revision.clone()).await?; current_revision = next_revision; } Ok(()) } /// Updates config files to the specified revision. async fn update_to(revision: Revision) -> Result<(), UpdateError> { match revision { Revision::V0 => unreachable!(), Revision::V1 => v1::run().await?, } Ok(()) }