use clap::{CommandFactory, Parser, Subcommand};
use microsandbox_cli::{
commands::{
create, exec, image, inspect, install, list, metrics, ps, pull, registry, remove, run,
self_cmd, shell, start, stop, uninstall, volume,
},
log_args::{self, LogArgs},
sandbox_cmd::{self, SandboxArgs},
};
#[derive(Parser)]
#[command(name = "msb", version, about = "Microsandbox CLI", styles = microsandbox_cli::styles::styles())]
struct Cli {
#[arg(long, global = true)]
tree: bool,
#[command(flatten)]
logs: LogArgs,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
#[command(hide = true)]
Sandbox(Box<SandboxArgs>),
Run(run::RunArgs),
Create(create::CreateArgs),
Start(start::StartArgs),
Stop(stop::StopArgs),
#[command(visible_alias = "ls")]
List(list::ListArgs),
#[command(name = "status", visible_alias = "ps")]
Status(ps::PsArgs),
Metrics(metrics::MetricsArgs),
#[command(visible_alias = "rm")]
Remove(remove::RemoveArgs),
Exec(exec::ExecArgs),
Shell(shell::ShellArgs),
Image(image::ImageArgs),
Pull(pull::PullArgs),
Registry(registry::RegistryArgs),
#[command(hide = true)]
Images(image::ImageListArgs),
#[command(hide = true)]
Rmi(image::ImageRemoveArgs),
Inspect(inspect::InspectArgs),
#[command(visible_alias = "vol")]
Volume(volume::VolumeArgs),
Install(install::InstallArgs),
Uninstall(uninstall::UninstallArgs),
#[command(name = "self")]
Self_(self_cmd::SelfArgs),
}
fn main() {
microsandbox_cli::ui::install_panic_hook();
if std::env::var("MSB_PATH").is_err()
&& let Ok(exe) = std::env::current_exe()
{
unsafe { std::env::set_var("MSB_PATH", &exe) };
}
if let Some(tree) = microsandbox_cli::tree::try_show_tree(&Cli::command()) {
println!("{tree}");
return;
}
let cli = Cli::parse();
let log_level = cli.logs.selected_level();
log_args::init_tracing(log_level);
let result: Result<(), Box<dyn std::error::Error>> = match cli.command {
Commands::Sandbox(args) => sandbox_cmd::run(*args, log_level),
command => run_async_command(command, log_level),
};
if let Err(e) = result {
microsandbox_cli::ui::error(&e.to_string());
std::process::exit(1);
}
}
fn run_async_command(
command: Commands,
_log_level: Option<microsandbox::LogLevel>,
) -> Result<(), Box<dyn std::error::Error>> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
runtime.block_on(async move {
microsandbox::sandbox::spawn_reaper();
match command {
Commands::Sandbox(_) => unreachable!("handled before Tokio starts"),
Commands::Run(args) => run::run(args).await.map_err(Into::into),
Commands::Create(args) => create::run(args).await.map_err(Into::into),
Commands::Start(args) => start::run(args).await.map_err(Into::into),
Commands::Stop(args) => stop::run(args).await.map_err(Into::into),
Commands::List(args) => list::run(args).await.map_err(Into::into),
Commands::Status(args) => ps::run(args).await.map_err(Into::into),
Commands::Metrics(args) => metrics::run(args).await.map_err(Into::into),
Commands::Remove(args) => remove::run(args).await.map_err(Into::into),
Commands::Exec(args) => exec::run(args).await.map_err(Into::into),
Commands::Shell(args) => shell::run(args).await.map_err(Into::into),
Commands::Image(args) => image::run(args).await.map_err(Into::into),
Commands::Pull(args) => image::run_pull(args).await.map_err(Into::into),
Commands::Registry(args) => registry::run(args).await.map_err(Into::into),
Commands::Images(args) => image::run_list(args).await.map_err(Into::into),
Commands::Rmi(args) => image::run_remove(args).await.map_err(Into::into),
Commands::Inspect(args) => inspect::run(args).await.map_err(Into::into),
Commands::Volume(args) => volume::run(args).await.map_err(Into::into),
Commands::Install(args) => install::run(args).await.map_err(Into::into),
Commands::Uninstall(args) => uninstall::run(args).await.map_err(Into::into),
Commands::Self_(args) => self_cmd::run(args).await.map_err(Into::into),
}
})
}