use anyhow::Result;
use clap::{Parser, Subcommand};
use colored::*;
use db_migrate::{
config::Config,
commands::{CreateCommand, DownCommand, StatusCommand, UpCommand, VerifyCommand, ResetCommand},
migration::MigrationManager,
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[derive(Parser)]
#[command(
name = "db-migrate",
about = "Robust database migration tool for ScyllaDB",
version = env!("CARGO_PKG_VERSION")
)]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(short, long, default_value = "db-migrate.toml")]
config: String,
#[arg(short, long)]
verbose: bool,
#[arg(long, default_value = "text")]
output: String,
}
#[derive(Subcommand)]
enum Commands {
Create(CreateCommand),
Up(UpCommand),
Down(DownCommand),
Status(StatusCommand),
Verify(VerifyCommand),
Reset(ResetCommand),
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
init_logging(cli.verbose)?;
let config = Config::load(&cli.config).await?;
let mut manager = MigrationManager::new(config).await?;
let result = match cli.command {
Commands::Create(cmd) => cmd.execute(&manager).await,
Commands::Up(cmd) => cmd.execute(&mut manager).await,
Commands::Down(cmd) => cmd.execute(&mut manager).await,
Commands::Status(cmd) => cmd.execute(&manager).await,
Commands::Verify(cmd) => cmd.execute(&manager).await,
Commands::Reset(cmd) => cmd.execute(&mut manager).await,
};
match result {
Ok(output) => {
if cli.output == "json" {
println!("{}", serde_json::to_string_pretty(&output)?);
} else {
println!("{}", output);
}
std::process::exit(0);
}
Err(e) => {
if cli.output == "json" {
let error_output = serde_json::json!({
"success": false,
"error": e.to_string()
});
println!("{}", serde_json::to_string_pretty(&error_output)?);
} else {
eprintln!("{} {}", "Error:".red().bold(), e);
let mut source = e.source();
while let Some(err) = source {
eprintln!(" {}: {}", "Caused by".yellow(), err);
source = err.source();
}
}
std::process::exit(1);
}
}
}
fn init_logging(verbose: bool) -> Result<()> {
let filter = if verbose {
"db_migrate=debug,info"
} else {
"db_migrate=info,warn,error"
};
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| filter.into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
Ok(())
}