diff --git a/src/lib.rs b/src/lib.rs index 70d8053..1498c72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod commands; pub mod context; pub mod differ; pub mod jsonnet_evaluator; +pub mod macros; pub mod scheduler; pub mod sfn; pub mod sts; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..936795a --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,34 @@ +/// Allows you to exit immediately with error message. +/// It is a shortcut for `eprintln!` followed by `std::process::exit(1)`. +/// +/// # Examples +/// +/// ```no_run +/// # use fubura::fast_exit; +/// let x = 42; +/// if x != 42 { +/// fast_exit!("x is not 42"); +/// } else { +/// println!("x is 42"); +/// } +/// ``` +#[macro_export] +macro_rules! fast_exit { + () => { + { + std::process::exit(1); + } + }; + ($msg:expr) => { + { + eprintln!("{}", $msg); + std::process::exit(1); + } + }; + ($fmt:expr, $($arg:tt)*) => { + { + eprintln!($fmt, $($arg)*); + std::process::exit(1); + } + }; +} diff --git a/src/main.rs b/src/main.rs index 81dd449..d6f57d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use fubura::commands::apply::ApplyCommand; use fubura::commands::import::ImportCommand; use fubura::commands::plan::PlanCommand; use fubura::context::FuburaContext; +use fubura::fast_exit; use fubura::types::Config; #[tokio::main] @@ -68,7 +69,6 @@ async fn main() { }; if let Err(e) = result { - eprintln!("{}", e); - std::process::exit(1); + fast_exit!("{}", e); } } diff --git a/src/types/config.rs b/src/types/config.rs index c67b118..cd09f12 100644 --- a/src/types/config.rs +++ b/src/types/config.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use serde::{Deserialize, Serialize}; -use crate::{cli::StrKeyVal, jsonnet_evaluator}; +use crate::{cli::StrKeyVal, fast_exit, jsonnet_evaluator}; use super::SsConfig; @@ -14,11 +14,12 @@ pub struct Config { impl Config { pub fn load_from_path(config: &str, ext_str: &[StrKeyVal]) -> Config { - let config_value = jsonnet_evaluator::eval(config, ext_str).unwrap(); + let config_value = jsonnet_evaluator::eval(config, ext_str).unwrap_or_else(|e| { + fast_exit!("failed to evaluate jsonnet: {}", e); + }); serde_json::from_value(config_value).unwrap_or_else(|e| { - eprintln!("failed to parse config file with error: {}", e); - std::process::exit(1); + fast_exit!("failed to parse config file: {}", e); }) } diff --git a/src/types/schedule.rs b/src/types/schedule.rs index d5a6c5b..6daa626 100644 --- a/src/types/schedule.rs +++ b/src/types/schedule.rs @@ -1,6 +1,8 @@ use aws_sdk_scheduler::primitives::DateTime; use serde::{Deserialize, Serialize}; +use crate::fast_exit; + use super::ResourceTag; #[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)] @@ -18,8 +20,8 @@ impl From for FlexibleTimeWind aws_sdk_scheduler::types::FlexibleTimeWindowMode::Flexible => { FlexibleTimeWindowMode::Flexible } - // XXX: Don't panic here - _ => panic!("Unexpected flexible time window mode"), + // XXX: Don't fast_exit here + _ => fast_exit!("Unexpected flexible time window mode"), } } } @@ -122,8 +124,8 @@ impl From for AssignPublicIp { match value { aws_sdk_scheduler::types::AssignPublicIp::Disabled => AssignPublicIp::Disabled, aws_sdk_scheduler::types::AssignPublicIp::Enabled => AssignPublicIp::Enabled, - // XXX: Don't panic here - _ => panic!("Unexpected assign public ip"), + // XXX: Don't fast_exit here + _ => fast_exit!("Unexpected assign public ip"), } } } @@ -214,8 +216,8 @@ impl From for PlacementConstr aws_sdk_scheduler::types::PlacementConstraintType::DistinctInstance => { PlacementConstraintType::DistinctInstance } - // XXX: Don't panic here - _ => panic!("Unexpected placement constraint type"), + // XXX: Don't fast_exit here + _ => fast_exit!("Unexpected placement constraint type"), } } } @@ -281,8 +283,8 @@ impl From for PlacementStrategy aws_sdk_scheduler::types::PlacementStrategyType::Binpack => { PlacementStrategyType::Binpack } - // XXX: Don't panic here - _ => panic!("Unexpected placement strategy type"), + // XXX: Don't fast_exit here + _ => fast_exit!("Unexpected placement strategy type"), } } } @@ -348,8 +350,8 @@ impl From for LaunchType { aws_sdk_scheduler::types::LaunchType::Ec2 => LaunchType::Ec2, aws_sdk_scheduler::types::LaunchType::Fargate => LaunchType::Fargate, aws_sdk_scheduler::types::LaunchType::External => LaunchType::External, - // XXX: Don't panic here - _ => panic!("Unexpected launch type"), + // XXX: Don't fast_exit here + _ => fast_exit!("Unexpected launch type"), } } } @@ -376,8 +378,8 @@ impl From for PropagateTags { aws_sdk_scheduler::types::PropagateTags::TaskDefinition => { PropagateTags::TaskDefinition } - // XXX: Don't panic here - _ => panic!("Unexpected propagate tags"), + // XXX: Don't fast_exit here + _ => fast_exit!("Unexpected propagate tags"), } } } @@ -719,8 +721,8 @@ impl From for ScheduleState { match value { aws_sdk_scheduler::types::ScheduleState::Enabled => ScheduleState::Enabled, aws_sdk_scheduler::types::ScheduleState::Disabled => ScheduleState::Disabled, - // XXX: Don't panic here - _ => panic!("Unexpected schedule state"), + // XXX: Don't fast_exit here + _ => fast_exit!("Unexpected schedule state"), } } } @@ -803,14 +805,16 @@ mod datetime_format_as_aws_dt { use aws_sdk_sts::primitives::{DateTime, DateTimeFormat}; use serde::Deserialize; + use crate::fast_exit; + pub fn serialize(date: &Option, serializer: S) -> Result where S: serde::Serializer, { if let Some(date) = date { let date_str = date.fmt(DateTimeFormat::DateTime).unwrap_or_else(|e| { - // XXX: Don't panic here - panic!("Fail to parse datetime string {:?}", e); + // XXX: Don't fast_exit here + fast_exit!("Fail to parse datetime string {:?}", e); }); serializer.serialize_str(&date_str) @@ -827,8 +831,8 @@ mod datetime_format_as_aws_dt { if let Some(s) = s { let s = DateTime::from_str(s.as_str(), DateTimeFormat::DateTime).unwrap_or_else(|e| { - // XXX: Don't panic here - panic!("Fail to parse datetime string {:?}", e); + // XXX: Don't fast_exit here + fast_exit!("Fail to parse datetime string {:?}", e); }); Ok(Some(s)) diff --git a/src/types/state_machine.rs b/src/types/state_machine.rs index 7967ae6..112d8ab 100644 --- a/src/types/state_machine.rs +++ b/src/types/state_machine.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; +use crate::fast_exit; + use super::ResourceTag; #[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)] @@ -19,10 +21,10 @@ impl From for CloudWatchLogsLogGroup impl From for aws_sdk_sfn::types::CloudWatchLogsLogGroup { fn from(value: CloudWatchLogsLogGroup) -> Self { - // XXX: Don't panic here + // XXX: Don't fast_exit here let log_group_arn = value .log_group_arn - .unwrap_or_else(|| panic!("log_group_arn is required for CloudWatchLogsLogGroup")); + .unwrap_or_else(|| fast_exit!("log_group_arn is required for CloudWatchLogsLogGroup")); aws_sdk_sfn::types::builders::CloudWatchLogsLogGroupBuilder::default() .log_group_arn(log_group_arn) @@ -72,13 +74,13 @@ pub enum LogLevel { impl From for LogLevel { fn from(value: aws_sdk_sfn::types::LogLevel) -> Self { - // XXX: Don't panic here + // XXX: Don't fast_exit here match value { aws_sdk_sfn::types::LogLevel::All => LogLevel::All, aws_sdk_sfn::types::LogLevel::Error => LogLevel::Error, aws_sdk_sfn::types::LogLevel::Fatal => LogLevel::Fatal, aws_sdk_sfn::types::LogLevel::Off => LogLevel::Off, - _ => panic!("unknown log level: {:?}", value), + _ => fast_exit!("unknown log level: {:?}", value), } } } @@ -122,8 +124,8 @@ impl From for aws_sdk_sfn::types::LoggingConfiguration { let mut builder = aws_sdk_sfn::types::builders::LoggingConfigurationBuilder::default(); if value.destinations.len() > 1 { - // XXX: Don't panic here - panic!("destinations size is limited to 1."); + // XXX: Don't fast_exit here + fast_exit!("destinations size is limited to 1."); } if let Some(destination) = value.destinations.first() { @@ -176,8 +178,8 @@ impl From for StateMachineType { match value { aws_sdk_sfn::types::StateMachineType::Standard => StateMachineType::Standard, aws_sdk_sfn::types::StateMachineType::Express => StateMachineType::Express, - // XXX: Don't panic here - _ => panic!("unknown state machine type: {:?}", value), + // XXX: Don't fast_exit here + _ => fast_exit!("unknown state machine type: {:?}", value), } } }