This commit is contained in:
naskya 2024-06-21 04:36:44 +09:00
parent a502c30791
commit 3a57eb5880
Signed by: naskya
GPG key ID: 712D413B3A9FED5C
3 changed files with 74 additions and 65 deletions

View file

@ -3,8 +3,10 @@
mod migrate; mod migrate;
mod validate; mod validate;
use crate::config::Revision; use crate::config::{Revision, CLIENT_CONFIG_PATH, OLD_CONFIG_PATH, SERVER_CONFIG_PATH};
use clap::Subcommand; use clap::Subcommand;
use serde::Deserialize;
use std::{fs, io::Read, path::Path};
#[derive(Subcommand)] #[derive(Subcommand)]
pub(crate) enum Commands { pub(crate) enum Commands {
@ -22,6 +24,71 @@ pub(crate) enum Error {
Validate(#[from] validate::ValidationError), Validate(#[from] validate::ValidationError),
} }
#[derive(thiserror::Error, Debug)]
pub(crate) enum RevisionCheckError {
#[error("failed to determine the current config revision ({0})")]
UnknownRevision(&'static str),
#[error(transparent)]
InvalidConfig(#[from] toml::de::Error),
#[error(transparent)]
ReadFile(#[from] std::io::Error),
}
fn next_revision() -> Result<Option<Revision>, RevisionCheckError> {
let old_config_exists = Path::new(OLD_CONFIG_PATH).is_file();
let server_config_exists = Path::new(SERVER_CONFIG_PATH).is_file();
let client_config_exists = Path::new(CLIENT_CONFIG_PATH).is_file();
if server_config_exists && !client_config_exists {
return Err(RevisionCheckError::UnknownRevision(
"client config file does not exist",
));
}
if !server_config_exists && client_config_exists {
return Err(RevisionCheckError::UnknownRevision(
"server config file does not exist",
));
}
if !old_config_exists && !server_config_exists && !client_config_exists {
return Err(RevisionCheckError::UnknownRevision(
"config file does not exist",
));
}
if old_config_exists && !server_config_exists && !client_config_exists {
return Ok(Some(Revision::V20240701));
}
#[derive(Deserialize)]
struct Config {
config_revision: Revision,
}
let mut buffer = String::new();
let mut server_toml = fs::File::open(SERVER_CONFIG_PATH)?;
server_toml.read_to_string(&mut buffer)?;
let server_config_revision = toml::from_str::<Config>(&buffer)?.config_revision;
let mut client_toml = fs::File::open(CLIENT_CONFIG_PATH)?;
client_toml.read_to_string(&mut buffer)?;
let client_config_revision = toml::from_str::<Config>(&buffer)?.config_revision;
if server_config_revision != client_config_revision {
return Err(RevisionCheckError::UnknownRevision(
"server config revision and client config revision are different",
));
}
let next_revision = match server_config_revision {
Revision::V20240701 => None,
};
Ok(next_revision)
}
pub(crate) async fn run(command: Commands) -> Result<(), Error> { pub(crate) async fn run(command: Commands) -> Result<(), Error> {
match command { match command {
Commands::Migrate { revision } => migrate::run(revision).await?, Commands::Migrate { revision } => migrate::run(revision).await?,

View file

@ -2,77 +2,19 @@
mod v20240701; mod v20240701;
use crate::config::{Revision, CLIENT_CONFIG_PATH, OLD_CONFIG_PATH, SERVER_CONFIG_PATH}; use crate::{
use serde::Deserialize; command::config::{next_revision, RevisionCheckError},
use std::{fs, io::Read, path::Path}; config::Revision,
};
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub(crate) enum MigrationError { pub(crate) enum MigrationError {
#[error("failed to determine the current config revision ({0})")]
UnknownRevision(&'static str),
#[error(transparent)] #[error(transparent)]
ReadFile(#[from] std::io::Error), UnknownRevision(#[from] RevisionCheckError),
#[error(transparent)]
InvalidConfig(#[from] toml::de::Error),
#[error(transparent)] #[error(transparent)]
V20240701(#[from] v20240701::Error), V20240701(#[from] v20240701::Error),
} }
fn next_revision() -> Result<Option<Revision>, MigrationError> {
let old_config_exists = Path::new(OLD_CONFIG_PATH).is_file();
let server_config_exists = Path::new(SERVER_CONFIG_PATH).is_file();
let client_config_exists = Path::new(CLIENT_CONFIG_PATH).is_file();
if server_config_exists && !client_config_exists {
return Err(MigrationError::UnknownRevision(
"client config file does not exist",
));
}
if !server_config_exists && client_config_exists {
return Err(MigrationError::UnknownRevision(
"server config file does not exist",
));
}
if !old_config_exists && !server_config_exists && !client_config_exists {
return Err(MigrationError::UnknownRevision(
"config file does not exist",
));
}
if old_config_exists && !server_config_exists && !client_config_exists {
return Ok(Some(Revision::V20240701));
}
#[derive(Deserialize)]
struct Config {
config_revision: Revision,
}
let mut buffer = String::new();
let mut server_toml = fs::File::open(SERVER_CONFIG_PATH)?;
server_toml.read_to_string(&mut buffer)?;
let server_config_revision = toml::from_str::<Config>(&buffer)?.config_revision;
let mut client_toml = fs::File::open(CLIENT_CONFIG_PATH)?;
client_toml.read_to_string(&mut buffer)?;
let client_config_revision = toml::from_str::<Config>(&buffer)?.config_revision;
if server_config_revision != client_config_revision {
return Err(MigrationError::UnknownRevision(
"server config revision and client config revision are different",
));
}
let next_revision = match server_config_revision {
Revision::V20240701 => None,
};
Ok(next_revision)
}
async fn update_to_latest() -> Result<(), MigrationError> { async fn update_to_latest() -> Result<(), MigrationError> {
if next_revision()?.is_none() { if next_revision()?.is_none() {
println!("Your config files are already up-to-date! (as of this fishctl release)"); println!("Your config files are already up-to-date! (as of this fishctl release)");

View file

@ -4,7 +4,7 @@ pub mod server;
use clap::ValueEnum; use clap::ValueEnum;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, PartialEq, PartialOrd, Clone, ValueEnum, Debug)] #[derive(Deserialize, Serialize, PartialEq, Clone, ValueEnum, Debug)]
pub enum Revision { pub enum Revision {
#[clap(name = "20240701")] #[clap(name = "20240701")]
#[serde(rename = "20240701")] #[serde(rename = "20240701")]