2024-06-20 08:17:13 +09:00
|
|
|
//! `config` subcommand
|
|
|
|
|
2024-06-20 02:07:34 +09:00
|
|
|
mod migrate;
|
|
|
|
mod validate;
|
|
|
|
|
2024-06-21 04:36:44 +09:00
|
|
|
use crate::config::{Revision, CLIENT_CONFIG_PATH, OLD_CONFIG_PATH, SERVER_CONFIG_PATH};
|
2024-06-21 03:41:48 +09:00
|
|
|
use clap::Subcommand;
|
2024-06-21 04:36:44 +09:00
|
|
|
use serde::Deserialize;
|
|
|
|
use std::{fs, io::Read, path::Path};
|
2024-06-20 02:07:34 +09:00
|
|
|
|
|
|
|
#[derive(Subcommand)]
|
|
|
|
pub(crate) enum Commands {
|
|
|
|
/// Convert an old config file into the new format
|
2024-06-21 04:27:03 +09:00
|
|
|
Migrate { revision: Option<Revision> },
|
2024-06-20 02:07:34 +09:00
|
|
|
/// Validate the config file
|
|
|
|
Validate,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
|
|
pub(crate) enum Error {
|
|
|
|
#[error(transparent)]
|
2024-06-21 03:13:58 +09:00
|
|
|
Migrate(#[from] migrate::MigrationError),
|
2024-06-20 02:07:34 +09:00
|
|
|
#[error(transparent)]
|
2024-06-21 03:13:58 +09:00
|
|
|
Validate(#[from] validate::ValidationError),
|
2024-06-20 02:07:34 +09:00
|
|
|
}
|
|
|
|
|
2024-06-21 04:36:44 +09:00
|
|
|
#[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)
|
|
|
|
}
|
|
|
|
|
2024-06-20 03:19:20 +09:00
|
|
|
pub(crate) async fn run(command: Commands) -> Result<(), Error> {
|
2024-06-20 02:07:34 +09:00
|
|
|
match command {
|
2024-06-21 03:31:13 +09:00
|
|
|
Commands::Migrate { revision } => migrate::run(revision).await?,
|
2024-06-20 02:07:34 +09:00
|
|
|
Commands::Validate => validate::run()?,
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|