88 lines
2.5 KiB
Rust
88 lines
2.5 KiB
Rust
//! `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("downgrading is not supported")]
|
|
Downgrade,
|
|
#[error("failed to update the config to revision 1")]
|
|
V1(#[from] v1::Error),
|
|
}
|
|
|
|
pub(super) async fn run(revision: Option<Revision>) -> Result<(), UpdateError> {
|
|
let current = current_revision()?;
|
|
|
|
if current.next().is_none() {
|
|
println!("Your config files are already up-to-date! (as of this fishctl release)");
|
|
return Ok(());
|
|
}
|
|
if current != Revision::V0 {
|
|
take_backup()?;
|
|
}
|
|
|
|
match revision {
|
|
Some(target) => update(current, target).await,
|
|
None => update(current, Revision::last().unwrap()).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(())
|
|
}
|
|
|
|
/// Updates config files to the specified revision.
|
|
async fn update(mut current: Revision, target: Revision) -> Result<(), UpdateError> {
|
|
if current > target {
|
|
return Err(UpdateError::Downgrade);
|
|
}
|
|
while current < target {
|
|
let next = current.next().unwrap();
|
|
update_one_revision(next.clone()).await?;
|
|
current = next;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Updates config file revision from `target - 1` to `target`.
|
|
async fn update_one_revision(target: Revision) -> Result<(), UpdateError> {
|
|
println!(
|
|
"Updating the config to revision {}...",
|
|
target.clone() as u8
|
|
);
|
|
match target {
|
|
Revision::V0 => unreachable!(),
|
|
Revision::V1 => v1::run().await?,
|
|
}
|
|
Ok(())
|
|
}
|