fishctl/src/command/config/validate.rs
2024-06-21 10:48:05 +09:00

99 lines
3.3 KiB
Rust

//! `config validate` subcommand
use crate::{
command::config::{current_revision, RevisionCheckError},
config::{client, server, CLIENT_CONFIG_PATH, SERVER_CONFIG_PATH},
};
use color_print::cprintln;
use enum_iterator::Sequence;
use std::{fs, io::Read};
use validator::Validate;
/// Errors that can happen in `config validate` subcommand
#[derive(thiserror::Error, Debug)]
pub(crate) enum ValidationError {
#[error(transparent)]
ReadFile(#[from] std::io::Error),
#[error(transparent)]
UnknownRevision(#[from] RevisionCheckError),
#[error("config files are not the latest revision")]
OutOfDate,
#[error("invalid config file")]
InvalidConfig,
}
#[derive(thiserror::Error, Debug)]
enum ReadError {
#[error(transparent)]
ReadFile(#[from] std::io::Error),
#[error("the config file is not written in the correct format")]
InvalidFormat(#[from] toml::de::Error),
}
pub(super) fn run() -> Result<(), ValidationError> {
if current_revision()?.next().is_some() {
cprintln!("Please first run `<bold>fishctl config update</>` to update your config files.");
return Err(ValidationError::OutOfDate);
}
let server_validation_result = match read_server_toml() {
Ok(config) => config.validate().map_err(|err| {
cprintln!("<r!><bold>config/server.toml is invalid.</></>\n{}", err);
ValidationError::InvalidConfig
}),
Err(ReadError::InvalidFormat(err)) => {
cprintln!("<r!><bold>config/server.toml is invalid.</></>\n{}", err);
Err(ValidationError::InvalidConfig)
}
Err(ReadError::ReadFile(err)) => Err(ValidationError::ReadFile(err)),
};
let client_validation_result = match read_client_toml() {
Ok(config) => config.validate().map_err(|err| {
cprintln!(
"<r!><bold>{} is invalid.</></>\n{}",
CLIENT_CONFIG_PATH,
err
);
ValidationError::InvalidConfig
}),
Err(ReadError::InvalidFormat(err)) => {
cprintln!(
"<r!><bold>{} is invalid.</></>\n{}",
CLIENT_CONFIG_PATH,
err
);
Err(ValidationError::InvalidConfig)
}
Err(ReadError::ReadFile(err)) => Err(ValidationError::ReadFile(err)),
};
if server_validation_result.is_ok() && client_validation_result.is_ok() {
cprintln!(
"<g!><bold>{} and {} are valid!</></>",
SERVER_CONFIG_PATH,
CLIENT_CONFIG_PATH
);
cprintln!("<bold>Note:</> This command only checks the format of the config files, and its result does not guarantee the correctness of the value.");
}
server_validation_result.and(client_validation_result)
}
fn read_server_toml() -> Result<server::Config, ReadError> {
let mut file = fs::File::open(SERVER_CONFIG_PATH)?;
let mut buffer = String::new();
file.read_to_string(&mut buffer)?;
toml::from_str(&buffer).map_err(ReadError::InvalidFormat)
}
fn read_client_toml() -> Result<client::Config, ReadError> {
let mut file = fs::File::open(CLIENT_CONFIG_PATH)?;
let mut buffer = String::new();
file.read_to_string(&mut buffer)?;
toml::from_str(&buffer).map_err(ReadError::InvalidFormat)
}